Passed
Pull Request — 1.11.x (#4350)
by Angel Fernando Quiroz
12:30 queued 04:54
created

api_check_password()   F

Complexity

Conditions 15
Paths 816

Size

Total Lines 78
Code Lines 43

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 43
c 0
b 0
f 0
dl 0
loc 78
rs 2.0055
cc 15
nc 816
nop 1

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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

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

Loading history...
1238
            isset($course_info['registration_code']) && !empty($course_info['registration_code'])
1239
        ) {
1240
            $is_visible = false;
1241
        }
1242
    }
1243
1244
    if (!empty($checkTool)) {
1245
        if (!api_is_allowed_to_edit(true, true, true)) {
1246
            $toolInfo = api_get_tool_information_by_name($checkTool);
1247
            if (!empty($toolInfo) && isset($toolInfo['visibility']) && $toolInfo['visibility'] == 0) {
1248
                api_not_allowed(true);
1249
1250
                return false;
1251
            }
1252
        }
1253
    }
1254
1255
    // Check session visibility
1256
    $session_id = api_get_session_id();
1257
1258
    if (!empty($session_id)) {
1259
        // $isAllowedInCourse was set in local.inc.php
1260
        if (!$isAllowedInCourse) {
1261
            $is_visible = false;
1262
        }
1263
1264
        // Check if course is inside session.
1265
        if (!SessionManager::relation_session_course_exist($session_id, $course_info['real_id'])) {
1266
            $is_visible = false;
1267
        }
1268
    }
1269
1270
    if (!$is_visible) {
1271
        api_not_allowed($print_headers);
1272
1273
        return false;
1274
    }
1275
1276
    if ($is_visible && 'true' === api_get_plugin_setting('positioning', 'tool_enable')) {
1277
        $plugin = Positioning::create();
1278
        $block = $plugin->get('block_course_if_initial_exercise_not_attempted');
1279
        if ('true' === $block) {
1280
            $currentPath = $_SERVER['PHP_SELF'];
1281
            // Allowed only this course paths.
1282
            $paths = [
1283
                '/plugin/positioning/start.php',
1284
                '/plugin/positioning/start_student.php',
1285
                '/main/course_home/course_home.php',
1286
                '/main/exercise/overview.php',
1287
            ];
1288
1289
            if (!in_array($currentPath, $paths, true)) {
1290
                // Check if entering an exercise.
1291
                global $current_course_tool;
1292
                if ('quiz' !== $current_course_tool) {
1293
                    $initialData = $plugin->getInitialExercise($course_info['real_id'], $session_id);
1294
                    if ($initialData && isset($initialData['exercise_id'])) {
1295
                        $results = Event::getExerciseResultsByUser(
0 ignored issues
show
Bug introduced by
The method getExerciseResultsByUser() does not exist on Event. ( Ignorable by Annotation )

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

1295
                        /** @scrutinizer ignore-call */ 
1296
                        $results = Event::getExerciseResultsByUser(

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

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

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

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

Loading history...
1373
        $tpl = new Template(null, true, true, false, true, false, true, 0);
1374
        $tpl->assign('hide_login_link', 1);
1375
1376
        //api_not_allowed(true, get_lang('AccountInactive'));
1377
        // we were not in a course, return to home page
1378
        $msg = Display::return_message(
1379
            get_lang('AccountInactive'),
1380
            'error',
1381
            false
1382
        );
1383
1384
        $msg .= '<p class="text-center">
1385
                 <a class="btn btn-default" href="'.$homeUrl.'">'.get_lang('BackHome').'</a></p>';
1386
1387
        if (api_is_anonymous()) {
1388
            $form = api_get_not_allowed_login_form();
1389
            $msg .= '<div class="well">';
1390
            $msg .= $form->returnForm();
1391
            $msg .= '</div>';
1392
        }
1393
1394
        $tpl->assign('content', $msg);
1395
        $tpl->display_one_col_template();
1396
        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...
1397
    }
1398
1399
    return $data;
1400
}
1401
1402
/**
1403
 * Function used to protect a teacher script.
1404
 * The function blocks access when the user has no teacher rights.
1405
 *
1406
 * @return bool True if the current user can access the script, false otherwise
1407
 *
1408
 * @author Yoselyn Castillo
1409
 */
1410
function api_protect_teacher_script()
1411
{
1412
    if (!api_is_allowed_to_edit()) {
1413
        api_not_allowed(true);
1414
1415
        return false;
1416
    }
1417
1418
    return true;
1419
}
1420
1421
/**
1422
 * Function used to prevent anonymous users from accessing a script.
1423
 *
1424
 * @param bool|true $printHeaders
1425
 *
1426
 * @author Roan Embrechts
1427
 *
1428
 * @return bool
1429
 */
1430
function api_block_anonymous_users($printHeaders = true)
1431
{
1432
    $user = api_get_user_info();
1433
    if (!(isset($user['user_id']) && $user['user_id']) || api_is_anonymous($user['user_id'], true)) {
1434
        api_not_allowed($printHeaders);
1435
1436
        return false;
1437
    }
1438
    api_block_inactive_user();
1439
1440
    return true;
1441
}
1442
1443
/**
1444
 * Returns a rough evaluation of the browser's name and version based on very
1445
 * simple regexp.
1446
 *
1447
 * @return array with the navigator name and version ['name' => '...', 'version' => '...']
1448
 */
1449
function api_get_navigator()
1450
{
1451
    $navigator = 'Unknown';
1452
    $version = 0;
1453
1454
    if (!isset($_SERVER['HTTP_USER_AGENT'])) {
1455
        return ['name' => 'Unknown', 'version' => '0.0.0'];
1456
    }
1457
1458
    if (strpos($_SERVER['HTTP_USER_AGENT'], 'Opera') !== false) {
1459
        $navigator = 'Opera';
1460
        list(, $version) = explode('Opera', $_SERVER['HTTP_USER_AGENT']);
1461
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Edge') !== false) {
1462
        $navigator = 'Edge';
1463
        list(, $version) = explode('Edge', $_SERVER['HTTP_USER_AGENT']);
1464
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== false) {
1465
        $navigator = 'Internet Explorer';
1466
        list(, $version) = explode('MSIE ', $_SERVER['HTTP_USER_AGENT']);
1467
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Chrome') !== false) {
1468
        $navigator = 'Chrome';
1469
        list(, $version) = explode('Chrome', $_SERVER['HTTP_USER_AGENT']);
1470
    } elseif (stripos($_SERVER['HTTP_USER_AGENT'], 'Safari') !== false) {
1471
        $navigator = 'Safari';
1472
        if (stripos($_SERVER['HTTP_USER_AGENT'], 'Version/') !== false) {
1473
            // If this Safari does have the "Version/" string in its user agent
1474
            // then use that as a version indicator rather than what's after
1475
            // "Safari/" which is rather a "build number" or something
1476
            list(, $version) = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1477
        } else {
1478
            list(, $version) = explode('Safari/', $_SERVER['HTTP_USER_AGENT']);
1479
        }
1480
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Firefox') !== false) {
1481
        $navigator = 'Firefox';
1482
        list(, $version) = explode('Firefox', $_SERVER['HTTP_USER_AGENT']);
1483
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Netscape') !== false) {
1484
        $navigator = 'Netscape';
1485
        if (stripos($_SERVER['HTTP_USER_AGENT'], 'Netscape/') !== false) {
1486
            list(, $version) = explode('Netscape', $_SERVER['HTTP_USER_AGENT']);
1487
        } else {
1488
            list(, $version) = explode('Navigator', $_SERVER['HTTP_USER_AGENT']);
1489
        }
1490
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Konqueror') !== false) {
1491
        $navigator = 'Konqueror';
1492
        list(, $version) = explode('Konqueror', $_SERVER['HTTP_USER_AGENT']);
1493
    } elseif (stripos($_SERVER['HTTP_USER_AGENT'], 'applewebkit') !== false) {
1494
        $navigator = 'AppleWebKit';
1495
        list(, $version) = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1496
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Gecko') !== false) {
1497
        $navigator = 'Mozilla';
1498
        list(, $version) = explode('; rv:', $_SERVER['HTTP_USER_AGENT']);
1499
    }
1500
1501
    // Now cut extra stuff around (mostly *after*) the version number
1502
    $version = preg_replace('/^([\/\s])?([\d\.]+)?.*/', '\2', $version);
1503
1504
    if (strpos($version, '.') === false) {
1505
        $version = number_format(doubleval($version), 1);
1506
    }
1507
1508
    return ['name' => $navigator, 'version' => $version];
1509
}
1510
1511
/**
1512
 * @return true if user self registration is allowed, false otherwise
1513
 */
1514
function api_is_self_registration_allowed()
1515
{
1516
    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...
1517
}
1518
1519
/**
1520
 * This function returns the id of the user which is stored in the $_user array.
1521
 *
1522
 * example: The function can be used to check if a user is logged in
1523
 *          if (api_get_user_id())
1524
 *
1525
 * @return int the id of the current user, 0 if is empty
1526
 */
1527
function api_get_user_id()
1528
{
1529
    $userInfo = Session::read('_user');
1530
    if ($userInfo && isset($userInfo['user_id'])) {
1531
        return (int) $userInfo['user_id'];
1532
    }
1533
1534
    return 0;
1535
}
1536
1537
/**
1538
 * Gets the list of courses a specific user is subscribed to.
1539
 *
1540
 * @param int       User ID
1541
 * @param bool $fetch_session Whether to get session courses or not - NOT YET IMPLEMENTED
1542
 *
1543
 * @return array Array of courses in the form [0]=>('code'=>xxx,'db'=>xxx,'dir'=>xxx,'status'=>d)
1544
 *
1545
 * @deprecated use CourseManager::get_courses_list_by_user_id()
1546
 */
1547
function api_get_user_courses($userId, $fetch_session = true)
1548
{
1549
    // Get out if not integer
1550
    if ($userId != strval(intval($userId))) {
1551
        return [];
1552
    }
1553
1554
    $t_course = Database::get_main_table(TABLE_MAIN_COURSE);
1555
    $t_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
1556
1557
    $sql = "SELECT cc.id as real_id, cc.code code, cc.directory dir, cu.status status
1558
            FROM $t_course cc, $t_course_user cu
1559
            WHERE
1560
                cc.id = cu.c_id AND
1561
                cu.user_id = $userId AND
1562
                cu.relation_type <> ".COURSE_RELATION_TYPE_RRHH;
1563
    $result = Database::query($sql);
1564
    if ($result === false) {
1565
        return [];
1566
    }
1567
1568
    $courses = [];
1569
    while ($row = Database::fetch_array($result)) {
1570
        // we only need the database name of the course
1571
        $courses[] = $row;
1572
    }
1573
1574
    return $courses;
1575
}
1576
1577
/**
1578
 * Formats user information into a standard array
1579
 * This function should be only used inside api_get_user_info().
1580
 *
1581
 * @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...
1582
 * @param bool $add_password
1583
 * @param bool $loadAvatars  turn off to improve performance
1584
 *
1585
 * @return array Standard user array
1586
 */
1587
function _api_format_user($user, $add_password = false, $loadAvatars = true)
1588
{
1589
    $result = [];
1590
1591
    $result['firstname'] = null;
1592
    $result['lastname'] = null;
1593
1594
    if (isset($user['firstname']) && isset($user['lastname'])) { // with only lowercase
1595
        $result['firstname'] = $user['firstname'];
1596
        $result['lastname'] = $user['lastname'];
1597
    } elseif (isset($user['firstName']) && isset($user['lastName'])) { // with uppercase letters
1598
        $result['firstname'] = isset($user['firstName']) ? $user['firstName'] : null;
1599
        $result['lastname'] = isset($user['lastName']) ? $user['lastName'] : null;
1600
    }
1601
1602
    if (isset($user['email'])) {
1603
        $result['mail'] = isset($user['email']) ? $user['email'] : null;
1604
        $result['email'] = isset($user['email']) ? $user['email'] : null;
1605
    } else {
1606
        $result['mail'] = isset($user['mail']) ? $user['mail'] : null;
1607
        $result['email'] = isset($user['mail']) ? $user['mail'] : null;
1608
    }
1609
1610
    $result['complete_name'] = api_get_person_name($result['firstname'], $result['lastname']);
1611
    $result['complete_name_with_username'] = $result['complete_name'];
1612
1613
    if (!empty($user['username']) && !api_get_configuration_value('hide_username_with_complete_name')) {
1614
        $result['complete_name_with_username'] = $result['complete_name'].' ('.$user['username'].')';
1615
    }
1616
1617
    $showEmail = api_get_setting('show_email_addresses') === 'true';
1618
    if (!empty($user['email'])) {
1619
        $result['complete_name_with_email_forced'] = $result['complete_name'].' ('.$user['email'].')';
1620
        if ($showEmail) {
1621
            $result['complete_name_with_email'] = $result['complete_name'].' ('.$user['email'].')';
1622
        }
1623
    } else {
1624
        $result['complete_name_with_email'] = $result['complete_name'];
1625
        $result['complete_name_with_email_forced'] = $result['complete_name'];
1626
    }
1627
1628
    // Kept for historical reasons
1629
    $result['firstName'] = $result['firstname'];
1630
    $result['lastName'] = $result['lastname'];
1631
1632
    $attributes = [
1633
        'phone',
1634
        'address',
1635
        'picture_uri',
1636
        'official_code',
1637
        'status',
1638
        'active',
1639
        'auth_source',
1640
        'username',
1641
        'theme',
1642
        'language',
1643
        'creator_id',
1644
        'registration_date',
1645
        'hr_dept_id',
1646
        'expiration_date',
1647
        'last_login',
1648
        'user_is_online',
1649
    ];
1650
1651
    if (api_get_setting('extended_profile') === 'true') {
1652
        $attributes[] = 'competences';
1653
        $attributes[] = 'diplomas';
1654
        $attributes[] = 'teach';
1655
        $attributes[] = 'openarea';
1656
    }
1657
1658
    foreach ($attributes as $attribute) {
1659
        $result[$attribute] = isset($user[$attribute]) ? $user[$attribute] : null;
1660
    }
1661
1662
    $user_id = (int) $user['user_id'];
1663
    // Maintain the user_id index for backwards compatibility
1664
    $result['user_id'] = $result['id'] = $user_id;
1665
1666
    $hasCertificates = Certificate::getCertificateByUser($user_id);
1667
    $result['has_certificates'] = 0;
1668
    if (!empty($hasCertificates)) {
1669
        $result['has_certificates'] = 1;
1670
    }
1671
1672
    $result['icon_status'] = '';
1673
    $result['icon_status_medium'] = '';
1674
1675
    $result['is_admin'] = UserManager::is_admin($user_id);
1676
1677
    // Getting user avatar.
1678
    if ($loadAvatars) {
1679
        $result['avatar'] = '';
1680
        $result['avatar_no_query'] = '';
1681
        $result['avatar_small'] = '';
1682
        $result['avatar_medium'] = '';
1683
1684
        if (!isset($user['avatar'])) {
1685
            $originalFile = UserManager::getUserPicture(
1686
                $user_id,
1687
                USER_IMAGE_SIZE_ORIGINAL,
1688
                null,
1689
                $result
1690
            );
1691
            $result['avatar'] = $originalFile;
1692
            $avatarString = explode('?', $result['avatar']);
1693
            $result['avatar_no_query'] = reset($avatarString);
1694
        } else {
1695
            $result['avatar'] = $user['avatar'];
1696
            $avatarString = explode('?', $user['avatar']);
1697
            $result['avatar_no_query'] = reset($avatarString);
1698
        }
1699
1700
        if (!isset($user['avatar_small'])) {
1701
            $smallFile = UserManager::getUserPicture(
1702
                $user_id,
1703
                USER_IMAGE_SIZE_SMALL,
1704
                null,
1705
                $result
1706
            );
1707
            $result['avatar_small'] = $smallFile;
1708
        } else {
1709
            $result['avatar_small'] = $user['avatar_small'];
1710
        }
1711
1712
        if (!isset($user['avatar_medium'])) {
1713
            $mediumFile = UserManager::getUserPicture(
1714
                $user_id,
1715
                USER_IMAGE_SIZE_MEDIUM,
1716
                null,
1717
                $result
1718
            );
1719
            $result['avatar_medium'] = $mediumFile;
1720
        } else {
1721
            $result['avatar_medium'] = $user['avatar_medium'];
1722
        }
1723
1724
        $urlImg = api_get_path(WEB_IMG_PATH);
1725
        $iconStatus = '';
1726
        $iconStatusMedium = '';
1727
        $label = '';
1728
        switch ($result['status']) {
1729
            case STUDENT:
1730
                if ($result['has_certificates']) {
1731
                    $iconStatus = $urlImg.'icons/svg/identifier_graduated.svg';
1732
                    $label = get_lang('Graduated');
1733
                } else {
1734
                    $iconStatus = $urlImg.'icons/svg/identifier_student.svg';
1735
                    $label = get_lang('Student');
1736
                }
1737
                break;
1738
            case COURSEMANAGER:
1739
                if ($result['is_admin']) {
1740
                    $iconStatus = $urlImg.'icons/svg/identifier_admin.svg';
1741
                    $label = get_lang('Admin');
1742
                } else {
1743
                    $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1744
                    $label = get_lang('Teacher');
1745
                }
1746
                break;
1747
            case STUDENT_BOSS:
1748
                $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1749
                $label = get_lang('StudentBoss');
1750
                break;
1751
        }
1752
1753
        if (!empty($iconStatus)) {
1754
            $iconStatusMedium = '<img src="'.$iconStatus.'" width="32px" height="32px">';
1755
            $iconStatus = '<img src="'.$iconStatus.'" width="22px" height="22px">';
1756
        }
1757
1758
        $result['icon_status'] = $iconStatus;
1759
        $result['icon_status_label'] = $label;
1760
        $result['icon_status_medium'] = $iconStatusMedium;
1761
    }
1762
1763
    if (isset($user['user_is_online'])) {
1764
        $result['user_is_online'] = $user['user_is_online'] == true ? 1 : 0;
1765
    }
1766
    if (isset($user['user_is_online_in_chat'])) {
1767
        $result['user_is_online_in_chat'] = (int) $user['user_is_online_in_chat'];
1768
    }
1769
1770
    if ($add_password) {
1771
        $result['password'] = $user['password'];
1772
    }
1773
1774
    if (isset($result['profile_completed'])) {
1775
        $result['profile_completed'] = $user['profile_completed'];
1776
    }
1777
1778
    $result['profile_url'] = api_get_path(WEB_CODE_PATH).'social/profile.php?u='.$user_id;
1779
1780
    // Send message link
1781
    $sendMessage = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&user_id='.$user_id;
1782
    $result['complete_name_with_message_link'] = Display::url(
1783
        $result['complete_name_with_username'],
1784
        $sendMessage,
1785
        ['class' => 'ajax']
1786
    );
1787
1788
    if (isset($user['extra'])) {
1789
        $result['extra'] = $user['extra'];
1790
    }
1791
1792
    return $result;
1793
}
1794
1795
/**
1796
 * Finds all the information about a user.
1797
 * If no parameter is passed you find all the information about the current user.
1798
 *
1799
 * @param int  $user_id
1800
 * @param bool $checkIfUserOnline
1801
 * @param bool $showPassword
1802
 * @param bool $loadExtraData
1803
 * @param bool $loadOnlyVisibleExtraData Get the user extra fields that are visible
1804
 * @param bool $loadAvatars              turn off to improve performance and if avatars are not needed
1805
 * @param bool $updateCache              update apc cache if exists
1806
 *
1807
 * @return mixed $user_info user_id, lastname, firstname, username, email, etc or false on error
1808
 *
1809
 * @author Patrick Cool <[email protected]>
1810
 * @author Julio Montoya
1811
 *
1812
 * @version 21 September 2004
1813
 */
1814
function api_get_user_info(
1815
    $user_id = 0,
1816
    $checkIfUserOnline = false,
1817
    $showPassword = false,
1818
    $loadExtraData = false,
1819
    $loadOnlyVisibleExtraData = false,
1820
    $loadAvatars = true,
1821
    $updateCache = false
1822
) {
1823
    $apcVar = null;
1824
    $user = false;
1825
    $cacheAvailable = api_get_configuration_value('apc');
1826
1827
    if (empty($user_id)) {
1828
        $userFromSession = Session::read('_user');
1829
1830
        if (isset($userFromSession)) {
1831
            if ($cacheAvailable === true &&
1832
                (
1833
                    empty($userFromSession['is_anonymous']) &&
1834
                    (isset($userFromSession['status']) && $userFromSession['status'] != ANONYMOUS)
1835
                )
1836
            ) {
1837
                $apcVar = api_get_configuration_value('apc_prefix').'userinfo_'.$userFromSession['user_id'];
1838
                if (apcu_exists($apcVar)) {
1839
                    if ($updateCache) {
1840
                        apcu_store($apcVar, $userFromSession, 60);
1841
                    }
1842
                    $user = apcu_fetch($apcVar);
1843
                } else {
1844
                    $user = _api_format_user(
1845
                        $userFromSession,
1846
                        $showPassword,
1847
                        $loadAvatars
1848
                    );
1849
                    apcu_store($apcVar, $user, 60);
1850
                }
1851
            } else {
1852
                $user = _api_format_user(
1853
                    $userFromSession,
1854
                    $showPassword,
1855
                    $loadAvatars
1856
                );
1857
            }
1858
1859
            return $user;
1860
        }
1861
1862
        return false;
1863
    }
1864
1865
    // Make sure user_id is safe
1866
    $user_id = (int) $user_id;
1867
1868
    // Re-use user information if not stale and already stored in APCu
1869
    if ($cacheAvailable === true) {
1870
        $apcVar = api_get_configuration_value('apc_prefix').'userinfo_'.$user_id;
1871
        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...
1872
            $user = apcu_fetch($apcVar);
1873
1874
            return $user;
1875
        }
1876
    }
1877
1878
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1879
            WHERE id = $user_id";
1880
    $result = Database::query($sql);
1881
    if (Database::num_rows($result) > 0) {
1882
        $result_array = Database::fetch_array($result);
1883
        $result_array['user_is_online_in_chat'] = 0;
1884
        if ($checkIfUserOnline) {
1885
            $use_status_in_platform = user_is_online($user_id);
1886
            $result_array['user_is_online'] = $use_status_in_platform;
1887
            $user_online_in_chat = 0;
1888
            if ($use_status_in_platform) {
1889
                $user_status = UserManager::get_extra_user_data_by_field(
1890
                    $user_id,
1891
                    'user_chat_status',
1892
                    false,
1893
                    true
1894
                );
1895
                if ((int) $user_status['user_chat_status'] == 1) {
1896
                    $user_online_in_chat = 1;
1897
                }
1898
            }
1899
            $result_array['user_is_online_in_chat'] = $user_online_in_chat;
1900
        }
1901
1902
        if ($loadExtraData) {
1903
            $fieldValue = new ExtraFieldValue('user');
1904
            $result_array['extra'] = $fieldValue->getAllValuesForAnItem(
1905
                $user_id,
1906
                $loadOnlyVisibleExtraData
1907
            );
1908
        }
1909
        $user = _api_format_user($result_array, $showPassword, $loadAvatars);
1910
    }
1911
1912
    if ($cacheAvailable === true) {
1913
        apcu_store($apcVar, $user, 60);
1914
    }
1915
1916
    return $user;
1917
}
1918
1919
/**
1920
 * @param int $userId
1921
 *
1922
 * @return User
1923
 */
1924
function api_get_user_entity($userId)
1925
{
1926
    $userId = (int) $userId;
1927
    $repo = UserManager::getRepository();
1928
1929
    /** @var User $user */
1930
    $user = $repo->find($userId);
1931
1932
    return $user;
1933
}
1934
1935
/**
1936
 * Finds all the information about a user from username instead of user id.
1937
 *
1938
 * @param string $username
1939
 *
1940
 * @return mixed $user_info array user_id, lastname, firstname, username, email or false on error
1941
 *
1942
 * @author Yannick Warnier <[email protected]>
1943
 */
1944
function api_get_user_info_from_username($username)
1945
{
1946
    if (empty($username)) {
1947
        return false;
1948
    }
1949
    $username = trim($username);
1950
1951
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1952
            WHERE username='".Database::escape_string($username)."'";
1953
    $result = Database::query($sql);
1954
    if (Database::num_rows($result) > 0) {
1955
        $resultArray = Database::fetch_array($result);
1956
1957
        return _api_format_user($resultArray);
1958
    }
1959
1960
    return false;
1961
}
1962
1963
/**
1964
 * Get first user with an email.
1965
 *
1966
 * @param string $email
1967
 *
1968
 * @return array|bool
1969
 */
1970
function api_get_user_info_from_email($email = '')
1971
{
1972
    if (empty($email)) {
1973
        return false;
1974
    }
1975
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1976
            WHERE email ='".Database::escape_string($email)."' LIMIT 1";
1977
    $result = Database::query($sql);
1978
    if (Database::num_rows($result) > 0) {
1979
        $resultArray = Database::fetch_array($result);
1980
1981
        return _api_format_user($resultArray);
1982
    }
1983
1984
    return false;
1985
}
1986
1987
/**
1988
 * @return string
1989
 */
1990
function api_get_course_id()
1991
{
1992
    return Session::read('_cid', null);
1993
}
1994
1995
/**
1996
 * Returns the current course id (integer).
1997
 *
1998
 * @param string $code Optional course code
1999
 *
2000
 * @return int
2001
 */
2002
function api_get_course_int_id($code = null)
2003
{
2004
    if (!empty($code)) {
2005
        $code = Database::escape_string($code);
2006
        $row = Database::select(
2007
            'id',
2008
            Database::get_main_table(TABLE_MAIN_COURSE),
2009
            ['where' => ['code = ?' => [$code]]],
2010
            'first'
2011
        );
2012
2013
        if (is_array($row) && isset($row['id'])) {
2014
            return $row['id'];
2015
        } else {
2016
            return false;
2017
        }
2018
    }
2019
2020
    return Session::read('_real_cid', 0);
2021
}
2022
2023
/**
2024
 * Returns the current course directory.
2025
 *
2026
 * This function relies on api_get_course_info()
2027
 *
2028
 * @param string    The course code - optional (takes it from session if not given)
2029
 *
2030
 * @return string The directory where the course is located inside the Chamilo "courses" directory
2031
 *
2032
 * @author Yannick Warnier <[email protected]>
2033
 */
2034
function api_get_course_path($course_code = null)
2035
{
2036
    $info = !empty($course_code) ? api_get_course_info($course_code) : api_get_course_info();
2037
2038
    return $info['path'];
2039
}
2040
2041
/**
2042
 * Gets a course setting from the current course_setting table. Try always using integer values.
2043
 *
2044
 * @param string $settingName The name of the setting we want from the table
2045
 * @param array  $courseInfo
2046
 * @param bool   $force       force checking the value in the database
2047
 *
2048
 * @return mixed The value of that setting in that table. Return -1 if not found.
2049
 */
2050
function api_get_course_setting($settingName, $courseInfo = [], $force = false)
2051
{
2052
    if (empty($courseInfo)) {
2053
        $courseInfo = api_get_course_info();
2054
    }
2055
2056
    if (empty($courseInfo) || empty($settingName)) {
2057
        return -1;
2058
    }
2059
2060
    $courseId = isset($courseInfo['real_id']) && !empty($courseInfo['real_id']) ? $courseInfo['real_id'] : 0;
2061
2062
    if (empty($courseId)) {
2063
        return -1;
2064
    }
2065
2066
    static $courseSettingInfo = [];
2067
2068
    if ($force) {
2069
        $courseSettingInfo = [];
2070
    }
2071
2072
    if (!isset($courseSettingInfo[$courseId])) {
2073
        $table = Database::get_course_table(TABLE_COURSE_SETTING);
2074
        $settingName = Database::escape_string($settingName);
2075
2076
        $sql = "SELECT variable, value FROM $table
2077
                WHERE c_id = $courseId ";
2078
        $res = Database::query($sql);
2079
        if (Database::num_rows($res) > 0) {
2080
            $result = Database::store_result($res, 'ASSOC');
2081
            $courseSettingInfo[$courseId] = array_column($result, 'value', 'variable');
2082
2083
            if (isset($courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'])) {
2084
                $value = $courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'];
2085
                if (!is_null($value)) {
2086
                    $result = explode(',', $value);
2087
                    $courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'] = $result;
2088
                }
2089
            }
2090
        }
2091
    }
2092
2093
    if (isset($courseSettingInfo[$courseId]) && array_key_exists($settingName, $courseSettingInfo[$courseId])) {
2094
        return $courseSettingInfo[$courseId][$settingName];
2095
    }
2096
2097
    return -1;
2098
}
2099
2100
function api_get_course_plugin_setting($plugin, $settingName, $courseInfo = [])
2101
{
2102
    $value = api_get_course_setting($settingName, $courseInfo, true);
2103
2104
    if (-1 === $value) {
2105
        // Check global settings
2106
        $value = api_get_plugin_setting($plugin, $settingName);
2107
        if ($value === 'true') {
2108
            return 1;
2109
        }
2110
        if ($value === 'false') {
2111
            return 0;
2112
        }
2113
        if (null === $value) {
2114
            return -1;
2115
        }
2116
    }
2117
2118
    return $value;
2119
}
2120
2121
/**
2122
 * Gets an anonymous user ID.
2123
 *
2124
 * For some tools that need tracking, like the learnpath tool, it is necessary
2125
 * to have a usable user-id to enable some kind of tracking, even if not
2126
 * perfect. An anonymous ID is taken from the users table by looking for a
2127
 * status of "6" (anonymous).
2128
 *
2129
 * @return int User ID of the anonymous user, or O if no anonymous user found
2130
 */
2131
function api_get_anonymous_id()
2132
{
2133
    // Find if another anon is connected now
2134
    $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
2135
    $tableU = Database::get_main_table(TABLE_MAIN_USER);
2136
    $ip = Database::escape_string(api_get_real_ip());
2137
    $max = (int) api_get_configuration_value('max_anonymous_users');
2138
    if ($max >= 2) {
2139
        $sql = "SELECT * FROM $table as TEL
2140
                JOIN $tableU as U
2141
                ON U.user_id = TEL.login_user_id
2142
                WHERE TEL.user_ip = '$ip'
2143
                    AND U.status = ".ANONYMOUS."
2144
                    AND U.user_id != 2 ";
2145
2146
        $result = Database::query($sql);
2147
        if (empty(Database::num_rows($result))) {
2148
            $login = uniqid('anon_');
2149
            $anonList = UserManager::get_user_list(['status' => ANONYMOUS], ['registration_date ASC']);
2150
            if (count($anonList) >= $max) {
2151
                foreach ($anonList as $userToDelete) {
2152
                    UserManager::delete_user($userToDelete['user_id']);
2153
                    break;
2154
                }
2155
            }
2156
            // Return the user ID
2157
            return UserManager::create_user(
0 ignored issues
show
Bug Best Practice introduced by
The expression return UserManager::crea...lhost', $login, $login) could also return false which is incompatible with the documented return type integer. Did you maybe forget to handle an error condition?

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

Loading history...
2158
                $login,
2159
                'anon',
2160
                ANONYMOUS,
2161
                ' anonymous@localhost',
2162
                $login,
2163
                $login
2164
            );
2165
        } else {
2166
            $row = Database::fetch_array($result, 'ASSOC');
2167
2168
            return $row['user_id'];
2169
        }
2170
    }
2171
2172
    $table = Database::get_main_table(TABLE_MAIN_USER);
2173
    $sql = "SELECT user_id
2174
            FROM $table
2175
            WHERE status = ".ANONYMOUS." ";
2176
    $res = Database::query($sql);
2177
    if (Database::num_rows($res) > 0) {
2178
        $row = Database::fetch_array($res, 'ASSOC');
2179
2180
        return $row['user_id'];
2181
    }
2182
2183
    // No anonymous user was found.
2184
    return 0;
2185
}
2186
2187
/**
2188
 * @param string $courseCode
2189
 * @param int    $sessionId
2190
 * @param int    $groupId
2191
 *
2192
 * @return string
2193
 */
2194
function api_get_cidreq_params($courseCode, $sessionId = 0, $groupId = 0)
2195
{
2196
    $courseCode = !empty($courseCode) ? htmlspecialchars($courseCode) : '';
2197
    $sessionId = !empty($sessionId) ? (int) $sessionId : 0;
2198
    $groupId = !empty($groupId) ? (int) $groupId : 0;
2199
2200
    $url = 'cidReq='.$courseCode;
2201
    $url .= '&id_session='.$sessionId;
2202
    $url .= '&gidReq='.$groupId;
2203
2204
    return $url;
2205
}
2206
2207
/**
2208
 * Returns the current course url part including session, group, and gradebook params.
2209
 *
2210
 * @param bool   $addSessionId
2211
 * @param bool   $addGroupId
2212
 * @param string $origin
2213
 *
2214
 * @return string Course & session references to add to a URL
2215
 */
2216
function api_get_cidreq($addSessionId = true, $addGroupId = true, $origin = '')
2217
{
2218
    $courseCode = api_get_course_id();
2219
    $url = empty($courseCode) ? '' : 'cidReq='.urlencode(htmlspecialchars($courseCode));
2220
    $origin = empty($origin) ? api_get_origin() : urlencode(Security::remove_XSS($origin));
2221
2222
    if ($addSessionId) {
2223
        if (!empty($url)) {
2224
            $url .= api_get_session_id() == 0 ? '&id_session=0' : '&id_session='.api_get_session_id();
2225
        }
2226
    }
2227
2228
    if ($addGroupId) {
2229
        if (!empty($url)) {
2230
            $url .= api_get_group_id() == 0 ? '&gidReq=0' : '&gidReq='.api_get_group_id();
2231
        }
2232
    }
2233
2234
    if (!empty($url)) {
2235
        $url .= '&gradebook='.intval(api_is_in_gradebook());
2236
        $url .= '&origin='.$origin;
2237
    }
2238
2239
    return $url;
2240
}
2241
2242
/**
2243
 * Get if we visited a gradebook page.
2244
 *
2245
 * @return bool
2246
 */
2247
function api_is_in_gradebook()
2248
{
2249
    return Session::read('in_gradebook', false);
2250
}
2251
2252
/**
2253
 * Set that we are in a page inside a gradebook.
2254
 */
2255
function api_set_in_gradebook()
2256
{
2257
    Session::write('in_gradebook', true);
2258
}
2259
2260
/**
2261
 * Remove gradebook session.
2262
 */
2263
function api_remove_in_gradebook()
2264
{
2265
    Session::erase('in_gradebook');
2266
}
2267
2268
/**
2269
 * Returns the current course info array see api_format_course_array()
2270
 * If the course_code is given, the returned array gives info about that
2271
 * particular course, if none given it gets the course info from the session.
2272
 *
2273
 * @param string $course_code
2274
 *
2275
 * @return array
2276
 */
2277
function api_get_course_info($course_code = null)
2278
{
2279
    if (!empty($course_code)) {
2280
        $course_code = Database::escape_string($course_code);
2281
        $courseId = api_get_course_int_id($course_code);
2282
2283
        if (empty($courseId)) {
2284
            return [];
2285
        }
2286
2287
        $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
2288
        $course_cat_table = Database::get_main_table(TABLE_MAIN_CATEGORY);
2289
        $sql = "SELECT
2290
                    course.*,
2291
                    course_category.code faCode,
2292
                    course_category.name faName
2293
                FROM $course_table
2294
                LEFT JOIN $course_cat_table
2295
                ON course.category_code = course_category.code
2296
                WHERE course.id = $courseId";
2297
        $result = Database::query($sql);
2298
        $courseInfo = [];
2299
        if (Database::num_rows($result) > 0) {
2300
            $data = Database::fetch_array($result);
2301
            $courseInfo = api_format_course_array($data);
2302
        }
2303
2304
        return $courseInfo;
2305
    }
2306
2307
    global $_course;
2308
    if ($_course == '-1') {
2309
        $_course = [];
2310
    }
2311
2312
    return $_course;
2313
}
2314
2315
/**
2316
 * @param int $courseId
2317
 *
2318
 * @return \Chamilo\CoreBundle\Entity\Course
2319
 */
2320
function api_get_course_entity($courseId = 0)
2321
{
2322
    if (empty($courseId)) {
2323
        $courseId = api_get_course_int_id();
2324
    }
2325
2326
    return Database::getManager()->getRepository('ChamiloCoreBundle:Course')->find($courseId);
2327
}
2328
2329
function api_get_group_entity($id = 0)
2330
{
2331
    if (empty($id)) {
2332
        $id = api_get_group_id();
2333
    }
2334
2335
    return Database::getManager()->getRepository('ChamiloCourseBundle:CGroupInfo')->find($id);
2336
}
2337
2338
/**
2339
 * @param int $id
2340
 *
2341
 * @return \Chamilo\CoreBundle\Entity\Session
2342
 */
2343
function api_get_session_entity($id = 0)
2344
{
2345
    if (empty($id)) {
2346
        $id = api_get_session_id();
2347
    }
2348
2349
    return Database::getManager()->getRepository('ChamiloCoreBundle:Session')->find($id);
2350
}
2351
2352
/**
2353
 * Returns the current course info array.
2354
2355
 * Now if the course_code is given, the returned array gives info about that
2356
 * particular course, not specially the current one.
2357
 *
2358
 * @param int $id Numeric ID of the course
2359
 *
2360
 * @return array The course info as an array formatted by api_format_course_array, including category.name
2361
 */
2362
function api_get_course_info_by_id($id = null)
2363
{
2364
    if (!empty($id)) {
2365
        $id = (int) $id;
2366
        $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
2367
        $course_cat_table = Database::get_main_table(TABLE_MAIN_CATEGORY);
2368
        $sql = "SELECT
2369
                    course.*,
2370
                    course_category.code faCode,
2371
                    course_category.name faName
2372
                FROM $course_table
2373
                LEFT JOIN $course_cat_table
2374
                ON course.category_code = course_category.code
2375
                WHERE course.id = $id";
2376
        $result = Database::query($sql);
2377
        $_course = [];
2378
        if (Database::num_rows($result) > 0) {
2379
            $row = Database::fetch_array($result);
2380
            $_course = api_format_course_array($row);
2381
        }
2382
2383
        return $_course;
2384
    }
2385
2386
    global $_course;
2387
    if ($_course == '-1') {
2388
        $_course = [];
2389
    }
2390
2391
    return $_course;
2392
}
2393
2394
/**
2395
 * Reformat the course array (output by api_get_course_info()) in order, mostly,
2396
 * to switch from 'code' to 'id' in the array. This is a legacy feature and is
2397
 * now possibly causing massive confusion as a new "id" field has been added to
2398
 * the course table in 1.9.0.
2399
 *
2400
 * @param $course_data
2401
 *
2402
 * @return array
2403
 *
2404
 * @todo eradicate the false "id"=code field of the $_course array and use the int id
2405
 */
2406
function api_format_course_array($course_data)
2407
{
2408
    if (empty($course_data)) {
2409
        return [];
2410
    }
2411
2412
    $_course = [];
2413
    $_course['id'] = $course_data['code'];
2414
    $_course['real_id'] = $course_data['id'];
2415
2416
    // Added
2417
    $_course['code'] = $course_data['code'];
2418
    $_course['name'] = $course_data['title'];
2419
    $_course['title'] = $course_data['title'];
2420
    $_course['official_code'] = $course_data['visual_code'];
2421
    $_course['visual_code'] = $course_data['visual_code'];
2422
    $_course['sysCode'] = $course_data['code'];
2423
    $_course['path'] = $course_data['directory']; // Use as key in path.
2424
    $_course['directory'] = $course_data['directory'];
2425
    $_course['creation_date'] = $course_data['creation_date'];
2426
    $_course['titular'] = $course_data['tutor_name'];
2427
    $_course['tutor_name'] = $course_data['tutor_name'];
2428
    $_course['language'] = $course_data['course_language'];
2429
    $_course['extLink']['url'] = $course_data['department_url'];
2430
    $_course['extLink']['name'] = $course_data['department_name'];
2431
    $_course['categoryCode'] = $course_data['faCode'];
2432
    $_course['category_code'] = $course_data['faCode'];
2433
    $_course['categoryName'] = $course_data['faName'];
2434
    $_course['visibility'] = $course_data['visibility'];
2435
    $_course['subscribe_allowed'] = $course_data['subscribe'];
2436
    $_course['subscribe'] = $course_data['subscribe'];
2437
    $_course['unsubscribe'] = $course_data['unsubscribe'];
2438
    $_course['course_language'] = $course_data['course_language'];
2439
    $_course['activate_legal'] = isset($course_data['activate_legal']) ? $course_data['activate_legal'] : false;
2440
    $_course['legal'] = $course_data['legal'];
2441
    $_course['show_score'] = $course_data['show_score']; //used in the work tool
2442
    $_course['department_name'] = $course_data['department_name'];
2443
    $_course['department_url'] = $course_data['department_url'];
2444
2445
    $courseSys = api_get_path(SYS_COURSE_PATH).$course_data['directory'];
2446
    $webCourseHome = api_get_path(WEB_COURSE_PATH).$course_data['directory'];
2447
2448
    // Course password
2449
    $_course['registration_code'] = !empty($course_data['registration_code']) ? sha1($course_data['registration_code']) : null;
2450
    $_course['disk_quota'] = $course_data['disk_quota'];
2451
    $_course['course_public_url'] = $webCourseHome.'/index.php';
2452
    $_course['course_sys_path'] = $courseSys.'/';
2453
2454
    if (array_key_exists('add_teachers_to_sessions_courses', $course_data)) {
2455
        $_course['add_teachers_to_sessions_courses'] = $course_data['add_teachers_to_sessions_courses'];
2456
    }
2457
2458
    // Course image
2459
    $_course['course_image_source'] = '';
2460
    if (file_exists($courseSys.'/course-pic85x85.png')) {
2461
        $url_image = $webCourseHome.'/course-pic85x85.png';
2462
        $_course['course_image_source'] = $courseSys.'/course-pic85x85.png';
2463
    } else {
2464
        $url_image = Display::return_icon(
2465
            'course.png',
2466
            null,
2467
            null,
2468
            ICON_SIZE_LARGE,
2469
            null,
2470
            true,
2471
            true
2472
        );
2473
    }
2474
    $_course['course_image'] = $url_image;
2475
2476
    // Course large image
2477
    $_course['course_image_large_source'] = '';
2478
    if (file_exists($courseSys.'/course-pic.png')) {
2479
        $url_image = $webCourseHome.'/course-pic.png';
2480
        $_course['course_image_large_source'] = $courseSys.'/course-pic.png';
2481
    } else {
2482
        $url_image = Display::return_icon(
2483
            'session_default.png',
2484
            null,
2485
            null,
2486
            null,
2487
            null,
2488
            true,
2489
            true
2490
        );
2491
    }
2492
2493
    $_course['course_image_large'] = $url_image;
2494
2495
    return $_course;
2496
}
2497
2498
/**
2499
 * Returns a difficult to guess password.
2500
 *
2501
 * @param int $length the length of the password
2502
 *
2503
 * @return string the generated password
2504
 */
2505
function api_generate_password($length = 8)
2506
{
2507
    if ($length < 2) {
2508
        $length = 2;
2509
    }
2510
2511
    $charactersLowerCase = Security::CHAR_LOWER;
2512
    $charactersUpperCase = Security::CHAR_UPPER;
2513
    $charactersSpecials = Security::CHAR_SYMBOLS;
2514
    $minNumbers = 2;
2515
    $length = $length - $minNumbers;
2516
    $minLowerCase = round($length / 2);
2517
    $minUpperCase = $length - $minLowerCase;
2518
2519
    $password = '';
2520
    $passwordRequirements = api_get_configuration_value('password_requirements');
2521
2522
    $factory = new RandomLib\Factory();
2523
    $generator = $factory->getMediumStrengthGenerator();
2524
2525
    if (!empty($passwordRequirements)) {
2526
        $length = $passwordRequirements['min']['length'];
2527
        $minNumbers = $passwordRequirements['min']['numeric'];
2528
        $minLowerCase = $passwordRequirements['min']['lowercase'];
2529
        $minUpperCase = $passwordRequirements['min']['uppercase'];
2530
        $minSpecials = $passwordRequirements['min']['specials'];
2531
2532
        $rest = $length - $minNumbers - $minLowerCase - $minUpperCase - $minSpecials;
2533
        // Add the rest to fill the length requirement
2534
        if ($rest > 0) {
2535
            $password .= $generator->generateString(
2536
                $rest,
2537
                $charactersLowerCase.$charactersUpperCase.$charactersSpecials
2538
            );
2539
        }
2540
    }
2541
2542
    // Min digits default 2
2543
    for ($i = 0; $i < $minNumbers; $i++) {
2544
        $password .= $generator->generateInt(2, 9);
2545
    }
2546
2547
    // Min lowercase
2548
    $password .= $generator->generateString($minLowerCase, $charactersLowerCase);
2549
2550
    // Min uppercase
2551
    $password .= $generator->generateString($minUpperCase, $charactersUpperCase);
2552
    $password = str_shuffle($password);
2553
2554
    return $password;
2555
}
2556
2557
/**
2558
 * Checks a password to see wether it is OK to use.
2559
 *
2560
 * @param string $password
2561
 *
2562
 * @return bool if the password is acceptable, false otherwise
2563
 *              Notes about what a password "OK to use" is:
2564
 *              1. The password should be at least 5 characters long.
2565
 *              2. Only English letters (uppercase or lowercase, it doesn't matter) and digits are allowed.
2566
 *              3. The password should contain at least 3 letters.
2567
 *              4. It should contain at least 2 digits.
2568
 *              Settings will change if the configuration value is set: password_requirements
2569
 */
2570
function api_check_password($password)
2571
{
2572
    $passwordRequirements = Security::getPasswordRequirements();
2573
2574
    $minLength = $passwordRequirements['min']['length'];
2575
    $minNumbers = $passwordRequirements['min']['numeric'];
2576
    // Optional
2577
    $minLowerCase = $passwordRequirements['min']['lowercase'];
2578
    $minUpperCase = $passwordRequirements['min']['uppercase'];
2579
    $minSpecials = $passwordRequirements['min']['specials'];
2580
2581
    $minLetters = $minLowerCase + $minUpperCase;
2582
    $passwordLength = api_strlen($password);
2583
2584
    $conditions = [
2585
        'min_length' => $passwordLength >= $minLength,
2586
    ];
2587
2588
    $digits = 0;
2589
    $lowerCase = 0;
2590
    $upperCase = 0;
2591
    $specials = 0;
2592
2593
    for ($i = 0; $i < $passwordLength; $i++) {
2594
        $currentCharacterCode = api_ord(api_substr($password, $i, 1));
2595
        if ($currentCharacterCode >= 65 && $currentCharacterCode <= 90) {
2596
            $upperCase++;
2597
        }
2598
2599
        if ($currentCharacterCode >= 97 && $currentCharacterCode <= 122) {
2600
            $lowerCase++;
2601
        }
2602
        if ($currentCharacterCode >= 48 && $currentCharacterCode <= 57) {
2603
            $digits++;
2604
        }
2605
2606
        if (false !== strpos(Security::CHAR_SYMBOLS, $currentCharacterCode)) {
2607
            $specials++;
2608
        }
2609
    }
2610
2611
    // Min number of digits
2612
    $conditions['min_numeric'] = $digits >= $minNumbers;
2613
2614
    if (!empty($minUpperCase)) {
2615
        // Uppercase
2616
        $conditions['min_uppercase'] = $upperCase >= $minUpperCase;
2617
    }
2618
2619
    if (!empty($minLowerCase)) {
2620
        // Lowercase
2621
        $conditions['min_lowercase'] = $lowerCase >= $minLowerCase;
2622
    }
2623
2624
    if (!empty($minSpecials)) {
2625
        $conditions['min_specials'] = $specials >= $minSpecials;
2626
    }
2627
2628
    // Min letters
2629
    $letters = $upperCase + $lowerCase;
2630
    $conditions['min_letters'] = $letters >= $minLetters;
2631
2632
    $isPasswordOk = true;
2633
    foreach ($conditions as $condition) {
2634
        if ($condition === false) {
2635
            $isPasswordOk = false;
2636
            break;
2637
        }
2638
    }
2639
2640
    if ($isPasswordOk === false) {
2641
        $output = get_lang('NewPasswordRequirementsNotMatched').'<br />';
2642
        $output .= Security::getPasswordRequirementsToString($conditions);
2643
2644
        Display::addFlash(Display::return_message($output, 'warning', false));
2645
    }
2646
2647
    return $isPasswordOk;
2648
}
2649
2650
/**
2651
 * Clears the user ID from the session if it was the anonymous user. Generally
2652
 * used on out-of-tools pages to remove a user ID that could otherwise be used
2653
 * in the wrong context.
2654
 * This function is to be used in conjunction with the api_set_anonymous()
2655
 * function to simulate the user existence in case of an anonymous visit.
2656
 *
2657
 * @param bool      database check switch - passed to api_is_anonymous()
2658
 *
2659
 * @return bool true if succesfully unregistered, false if not anonymous
2660
 */
2661
function api_clear_anonymous($db_check = false)
2662
{
2663
    global $_user;
2664
    if (isset($_user['user_id']) && api_is_anonymous($_user['user_id'], $db_check)) {
2665
        unset($_user['user_id']);
2666
        Session::erase('_uid');
2667
2668
        return true;
2669
    }
2670
2671
    return false;
2672
}
2673
2674
/**
2675
 * Returns the status string corresponding to the status code.
2676
 *
2677
 * @author Noel Dieschburg
2678
 *
2679
 * @param int $status_code The integer status code (usually in the form of a constant)
2680
 *
2681
 * @return string
2682
 */
2683
function get_status_from_code($status_code)
2684
{
2685
    switch ($status_code) {
2686
        case STUDENT:
2687
            return get_lang('Student', '');
2688
        case COURSEMANAGER:
2689
            return get_lang('Teacher', '');
2690
        case SESSIONADMIN:
2691
            return get_lang('SessionsAdmin', '');
2692
        case DRH:
2693
            return get_lang('Drh', '');
2694
        case ANONYMOUS:
2695
            return get_lang('Anonymous', '');
2696
        case PLATFORM_ADMIN:
2697
            return get_lang('Administrator', '');
2698
        case SESSION_COURSE_COACH:
2699
            return get_lang('SessionCourseCoach', '');
2700
        case SESSION_GENERAL_COACH:
2701
            return get_lang('SessionGeneralCoach', '');
2702
        case COURSE_TUTOR:
2703
            return get_lang('CourseAssistant', '');
2704
        case STUDENT_BOSS:
2705
            return get_lang('StudentBoss', '');
2706
        case INVITEE:
2707
            return get_lang('Invitee', '');
2708
    }
2709
2710
    return '';
2711
}
2712
2713
/**
2714
 * Sets the current user as anonymous if it hasn't been identified yet. This
2715
 * function should be used inside a tool only. The function api_clear_anonymous()
2716
 * acts in the opposite direction by clearing the anonymous user's data every
2717
 * time we get on a course homepage or on a neutral page (index, admin, my space).
2718
 *
2719
 * @return bool true if set user as anonymous, false if user was already logged in or anonymous id could not be found
2720
 */
2721
function api_set_anonymous()
2722
{
2723
    global $_user;
2724
2725
    if (!empty($_user['user_id'])) {
2726
        return false;
2727
    }
2728
2729
    $user_id = api_get_anonymous_id();
2730
    if ($user_id == 0) {
2731
        return false;
2732
    }
2733
2734
    if (isset($_user['is_anonymous'])) {
2735
        return false;
2736
    }
2737
2738
    Session::erase('_user');
2739
    $_user['user_id'] = $user_id;
2740
    $_user['is_anonymous'] = true;
2741
    $GLOBALS['_user'] = $_user;
2742
    Session::write('_user', $_user);
2743
2744
    return true;
2745
}
2746
2747
/**
2748
 * Gets the current Chamilo (not PHP/cookie) session ID.
2749
 *
2750
 * @return int O if no active session, the session ID otherwise
2751
 */
2752
function api_get_session_id()
2753
{
2754
    return (int) Session::read('id_session', 0);
2755
}
2756
2757
/**
2758
 * Gets the current Chamilo (not social network) group ID.
2759
 *
2760
 * @return int O if no active group, the group id otherwise
2761
 */
2762
function api_get_group_id()
2763
{
2764
    return (int) Session::read('_gid', 0);
2765
}
2766
2767
/**
2768
 * Gets the current or given session name.
2769
 *
2770
 * @param   int     Session ID (optional)
2771
 *
2772
 * @return string The session name, or null if not found
2773
 */
2774
function api_get_session_name($session_id = 0)
2775
{
2776
    if (empty($session_id)) {
2777
        $session_id = api_get_session_id();
2778
        if (empty($session_id)) {
2779
            return null;
2780
        }
2781
    }
2782
    $t = Database::get_main_table(TABLE_MAIN_SESSION);
2783
    $s = "SELECT name FROM $t WHERE id = ".(int) $session_id;
2784
    $r = Database::query($s);
2785
    $c = Database::num_rows($r);
2786
    if ($c > 0) {
2787
        //technically, there can be only one, but anyway we take the first
2788
        $rec = Database::fetch_array($r);
2789
2790
        return $rec['name'];
2791
    }
2792
2793
    return null;
2794
}
2795
2796
/**
2797
 * Gets the session info by id.
2798
 *
2799
 * @param int $id Session ID
2800
 *
2801
 * @return array information of the session
2802
 */
2803
function api_get_session_info($id)
2804
{
2805
    return SessionManager::fetch($id);
2806
}
2807
2808
/**
2809
 * Gets the session visibility by session id.
2810
 *
2811
 * @param int  $session_id
2812
 * @param int  $courseId
2813
 * @param bool $ignore_visibility_for_admins
2814
 * @param int  $userId
2815
 *
2816
 * @return int
2817
 *             0 = session still available,
2818
 *             SESSION_VISIBLE_READ_ONLY = 1,
2819
 *             SESSION_VISIBLE = 2,
2820
 *             SESSION_INVISIBLE = 3
2821
 */
2822
function api_get_session_visibility(
2823
    $session_id,
2824
    $courseId = null,
2825
    $ignore_visibility_for_admins = true,
2826
    $userId = 0
2827
) {
2828
    if (api_is_platform_admin()) {
2829
        if ($ignore_visibility_for_admins) {
2830
            return SESSION_AVAILABLE;
2831
        }
2832
    }
2833
2834
    $userId = empty($userId) ? api_get_user_id() : (int) $userId;
2835
2836
    $now = time();
2837
    if (empty($session_id)) {
2838
        return 0; // Means that the session is still available.
2839
    }
2840
2841
    $session_id = (int) $session_id;
2842
    $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
2843
2844
    $result = Database::query("SELECT * FROM $tbl_session WHERE id = $session_id");
2845
2846
    if (Database::num_rows($result) <= 0) {
2847
        return SESSION_INVISIBLE;
2848
    }
2849
2850
    $row = Database::fetch_array($result, 'ASSOC');
2851
    $visibility = $row['visibility'];
2852
2853
    // I don't care the session visibility.
2854
    if (empty($row['access_start_date']) && empty($row['access_end_date'])) {
2855
2856
        // Session duration per student.
2857
        if (isset($row['duration']) && !empty($row['duration'])) {
2858
            if (api_get_configuration_value('session_coach_access_after_duration_end') == true && api_is_teacher()) {
2859
                return SESSION_AVAILABLE;
2860
            }
2861
2862
            $duration = $row['duration'] * 24 * 60 * 60;
2863
            $courseAccess = CourseManager::getFirstCourseAccessPerSessionAndUser($session_id, $userId);
2864
2865
            // If there is a session duration but there is no previous
2866
            // access by the user, then the session is still available
2867
            if (0 == count($courseAccess)) {
2868
                return SESSION_AVAILABLE;
2869
            }
2870
2871
            $currentTime = time();
2872
            $firstAccess = isset($courseAccess['login_course_date'])
2873
                ? api_strtotime($courseAccess['login_course_date'], 'UTC')
2874
                : 0;
2875
            $userDurationData = SessionManager::getUserSession($userId, $session_id);
2876
            $userDuration = isset($userDurationData['duration'])
2877
                ? (intval($userDurationData['duration']) * 24 * 60 * 60)
2878
                : 0;
2879
2880
            $totalDuration = $firstAccess + $duration + $userDuration;
2881
2882
            return $totalDuration > $currentTime ? SESSION_AVAILABLE : SESSION_VISIBLE_READ_ONLY;
2883
        }
2884
2885
        return SESSION_AVAILABLE;
2886
    }
2887
2888
    // If start date was set.
2889
    if (!empty($row['access_start_date'])) {
2890
        $visibility = $now > api_strtotime($row['access_start_date'], 'UTC') ? SESSION_AVAILABLE : SESSION_INVISIBLE;
2891
    }
2892
2893
    // If the end date was set.
2894
    if (!empty($row['access_end_date'])) {
2895
        // Only if date_start said that it was ok
2896
        if ($visibility === SESSION_AVAILABLE) {
2897
            $visibility = $now < api_strtotime($row['access_end_date'], 'UTC')
2898
                ? SESSION_AVAILABLE // Date still available
2899
                : $row['visibility']; // Session ends
2900
        }
2901
    }
2902
2903
    // If I'm a coach the visibility can change in my favor depending in the coach dates.
2904
    $isCoach = api_is_coach($session_id, $courseId, $userId);
2905
2906
    if ($isCoach) {
2907
        // Test start date.
2908
        if (!empty($row['coach_access_start_date'])) {
2909
            $start = api_strtotime($row['coach_access_start_date'], 'UTC');
2910
            $visibility = $start < $now ? SESSION_AVAILABLE : SESSION_INVISIBLE;
2911
        }
2912
2913
        // Test end date.
2914
        if (!empty($row['coach_access_end_date'])) {
2915
            if ($visibility === SESSION_AVAILABLE) {
2916
                $endDateCoach = api_strtotime($row['coach_access_end_date'], 'UTC');
2917
                $visibility = $endDateCoach >= $now ? SESSION_AVAILABLE : $row['visibility'];
2918
            }
2919
        }
2920
    }
2921
2922
    return $visibility;
2923
}
2924
2925
/**
2926
 * This function returns a (star) session icon if the session is not null and
2927
 * the user is not a student.
2928
 *
2929
 * @param int $sessionId
2930
 * @param int $statusId  User status id - if 5 (student), will return empty
2931
 *
2932
 * @return string Session icon
2933
 */
2934
function api_get_session_image($sessionId, $statusId)
2935
{
2936
    $sessionId = (int) $sessionId;
2937
    $image = '';
2938
    if ($statusId != STUDENT) {
2939
        // Check whether is not a student
2940
        if ($sessionId > 0) {
2941
            $image = '&nbsp;&nbsp;'.Display::return_icon(
2942
                'star.png',
2943
                get_lang('SessionSpecificResource'),
2944
                ['align' => 'absmiddle'],
2945
                ICON_SIZE_SMALL
2946
            );
2947
        }
2948
    }
2949
2950
    return $image;
2951
}
2952
2953
/**
2954
 * This function add an additional condition according to the session of the course.
2955
 *
2956
 * @param int    $session_id        session id
2957
 * @param bool   $and               optional, true if more than one condition false if the only condition in the query
2958
 * @param bool   $with_base_content optional, true to accept content with session=0 as well,
2959
 *                                  false for strict session condition
2960
 * @param string $session_field
2961
 *
2962
 * @return string condition of the session
2963
 */
2964
function api_get_session_condition(
2965
    $session_id,
2966
    $and = true,
2967
    $with_base_content = false,
2968
    $session_field = 'session_id'
2969
) {
2970
    $session_id = (int) $session_id;
2971
2972
    if (empty($session_field)) {
2973
        $session_field = 'session_id';
2974
    }
2975
    // Condition to show resources by session
2976
    $condition_add = $and ? ' AND ' : ' WHERE ';
2977
2978
    if ($with_base_content) {
2979
        $condition_session = $condition_add." ( $session_field = $session_id OR $session_field = 0 OR $session_field IS NULL) ";
2980
    } else {
2981
        if (empty($session_id)) {
2982
            $condition_session = $condition_add." ($session_field = $session_id OR $session_field IS NULL)";
2983
        } else {
2984
            $condition_session = $condition_add." $session_field = $session_id ";
2985
        }
2986
    }
2987
2988
    return $condition_session;
2989
}
2990
2991
/**
2992
 * Returns the value of a setting from the web-adjustable admin config settings.
2993
 *
2994
 * WARNING true/false are stored as string, so when comparing you need to check e.g.
2995
 * if (api_get_setting('show_navigation_menu') == 'true') //CORRECT
2996
 * instead of
2997
 * if (api_get_setting('show_navigation_menu') == true) //INCORRECT
2998
 *
2999
 * @param string $variable The variable name
3000
 * @param string $key      The subkey (sub-variable) if any. Defaults to NULL
3001
 *
3002
 * @return string
3003
 *
3004
 * @author René Haentjens
3005
 * @author Bart Mollet
3006
 */
3007
function api_get_setting($variable, $key = null)
3008
{
3009
    global $_setting;
3010
    if ($variable == 'header_extra_content') {
3011
        $filename = api_get_home_path().'header_extra_content.txt';
3012
        if (file_exists($filename)) {
3013
            $value = file_get_contents($filename);
3014
3015
            return $value;
3016
        } else {
3017
            return '';
3018
        }
3019
    }
3020
    if ($variable == 'footer_extra_content') {
3021
        $filename = api_get_home_path().'footer_extra_content.txt';
3022
        if (file_exists($filename)) {
3023
            $value = file_get_contents($filename);
3024
3025
            return $value;
3026
        } else {
3027
            return '';
3028
        }
3029
    }
3030
    $value = null;
3031
    if (is_null($key)) {
3032
        $value = ((isset($_setting[$variable]) && $_setting[$variable] != '') ? $_setting[$variable] : null);
3033
    } else {
3034
        if (isset($_setting[$variable][$key])) {
3035
            $value = $_setting[$variable][$key];
3036
        }
3037
    }
3038
3039
    return $value;
3040
}
3041
3042
/**
3043
 * @param string $plugin
3044
 * @param string $variable
3045
 *
3046
 * @return string
3047
 */
3048
function api_get_plugin_setting($plugin, $variable)
3049
{
3050
    $variableName = $plugin.'_'.$variable;
3051
    $result = api_get_setting($variableName);
3052
3053
    if (isset($result[$plugin])) {
3054
        $value = $result[$plugin];
3055
        $unSerialized = UnserializeApi::unserialize('not_allowed_classes', $value, true);
3056
3057
        if (false !== $unSerialized) {
3058
            $value = $unSerialized;
3059
        }
3060
3061
        return $value;
3062
    }
3063
3064
    return null;
3065
}
3066
3067
/**
3068
 * Returns the value of a setting from the web-adjustable admin config settings.
3069
 */
3070
function api_get_settings_params($params)
3071
{
3072
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
3073
3074
    return Database::select('*', $table, ['where' => $params]);
3075
}
3076
3077
/**
3078
 * @param array $params example: [id = ? => '1']
3079
 *
3080
 * @return array
3081
 */
3082
function api_get_settings_params_simple($params)
3083
{
3084
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
3085
3086
    return Database::select('*', $table, ['where' => $params], 'one');
3087
}
3088
3089
/**
3090
 * Returns the value of a setting from the web-adjustable admin config settings.
3091
 */
3092
function api_delete_settings_params($params)
3093
{
3094
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
3095
    $result = Database::delete($table, $params);
3096
3097
    return $result;
3098
}
3099
3100
/**
3101
 * Returns an escaped version of $_SERVER['PHP_SELF'] to avoid XSS injection.
3102
 *
3103
 * @return string Escaped version of $_SERVER['PHP_SELF']
3104
 */
3105
function api_get_self()
3106
{
3107
    return htmlentities($_SERVER['PHP_SELF']);
3108
}
3109
3110
/* USER PERMISSIONS */
3111
3112
/**
3113
 * Checks whether current user is a platform administrator.
3114
 *
3115
 * @param bool $allowSessionAdmins Whether session admins should be considered admins or not
3116
 * @param bool $allowDrh           Whether HR directors should be considered admins or not
3117
 *
3118
 * @return bool true if the user has platform admin rights,
3119
 *              false otherwise
3120
 *
3121
 * @see usermanager::is_admin(user_id) for a user-id specific function
3122
 */
3123
function api_is_platform_admin($allowSessionAdmins = false, $allowDrh = false)
3124
{
3125
    $isAdmin = Session::read('is_platformAdmin');
3126
    if ($isAdmin) {
3127
        return true;
3128
    }
3129
    $user = api_get_user_info();
3130
3131
    return
3132
        isset($user['status']) &&
3133
        (
3134
            ($allowSessionAdmins && $user['status'] == SESSIONADMIN) ||
3135
            ($allowDrh && $user['status'] == DRH)
3136
        );
3137
}
3138
3139
/**
3140
 * Checks whether the user given as user id is in the admin table.
3141
 *
3142
 * @param int $user_id If none provided, will use current user
3143
 * @param int $url     URL ID. If provided, also check if the user is active on given URL
3144
 *
3145
 * @return bool True if the user is admin, false otherwise
3146
 */
3147
function api_is_platform_admin_by_id($user_id = null, $url = null)
3148
{
3149
    $user_id = (int) $user_id;
3150
    if (empty($user_id)) {
3151
        $user_id = api_get_user_id();
3152
    }
3153
    $admin_table = Database::get_main_table(TABLE_MAIN_ADMIN);
3154
    $sql = "SELECT * FROM $admin_table WHERE user_id = $user_id";
3155
    $res = Database::query($sql);
3156
    $is_admin = Database::num_rows($res) === 1;
3157
    if (!$is_admin || !isset($url)) {
3158
        return $is_admin;
3159
    }
3160
    // We get here only if $url is set
3161
    $url = (int) $url;
3162
    $url_user_table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
3163
    $sql = "SELECT * FROM $url_user_table
3164
            WHERE access_url_id = $url AND user_id = $user_id";
3165
    $res = Database::query($sql);
3166
    $result = Database::num_rows($res) === 1;
3167
3168
    return $result;
3169
}
3170
3171
/**
3172
 * Returns the user's numeric status ID from the users table.
3173
 *
3174
 * @param int $user_id If none provided, will use current user
3175
 *
3176
 * @return int User's status (1 for teacher, 5 for student, etc)
3177
 */
3178
function api_get_user_status($user_id = null)
3179
{
3180
    $user_id = (int) $user_id;
3181
    if (empty($user_id)) {
3182
        $user_id = api_get_user_id();
3183
    }
3184
    $table = Database::get_main_table(TABLE_MAIN_USER);
3185
    $sql = "SELECT status FROM $table WHERE user_id = $user_id ";
3186
    $result = Database::query($sql);
3187
    $status = null;
3188
    if (Database::num_rows($result)) {
3189
        $row = Database::fetch_array($result);
3190
        $status = $row['status'];
3191
    }
3192
3193
    return $status;
3194
}
3195
3196
/**
3197
 * Checks whether current user is allowed to create courses.
3198
 *
3199
 * @return bool true if the user has course creation rights,
3200
 *              false otherwise
3201
 */
3202
function api_is_allowed_to_create_course()
3203
{
3204
    if (api_is_platform_admin()) {
3205
        return true;
3206
    }
3207
3208
    // Teachers can only create courses
3209
    if (api_is_teacher()) {
3210
        if (api_get_setting('allow_users_to_create_courses') === 'true') {
3211
            return true;
3212
        } else {
3213
            return false;
3214
        }
3215
    }
3216
3217
    return Session::read('is_allowedCreateCourse');
3218
}
3219
3220
/**
3221
 * Checks whether the current user is a course administrator.
3222
 *
3223
 * @return bool True if current user is a course administrator
3224
 */
3225
function api_is_course_admin()
3226
{
3227
    if (api_is_platform_admin()) {
3228
        return true;
3229
    }
3230
3231
    return Session::read('is_courseAdmin');
3232
}
3233
3234
/**
3235
 * Checks whether the current user is a course coach
3236
 * Based on the presence of user in session.id_coach (session general coach).
3237
 *
3238
 * @return bool True if current user is a course coach
3239
 */
3240
function api_is_session_general_coach()
3241
{
3242
    return Session::read('is_session_general_coach');
3243
}
3244
3245
/**
3246
 * Checks whether the current user is a course tutor
3247
 * Based on the presence of user in session_rel_course_rel_user.user_id with status = 2.
3248
 *
3249
 * @return bool True if current user is a course tutor
3250
 */
3251
function api_is_course_tutor()
3252
{
3253
    return Session::read('is_courseTutor');
3254
}
3255
3256
/**
3257
 * @param int $user_id
3258
 * @param int $courseId
3259
 * @param int $session_id
3260
 *
3261
 * @return bool
3262
 */
3263
function api_is_course_session_coach($user_id, $courseId, $session_id)
3264
{
3265
    $session_table = Database::get_main_table(TABLE_MAIN_SESSION);
3266
    $session_rel_course_rel_user_table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3267
3268
    $user_id = (int) $user_id;
3269
    $session_id = (int) $session_id;
3270
    $courseId = (int) $courseId;
3271
3272
    $sql = "SELECT DISTINCT session.id
3273
            FROM $session_table
3274
            INNER JOIN $session_rel_course_rel_user_table session_rc_ru
3275
            ON session.id = session_rc_ru.session_id
3276
            WHERE
3277
                session_rc_ru.user_id = '".$user_id."'  AND
3278
                session_rc_ru.c_id = '$courseId' AND
3279
                session_rc_ru.status = 2 AND
3280
                session_rc_ru.session_id = '$session_id'";
3281
    $result = Database::query($sql);
3282
3283
    return Database::num_rows($result) > 0;
3284
}
3285
3286
/**
3287
 * Checks whether the current user is a course or session coach.
3288
 *
3289
 * @param int $session_id
3290
 * @param int $courseId
3291
 * @param bool  Check whether we are in student view and, if we are, return false
3292
 * @param int $userId
3293
 *
3294
 * @return bool True if current user is a course or session coach
3295
 */
3296
function api_is_coach($session_id = 0, $courseId = null, $check_student_view = true, $userId = 0)
3297
{
3298
    $userId = empty($userId) ? api_get_user_id() : (int) $userId;
3299
3300
    if (!empty($session_id)) {
3301
        $session_id = (int) $session_id;
3302
    } else {
3303
        $session_id = api_get_session_id();
3304
    }
3305
3306
    // The student preview was on
3307
    if ($check_student_view && api_is_student_view_active()) {
3308
        return false;
3309
    }
3310
3311
    if (!empty($courseId)) {
3312
        $courseId = (int) $courseId;
3313
    } else {
3314
        $courseId = api_get_course_int_id();
3315
    }
3316
3317
    $session_table = Database::get_main_table(TABLE_MAIN_SESSION);
3318
    $session_rel_course_rel_user_table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3319
    $sessionIsCoach = [];
3320
3321
    if (!empty($courseId)) {
3322
        $sql = "SELECT DISTINCT s.id, name, access_start_date, access_end_date
3323
                FROM $session_table s
3324
                INNER JOIN $session_rel_course_rel_user_table session_rc_ru
3325
                ON session_rc_ru.session_id = s.id AND session_rc_ru.user_id = '".$userId."'
3326
                WHERE
3327
                    session_rc_ru.c_id = '$courseId' AND
3328
                    session_rc_ru.status = 2 AND
3329
                    session_rc_ru.session_id = '$session_id'";
3330
        $result = Database::query($sql);
3331
        $sessionIsCoach = Database::store_result($result);
3332
    }
3333
3334
    if (!empty($session_id)) {
3335
        $sql = "SELECT DISTINCT id, name, access_start_date, access_end_date
3336
                FROM $session_table
3337
                WHERE session.id_coach = $userId AND id = $session_id
3338
                ORDER BY access_start_date, access_end_date, name";
3339
        $result = Database::query($sql);
3340
        if (!empty($sessionIsCoach)) {
3341
            $sessionIsCoach = array_merge(
3342
                $sessionIsCoach,
3343
                Database::store_result($result)
3344
            );
3345
        } else {
3346
            $sessionIsCoach = Database::store_result($result);
3347
        }
3348
    }
3349
3350
    return count($sessionIsCoach) > 0;
3351
}
3352
3353
/**
3354
 * Checks whether the current user is a session administrator.
3355
 *
3356
 * @return bool True if current user is a course administrator
3357
 */
3358
function api_is_session_admin()
3359
{
3360
    $user = api_get_user_info();
3361
3362
    return isset($user['status']) && $user['status'] == SESSIONADMIN;
3363
}
3364
3365
/**
3366
 * Checks whether the current user is a human resources manager.
3367
 *
3368
 * @return bool True if current user is a human resources manager
3369
 */
3370
function api_is_drh()
3371
{
3372
    $user = api_get_user_info();
3373
3374
    return isset($user['status']) && $user['status'] == DRH;
3375
}
3376
3377
/**
3378
 * Checks whether the current user is a student.
3379
 *
3380
 * @return bool True if current user is a human resources manager
3381
 */
3382
function api_is_student()
3383
{
3384
    $user = api_get_user_info();
3385
3386
    return isset($user['status']) && $user['status'] == STUDENT;
3387
}
3388
3389
/**
3390
 * Checks whether the current user has the status 'teacher'.
3391
 *
3392
 * @return bool True if current user is a human resources manager
3393
 */
3394
function api_is_teacher()
3395
{
3396
    $user = api_get_user_info();
3397
3398
    return isset($user['status']) && $user['status'] == COURSEMANAGER;
3399
}
3400
3401
/**
3402
 * Checks whether the current user is a invited user.
3403
 *
3404
 * @return bool
3405
 */
3406
function api_is_invitee()
3407
{
3408
    $user = api_get_user_info();
3409
3410
    return isset($user['status']) && $user['status'] == INVITEE;
3411
}
3412
3413
/**
3414
 * This function checks whether a session is assigned into a category.
3415
 *
3416
 * @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...
3417
 * @param string    - category name
3418
 *
3419
 * @return bool - true if is found, otherwise false
3420
 */
3421
function api_is_session_in_category($session_id, $category_name)
3422
{
3423
    $session_id = (int) $session_id;
3424
    $category_name = Database::escape_string($category_name);
3425
    $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
3426
    $tbl_session_category = Database::get_main_table(TABLE_MAIN_SESSION_CATEGORY);
3427
3428
    $sql = "SELECT 1
3429
            FROM $tbl_session
3430
            WHERE $session_id IN (
3431
                SELECT s.id FROM $tbl_session s, $tbl_session_category sc
3432
                WHERE
3433
                  s.session_category_id = sc.id AND
3434
                  sc.name LIKE '%$category_name'
3435
            )";
3436
    $rs = Database::query($sql);
3437
3438
    if (Database::num_rows($rs) > 0) {
3439
        return true;
3440
    } else {
3441
        return false;
3442
    }
3443
}
3444
3445
/**
3446
 * Displays the title of a tool.
3447
 * Normal use: parameter is a string:
3448
 * api_display_tool_title("My Tool").
3449
 *
3450
 * Optionally, there can be a subtitle below
3451
 * the normal title, and / or a supra title above the normal title.
3452
 *
3453
 * e.g. supra title:
3454
 * group
3455
 * GROUP PROPERTIES
3456
 *
3457
 * e.g. subtitle:
3458
 * AGENDA
3459
 * calender & events tool
3460
 *
3461
 * @author Hugues Peeters <[email protected]>
3462
 *
3463
 * @param mixed $title_element - it could either be a string or an array
3464
 *                             containing 'supraTitle', 'mainTitle',
3465
 *                             'subTitle'
3466
 */
3467
function api_display_tool_title($title_element)
3468
{
3469
    if (is_string($title_element)) {
3470
        $tit = $title_element;
3471
        unset($title_element);
3472
        $title_element = [];
3473
        $title_element['mainTitle'] = $tit;
3474
    }
3475
    echo '<h3>';
3476
    if (!empty($title_element['supraTitle'])) {
3477
        echo '<small>'.$title_element['supraTitle'].'</small><br />';
3478
    }
3479
    if (!empty($title_element['mainTitle'])) {
3480
        echo $title_element['mainTitle'];
3481
    }
3482
    if (!empty($title_element['subTitle'])) {
3483
        echo '<br /><small>'.$title_element['subTitle'].'</small>';
3484
    }
3485
    echo '</h3>';
3486
}
3487
3488
/**
3489
 * Displays options for switching between student view and course manager view.
3490
 *
3491
 * Changes in version 1.2 (Patrick Cool)
3492
 * Student view switch now behaves as a real switch. It maintains its current state until the state
3493
 * is changed explicitly
3494
 *
3495
 * Changes in version 1.1 (Patrick Cool)
3496
 * student view now works correctly in subfolders of the document tool
3497
 * student view works correctly in the new links tool
3498
 *
3499
 * Example code for using this in your tools:
3500
 * //if ($is_courseAdmin && api_get_setting('student_view_enabled') == 'true') {
3501
 * //   display_tool_view_option($isStudentView);
3502
 * //}
3503
 * //and in later sections, use api_is_allowed_to_edit()
3504
 *
3505
 * @author Roan Embrechts
3506
 * @author Patrick Cool
3507
 * @author Julio Montoya, changes added in Chamilo
3508
 *
3509
 * @version 1.2
3510
 *
3511
 * @todo rewrite code so it is easier to understand
3512
 */
3513
function api_display_tool_view_option()
3514
{
3515
    if (api_get_setting('student_view_enabled') != 'true') {
3516
        return '';
3517
    }
3518
3519
    $sourceurl = '';
3520
    $is_framed = false;
3521
    // Exceptions apply for all multi-frames pages
3522
    if (strpos($_SERVER['REQUEST_URI'], 'chat/chat_banner.php') !== false) {
3523
        // The chat is a multiframe bit that doesn't work too well with the student_view, so do not show the link
3524
        return '';
3525
    }
3526
3527
    // Uncomment to remove student view link from document view page
3528
    if (strpos($_SERVER['REQUEST_URI'], 'lp/lp_header.php') !== false) {
3529
        if (empty($_GET['lp_id'])) {
3530
            return '';
3531
        }
3532
        $sourceurl = substr($_SERVER['REQUEST_URI'], 0, strpos($_SERVER['REQUEST_URI'], '?'));
3533
        $sourceurl = str_replace(
3534
            'lp/lp_header.php',
3535
            'lp/lp_controller.php?'.api_get_cidreq().'&action=view&lp_id='.intval($_GET['lp_id']).'&isStudentView='.($_SESSION['studentview'] == 'studentview' ? 'false' : 'true'),
3536
            $sourceurl
3537
        );
3538
        //showinframes doesn't handle student view anyway...
3539
        //return '';
3540
        $is_framed = true;
3541
    }
3542
3543
    // Check whether the $_SERVER['REQUEST_URI'] contains already url parameters (thus a questionmark)
3544
    if (!$is_framed) {
3545
        if (strpos($_SERVER['REQUEST_URI'], '?') === false) {
3546
            $sourceurl = api_get_self().'?'.api_get_cidreq();
3547
        } else {
3548
            $sourceurl = $_SERVER['REQUEST_URI'];
3549
        }
3550
    }
3551
3552
    $output_string = '';
3553
    if (!empty($_SESSION['studentview'])) {
3554
        if ($_SESSION['studentview'] == 'studentview') {
3555
            // We have to remove the isStudentView=true from the $sourceurl
3556
            $sourceurl = str_replace('&isStudentView=true', '', $sourceurl);
3557
            $sourceurl = str_replace('&isStudentView=false', '', $sourceurl);
3558
            $output_string .= '<a class="btn btn-primary btn-sm" href="'.$sourceurl.'&isStudentView=false" target="_self">'.
3559
                Display::returnFontAwesomeIcon('eye').' '.get_lang('SwitchToTeacherView').'</a>';
3560
        } elseif ($_SESSION['studentview'] == 'teacherview') {
3561
            // Switching to teacherview
3562
            $sourceurl = str_replace('&isStudentView=true', '', $sourceurl);
3563
            $sourceurl = str_replace('&isStudentView=false', '', $sourceurl);
3564
            $output_string .= '<a class="btn btn-default btn-sm" href="'.$sourceurl.'&isStudentView=true" target="_self">'.
3565
                Display::returnFontAwesomeIcon('eye').' '.get_lang('SwitchToStudentView').'</a>';
3566
        }
3567
    } else {
3568
        $output_string .= '<a class="btn btn-default btn-sm" href="'.$sourceurl.'&isStudentView=true" target="_self">'.
3569
            Display::returnFontAwesomeIcon('eye').' '.get_lang('SwitchToStudentView').'</a>';
3570
    }
3571
    $output_string = Security::remove_XSS($output_string);
3572
    $html = Display::tag('div', $output_string, ['class' => 'view-options']);
3573
3574
    return $html;
3575
}
3576
3577
// TODO: This is for the permission section.
3578
/**
3579
 * Function that removes the need to directly use is_courseAdmin global in
3580
 * tool scripts. It returns true or false depending on the user's rights in
3581
 * this particular course.
3582
 * Optionally checking for tutor and coach roles here allows us to use the
3583
 * student_view feature altogether with these roles as well.
3584
 *
3585
 * @param bool  Whether to check if the user has the tutor role
3586
 * @param bool  Whether to check if the user has the coach role
3587
 * @param bool  Whether to check if the user has the session coach role
3588
 * @param bool  check the student view or not
3589
 *
3590
 * @author Roan Embrechts
3591
 * @author Patrick Cool
3592
 * @author Julio Montoya
3593
 *
3594
 * @version 1.1, February 2004
3595
 *
3596
 * @return bool true: the user has the rights to edit, false: he does not
3597
 */
3598
function api_is_allowed_to_edit(
3599
    $tutor = false,
3600
    $coach = false,
3601
    $session_coach = false,
3602
    $check_student_view = true
3603
) {
3604
    $allowSessionAdminEdit = api_get_configuration_value('session_admins_edit_courses_content') === true;
3605
3606
    // Admins can edit anything.
3607
    if (api_is_platform_admin($allowSessionAdminEdit)) {
3608
        //The student preview was on
3609
        if ($check_student_view && api_is_student_view_active()) {
3610
            return false;
3611
        }
3612
3613
        return true;
3614
    }
3615
3616
    $sessionId = api_get_session_id();
3617
3618
    if ($sessionId && api_get_configuration_value('session_courses_read_only_mode')) {
3619
        $efv = new ExtraFieldValue('course');
3620
        $lockExrafieldField = $efv->get_values_by_handler_and_field_variable(
3621
            api_get_course_int_id(),
3622
            'session_courses_read_only_mode'
3623
        );
3624
3625
        if (!empty($lockExrafieldField['value'])) {
3626
            return false;
3627
        }
3628
    }
3629
3630
    $is_allowed_coach_to_edit = api_is_coach(null, null, $check_student_view);
3631
    $session_visibility = api_get_session_visibility($sessionId);
3632
    $is_courseAdmin = api_is_course_admin();
3633
3634
    if (!$is_courseAdmin && $tutor) {
3635
        // If we also want to check if the user is a tutor...
3636
        $is_courseAdmin = $is_courseAdmin || api_is_course_tutor();
3637
    }
3638
3639
    if (!$is_courseAdmin && $coach) {
3640
        // If we also want to check if the user is a coach...';
3641
        // Check if session visibility is read only for coaches.
3642
        if ($session_visibility == SESSION_VISIBLE_READ_ONLY) {
3643
            $is_allowed_coach_to_edit = false;
3644
        }
3645
3646
        if (api_get_setting('allow_coach_to_edit_course_session') == 'true') {
3647
            // Check if coach is allowed to edit a course.
3648
            $is_courseAdmin = $is_courseAdmin || $is_allowed_coach_to_edit;
3649
        }
3650
    }
3651
3652
    if (!$is_courseAdmin && $session_coach) {
3653
        $is_courseAdmin = $is_courseAdmin || $is_allowed_coach_to_edit;
3654
    }
3655
3656
    // Check if the student_view is enabled, and if so, if it is activated.
3657
    if (api_get_setting('student_view_enabled') == 'true') {
3658
        if (!empty($sessionId)) {
3659
            // Check if session visibility is read only for coaches.
3660
            if ($session_visibility == SESSION_VISIBLE_READ_ONLY) {
3661
                $is_allowed_coach_to_edit = false;
3662
            }
3663
3664
            if (api_get_setting('allow_coach_to_edit_course_session') == 'true') {
3665
                // Check if coach is allowed to edit a course.
3666
                $is_allowed = $is_allowed_coach_to_edit;
3667
            } else {
3668
                $is_allowed = false;
3669
            }
3670
            if ($check_student_view) {
3671
                $is_allowed = $is_allowed && $_SESSION['studentview'] != 'studentview';
3672
            }
3673
        } else {
3674
            if ($check_student_view) {
3675
                $is_allowed = $is_courseAdmin && $_SESSION['studentview'] != 'studentview';
3676
            } else {
3677
                $is_allowed = $is_courseAdmin;
3678
            }
3679
        }
3680
3681
        return $is_allowed;
3682
    } else {
3683
        return $is_courseAdmin;
3684
    }
3685
}
3686
3687
/**
3688
 * Returns true if user is a course coach of at least one course in session.
3689
 *
3690
 * @param int $sessionId
3691
 *
3692
 * @return bool
3693
 */
3694
function api_is_coach_of_course_in_session($sessionId)
3695
{
3696
    if (api_is_platform_admin()) {
3697
        return true;
3698
    }
3699
3700
    $userId = api_get_user_id();
3701
    $courseList = UserManager::get_courses_list_by_session(
3702
        $userId,
3703
        $sessionId
3704
    );
3705
3706
    // Session visibility.
3707
    $visibility = api_get_session_visibility(
3708
        $sessionId,
3709
        null,
3710
        false
3711
    );
3712
3713
    if ($visibility != SESSION_VISIBLE && !empty($courseList)) {
3714
        // Course Coach session visibility.
3715
        $blockedCourseCount = 0;
3716
        $closedVisibilityList = [
3717
            COURSE_VISIBILITY_CLOSED,
3718
            COURSE_VISIBILITY_HIDDEN,
3719
        ];
3720
3721
        foreach ($courseList as $course) {
3722
            // Checking session visibility
3723
            $sessionCourseVisibility = api_get_session_visibility(
3724
                $sessionId,
3725
                $course['real_id']
3726
            );
3727
3728
            $courseIsVisible = !in_array(
3729
                $course['visibility'],
3730
                $closedVisibilityList
3731
            );
3732
            if ($courseIsVisible === false || $sessionCourseVisibility == SESSION_INVISIBLE) {
3733
                $blockedCourseCount++;
3734
            }
3735
        }
3736
3737
        // If all courses are blocked then no show in the list.
3738
        if ($blockedCourseCount === count($courseList)) {
3739
            $visibility = SESSION_INVISIBLE;
3740
        } else {
3741
            $visibility = SESSION_VISIBLE;
3742
        }
3743
    }
3744
3745
    switch ($visibility) {
3746
        case SESSION_VISIBLE_READ_ONLY:
3747
        case SESSION_VISIBLE:
3748
        case SESSION_AVAILABLE:
3749
            return true;
3750
            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...
3751
        case SESSION_INVISIBLE:
3752
            return false;
3753
    }
3754
3755
    return false;
3756
}
3757
3758
/**
3759
 * Checks if a student can edit contents in a session depending
3760
 * on the session visibility.
3761
 *
3762
 * @param bool $tutor Whether to check if the user has the tutor role
3763
 * @param bool $coach Whether to check if the user has the coach role
3764
 *
3765
 * @return bool true: the user has the rights to edit, false: he does not
3766
 */
3767
function api_is_allowed_to_session_edit($tutor = false, $coach = false)
3768
{
3769
    if (api_is_allowed_to_edit($tutor, $coach)) {
3770
        // If I'm a teacher, I will return true in order to not affect the normal behaviour of Chamilo tools.
3771
        return true;
3772
    } else {
3773
        $sessionId = api_get_session_id();
3774
3775
        if (0 == $sessionId) {
3776
            // I'm not in a session so i will return true to not affect the normal behaviour of Chamilo tools.
3777
            return true;
3778
        } else {
3779
            // I'm in a session and I'm a student
3780
            // Get the session visibility
3781
            $session_visibility = api_get_session_visibility($sessionId);
3782
            // if 5 the session is still available
3783
            switch ($session_visibility) {
3784
                case SESSION_VISIBLE_READ_ONLY: // 1
3785
                    return false;
3786
                case SESSION_VISIBLE:           // 2
3787
                    return true;
3788
                case SESSION_INVISIBLE:         // 3
3789
                    return false;
3790
                case SESSION_AVAILABLE:         //5
3791
                    return true;
3792
            }
3793
        }
3794
    }
3795
3796
    return false;
3797
}
3798
3799
/**
3800
 * Checks whether the user is allowed in a specific tool for a specific action.
3801
 *
3802
 * @param string $tool   the tool we are checking if the user has a certain permission
3803
 * @param string $action the action we are checking (add, edit, delete, move, visibility)
3804
 *
3805
 * @return bool
3806
 *
3807
 * @author Patrick Cool <[email protected]>, Ghent University
3808
 * @author Julio Montoya
3809
 *
3810
 * @version 1.0
3811
 */
3812
function api_is_allowed($tool, $action, $task_id = 0)
3813
{
3814
    $_user = api_get_user_info();
3815
    $_course = api_get_course_info();
3816
3817
    if (api_is_course_admin()) {
3818
        return true;
3819
    }
3820
3821
    if (is_array($_course) and count($_course) > 0) {
3822
        require_once __DIR__.'/../../permissions/permissions_functions.inc.php';
3823
3824
        // Getting the permissions of this user.
3825
        if ($task_id == 0) {
3826
            $user_permissions = get_permissions('user', $_user['user_id']);
3827
            $_SESSION['total_permissions'][$_course['code']] = $user_permissions;
3828
        }
3829
3830
        // Getting the permissions of the task.
3831
        if ($task_id != 0) {
3832
            $task_permissions = get_permissions('task', $task_id);
3833
            $_SESSION['total_permissions'][$_course['code']] = $task_permissions;
3834
        }
3835
        //print_r($_SESSION['total_permissions']);
3836
3837
        // Getting the permissions of the groups of the user
3838
        //$groups_of_user = GroupManager::get_group_ids($_course['db_name'], $_user['user_id']);
3839
3840
        //foreach($groups_of_user as $group)
3841
        //   $this_group_permissions = get_permissions('group', $group);
3842
3843
        // Getting the permissions of the courseroles of the user
3844
        $user_courserole_permissions = get_roles_permissions('user', $_user['user_id']);
3845
3846
        // Getting the permissions of the platformroles of the user
3847
        //$user_platformrole_permissions = get_roles_permissions('user', $_user['user_id'], ', platform');
3848
3849
        // Getting the permissions of the roles of the groups of the user
3850
        //foreach($groups_of_user as $group)
3851
        //    $this_group_courserole_permissions = get_roles_permissions('group', $group);
3852
3853
        // Getting the permissions of the platformroles of the groups of the user
3854
        //foreach($groups_of_user as $group)
3855
        //    $this_group_platformrole_permissions = get_roles_permissions('group', $group, 'platform');
3856
    }
3857
3858
    // If the permissions are limited, we have to map the extended ones to the limited ones.
3859
    if (api_get_setting('permissions') == 'limited') {
3860
        if ($action == 'Visibility') {
3861
            $action = 'Edit';
3862
        }
3863
        if ($action == 'Move') {
3864
            $action = 'Edit';
3865
        }
3866
    }
3867
3868
    // The session that contains all the permissions already exists for this course
3869
    // so there is no need to requery everything.
3870
    //my_print_r($_SESSION['total_permissions'][$_course['code']][$tool]);
3871
    if (is_array($_SESSION['total_permissions'][$_course['code']][$tool])) {
3872
        if (in_array($action, $_SESSION['total_permissions'][$_course['code']][$tool])) {
3873
            return true;
3874
        } else {
3875
            return false;
3876
        }
3877
    }
3878
3879
    return false;
3880
}
3881
3882
/**
3883
 * Tells whether this user is an anonymous user.
3884
 *
3885
 * @param int  $user_id  User ID (optional, will take session ID if not provided)
3886
 * @param bool $db_check Whether to check in the database (true) or simply in
3887
 *                       the session (false) to see if the current user is the anonymous user
3888
 *
3889
 * @return bool true if this user is anonymous, false otherwise
3890
 */
3891
function api_is_anonymous($user_id = null, $db_check = false)
3892
{
3893
    if (!isset($user_id)) {
3894
        $user_id = api_get_user_id();
3895
    }
3896
3897
    if ($db_check) {
3898
        $info = api_get_user_info($user_id);
3899
        if (false === $info || $info['status'] == ANONYMOUS) {
3900
            return true;
3901
        }
3902
    }
3903
3904
    $_user = api_get_user_info();
3905
3906
    if (isset($_user['status']) && $_user['status'] == ANONYMOUS) {
3907
        //if ($_user['user_id'] == 0) {
3908
        // In some cases, api_set_anonymous doesn't seem to be triggered in local.inc.php. Make sure it is.
3909
        // Occurs in agenda for admin links - YW
3910
        global $use_anonymous;
3911
        if (isset($use_anonymous) && $use_anonymous) {
3912
            api_set_anonymous();
3913
        }
3914
3915
        return true;
3916
    }
3917
3918
    return (isset($_user['is_anonymous']) && $_user['is_anonymous'] === true) || $_user === false;
3919
}
3920
3921
/**
3922
 * Displays message "You are not allowed here..." and exits the entire script.
3923
 *
3924
 * @param bool   $print_headers Whether or not to print headers (default = false -> does not print them)
3925
 * @param string $message
3926
 * @param int    $responseCode
3927
 */
3928
function api_not_allowed(
3929
    $print_headers = false,
3930
    $message = null,
3931
    $responseCode = 0
3932
) {
3933
    if (api_get_setting('sso_authentication') === 'true') {
3934
        global $osso;
3935
        if ($osso) {
3936
            $osso->logout();
3937
        }
3938
    }
3939
    $home_url = api_get_path(WEB_PATH);
3940
    $user_id = api_get_user_id();
3941
    $course = api_get_course_id();
3942
3943
    global $this_section;
3944
3945
    if (CustomPages::enabled() && !isset($user_id)) {
3946
        if (empty($user_id)) {
3947
            // Why the CustomPages::enabled() need to be to set the request_uri
3948
            $_SESSION['request_uri'] = $_SERVER['REQUEST_URI'];
3949
        }
3950
        CustomPages::display(CustomPages::INDEX_UNLOGGED);
3951
    }
3952
3953
    $origin = api_get_origin();
3954
3955
    $msg = null;
3956
    if (isset($message)) {
3957
        $msg = $message;
3958
    } else {
3959
        $msg = Display::return_message(
3960
            get_lang('NotAllowedClickBack').'
3961
            <script>function goBack(){window.history.back();}</script>',
3962
            'error',
3963
            false
3964
        );
3965
        $msg .= '<p class="text-center">
3966
             <a onclick="goBack();" class="btn btn-default" href="'.$home_url.'">'.get_lang('GoBack').'</a>
3967
             </p>';
3968
    }
3969
3970
    $msg = Display::div($msg, ['align' => 'center']);
3971
3972
    $show_headers = 0;
3973
    if ($print_headers && $origin != 'learnpath') {
3974
        $show_headers = 1;
3975
    }
3976
3977
    $hideBreadCrumb = false;
3978
    if (api_get_configuration_value('hide_breadcrumb_if_not_allowed')) {
3979
        $hideBreadCrumb = true;
3980
    }
3981
3982
    $tpl = new Template(null, $show_headers, $show_headers, $hideBreadCrumb, true, false, true, $responseCode);
3983
    $tpl->assign('hide_login_link', 1);
3984
    $tpl->assign('content', $msg);
3985
3986
    if (($user_id != 0 && !api_is_anonymous()) &&
3987
        (!isset($course) || $course == -1) &&
3988
        empty($_GET['cidReq'])
3989
    ) {
3990
        // if the access is not authorized and there is some login information
3991
        // but the cidReq is not found, assume we are missing course data and send the user
3992
        // to the user_portal
3993
        $tpl->display_one_col_template();
3994
        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...
3995
    }
3996
3997
    $tplPlugin = new AppPlugin();
3998
    $loginTopRegionContent = $tplPlugin->load_region('login_top', $tpl, true);
3999
    $loginBottomRegionContent = $tplPlugin->load_region('login_bottom', $tpl, true);
4000
4001
    if (!empty($_SERVER['REQUEST_URI']) &&
4002
        (
4003
            !empty($_GET['cidReq']) ||
4004
            $this_section == SECTION_MYPROFILE ||
4005
            $this_section == SECTION_PLATFORM_ADMIN
4006
        )
4007
    ) {
4008
        $courseCode = api_get_course_id();
4009
        // Only display form and return to the previous URL if there was a course ID included
4010
        if ($user_id != 0 && !api_is_anonymous()) {
4011
            //if there is a user ID, then the user is not allowed but the session is still there. Say so and exit
4012
            $tpl->assign('content', $msg);
4013
            $tpl->display_one_col_template();
4014
            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...
4015
        }
4016
4017
        if (!is_null($courseCode)) {
4018
            api_set_firstpage_parameter($courseCode);
4019
        }
4020
4021
        // If the user has no user ID, then his session has expired
4022
        $form = api_get_not_allowed_login_form();
4023
4024
        // see same text in auth/gotocourse.php and main_api.lib.php function api_not_allowed (above)
4025
        $content = Display::return_message(get_lang('NotAllowed'), 'error', false);
4026
4027
        if (!empty($courseCode)) {
4028
            $content .= '<h4>'.get_lang('LoginToGoToThisCourse').'</h4>';
4029
        }
4030
4031
        if (api_is_cas_activated()) {
4032
            $content .= Display::return_message(sprintf(get_lang('YouHaveAnInstitutionalAccount'), api_get_setting("Institution")), '', false);
4033
            $content .= Display::div(
4034
                Template::displayCASLoginButton(),
4035
                ['align' => 'center']
4036
            );
4037
            $content .= Display::return_message(get_lang('YouDontHaveAnInstitutionAccount'));
4038
            $content .= "<p style='text-align:center'><a href='#' onclick='$(this).parent().next().toggle()'>".get_lang('LoginWithExternalAccount')."</a></p>";
4039
            $content .= "<div style='display:none;'>";
4040
        }
4041
        $content .= PHP_EOL.$loginTopRegionContent;
4042
        $content .= '<div class="well">';
4043
        $content .= $form->returnForm();
4044
        $content .= '</div>';
4045
        $content .= PHP_EOL.$loginBottomRegionContent;
4046
        if (api_is_cas_activated()) {
4047
            $content .= "</div>";
4048
        }
4049
4050
        if (!empty($courseCode)) {
4051
            $content .= '<hr/><p style="text-align:center"><a href="'.$home_url.'">'.
4052
                get_lang('ReturnToCourseHomepage').'</a></p>';
4053
        } else {
4054
            $content .= '<hr/><p style="text-align:center"><a href="'.$home_url.'">'.
4055
                get_lang('BackHome').'</a></p>';
4056
        }
4057
4058
        $tpl->setLoginBodyClass();
4059
        $tpl->assign('content', $content);
4060
        $tpl->display_one_col_template();
4061
        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...
4062
    }
4063
4064
    if ($user_id != 0 && !api_is_anonymous()) {
4065
        $tpl->display_one_col_template();
4066
        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...
4067
    }
4068
4069
    $msg = null;
4070
    // The session is over and we were not in a course,
4071
    // or we try to get directly to a private course without being logged
4072
    $courseId = api_get_course_int_id();
4073
    if (!empty($courseId)) {
4074
        api_set_firstpage_parameter(api_get_course_id());
4075
        $tpl->setLoginBodyClass();
4076
4077
        // see same text in auth/gotocourse.php and main_api.lib.php function api_not_allowed (bellow)
4078
        $msg = Display::return_message(get_lang('NotAllowed'), 'error', false);
4079
        $msg .= '<h4>'.get_lang('LoginToGoToThisCourse').'</h4>';
4080
        $casEnabled = api_is_cas_activated();
4081
        if ($casEnabled) {
4082
            $msg .= Display::return_message(
4083
                sprintf(get_lang('YouHaveAnInstitutionalAccount'), api_get_setting("Institution")),
4084
                '',
4085
                false
4086
            );
4087
            $msg .= Display::div(
4088
                Template::displayCASLoginButton(),
4089
                ['align' => 'center']
4090
            );
4091
            $msg .= Display::return_message(get_lang('YouDontHaveAnInstitutionAccount'));
4092
            $msg .= "<p style='text-align:center'><a href='#' onclick='$(this).parent().next().toggle()'>".get_lang('LoginWithExternalAccount')."</a></p>";
4093
            $msg .= "<div style='display:none;'>";
4094
        }
4095
        $form = api_get_not_allowed_login_form();
4096
        $msg .= PHP_EOL.$loginTopRegionContent;
4097
        $msg .= '<div class="well">';
4098
        $msg .= $form->returnForm();
4099
        $msg .= '</div>';
4100
        $msg .= PHP_EOL.$loginBottomRegionContent;
4101
        if ($casEnabled) {
4102
            $msg .= "</div>";
4103
        }
4104
    } else {
4105
        // we were not in a course, return to home page
4106
        $msg = Display::return_message(
4107
            get_lang('NotAllowed'),
4108
            'error',
4109
            false
4110
        );
4111
4112
        $msg .= '<p class="text-center">
4113
                 <a class="btn btn-default" href="'.$home_url.'">'.get_lang('BackHome').'</a>
4114
                 </p>';
4115
4116
        if (!empty($message)) {
4117
            $msg = $message;
4118
        }
4119
4120
        if (api_is_anonymous()) {
4121
            $form = api_get_not_allowed_login_form();
4122
            $msg .= PHP_EOL.$loginTopRegionContent;
4123
            $msg .= '<div class="well">';
4124
            $msg .= $form->returnForm();
4125
            $msg .= '</div>';
4126
            $msg .= PHP_EOL.$loginBottomRegionContent;
4127
        }
4128
    }
4129
4130
    $tpl->assign('content', $msg);
4131
    $tpl->display_one_col_template();
4132
    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...
4133
}
4134
4135
/**
4136
 * @return FormValidator
4137
 */
4138
function api_get_not_allowed_login_form()
4139
{
4140
    $action = api_get_self().'?'.Security::remove_XSS($_SERVER['QUERY_STRING']);
4141
    $action = str_replace('&amp;', '&', $action);
4142
    Session::write('redirect_after_not_allow_page', $action);
4143
    $action .= '&redirect_after_not_allow_page=1';
4144
4145
    $form = new FormValidator(
4146
        'formLogin',
4147
        'post',
4148
        $action,
4149
        null,
4150
        ['class' => 'form-stacked']
4151
    );
4152
    $params = [
4153
        'placeholder' => get_lang('UserName'),
4154
        'class' => 'col-md-3',
4155
    ];
4156
    if (api_browser_support('autocapitalize')) {
4157
        $params['autocapitalize'] = 'none';
4158
    }
4159
4160
    $form->addElement(
4161
        'text',
4162
        'login',
4163
        null,
4164
        $params
4165
    );
4166
    $form->addElement(
4167
        'password',
4168
        'password',
4169
        null,
4170
        ['placeholder' => get_lang('Password'), 'class' => 'col-md-3']
4171
    ); //new
4172
    $form->addButtonNext(get_lang('LoginEnter'), 'submitAuth');
4173
4174
    return $form;
4175
}
4176
4177
/**
4178
 * Gets a UNIX timestamp from a database (MySQL) datetime format string.
4179
 *
4180
 * @param string $last_post_datetime standard output date in a sql query
4181
 *
4182
 * @return int timestamp
4183
 *
4184
 * @author Toon Van Hoecke <[email protected]>
4185
 *
4186
 * @version October 2003
4187
 * @desc convert sql date to unix timestamp
4188
 */
4189
function convert_sql_date($last_post_datetime)
4190
{
4191
    list($last_post_date, $last_post_time) = explode(' ', $last_post_datetime);
4192
    list($year, $month, $day) = explode('-', $last_post_date);
4193
    list($hour, $min, $sec) = explode(':', $last_post_time);
4194
4195
    return mktime((int) $hour, (int) $min, (int) $sec, (int) $month, (int) $day, (int) $year);
4196
}
4197
4198
/**
4199
 * Gets item visibility from the item_property table.
4200
 *
4201
 * Getting the visibility is done by getting the last updated visibility entry,
4202
 * using the largest session ID found if session 0 and another was found (meaning
4203
 * the only one that is actually from the session, in case there are results from
4204
 * session 0 *AND* session n).
4205
 *
4206
 * @param array  $_course  Course properties array (result of api_get_course_info())
4207
 * @param string $tool     Tool (learnpath, document, etc)
4208
 * @param int    $id       The item ID in the given tool
4209
 * @param int    $session  The session ID (optional)
4210
 * @param int    $user_id
4211
 * @param string $type
4212
 * @param string $group_id
4213
 *
4214
 * @return int -1 on error, 0 if invisible, 1 if visible
4215
 */
4216
function api_get_item_visibility(
4217
    $_course,
4218
    $tool,
4219
    $id,
4220
    $session = 0,
4221
    $user_id = null,
4222
    $type = null,
4223
    $group_id = null
4224
) {
4225
    if (!is_array($_course) || count($_course) == 0 || empty($tool) || empty($id)) {
4226
        return -1;
4227
    }
4228
4229
    $tool = Database::escape_string($tool);
4230
    $id = (int) $id;
4231
    $session = (int) $session;
4232
    $TABLE_ITEMPROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY);
4233
    $course_id = (int) $_course['real_id'];
4234
4235
    $userCondition = '';
4236
    if (!empty($user_id)) {
4237
        $user_id = (int) $user_id;
4238
        $userCondition = " AND to_user_id = $user_id ";
4239
    }
4240
4241
    $typeCondition = '';
4242
    if (!empty($type)) {
4243
        $type = Database::escape_string($type);
4244
        $typeCondition = " AND lastedit_type = '$type' ";
4245
    }
4246
4247
    $groupCondition = '';
4248
    if (!empty($group_id)) {
4249
        $group_id = (int) $group_id;
4250
        $groupCondition = " AND to_group_id = '$group_id' ";
4251
    }
4252
4253
    $sql = "SELECT visibility
4254
            FROM $TABLE_ITEMPROPERTY
4255
            WHERE
4256
                c_id = $course_id AND
4257
                tool = '$tool' AND
4258
                ref = $id AND
4259
                (session_id = $session OR session_id = 0 OR session_id IS NULL)
4260
                $userCondition $typeCondition $groupCondition
4261
            ORDER BY session_id DESC, lastedit_date DESC
4262
            LIMIT 1";
4263
4264
    $res = Database::query($sql);
4265
    if ($res === false || Database::num_rows($res) == 0) {
4266
        return -1;
4267
    }
4268
    $row = Database::fetch_array($res);
4269
4270
    return (int) $row['visibility'];
4271
}
4272
4273
/**
4274
 * Delete a row in the c_item_property table.
4275
 *
4276
 * @param array  $courseInfo
4277
 * @param string $tool
4278
 * @param int    $itemId
4279
 * @param int    $userId
4280
 * @param int    $groupId    group.iid
4281
 * @param int    $sessionId
4282
 *
4283
 * @return false|null
4284
 */
4285
function api_item_property_delete(
4286
    $courseInfo,
4287
    $tool,
4288
    $itemId,
4289
    $userId,
4290
    $groupId = 0,
4291
    $sessionId = 0
4292
) {
4293
    if (empty($courseInfo)) {
4294
        return false;
4295
    }
4296
4297
    $courseId = (int) $courseInfo['real_id'];
4298
4299
    if (empty($courseId) || empty($tool) || empty($itemId)) {
4300
        return false;
4301
    }
4302
4303
    $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4304
    $tool = Database::escape_string($tool);
4305
    $itemId = intval($itemId);
4306
    $userId = intval($userId);
4307
    $groupId = intval($groupId);
4308
    $sessionId = intval($sessionId);
4309
4310
    $groupCondition = " AND to_group_id = $groupId ";
4311
    if (empty($groupId)) {
4312
        $groupCondition = " AND (to_group_id is NULL OR to_group_id = 0) ";
4313
    }
4314
4315
    $userCondition = " AND to_user_id = $userId ";
4316
    if (empty($userId)) {
4317
        $userCondition = " AND (to_user_id is NULL OR to_user_id = 0) ";
4318
    }
4319
    $sessionCondition = api_get_session_condition($sessionId, true, false, 'session_id');
4320
    $sql = "DELETE FROM $table
4321
            WHERE
4322
                c_id = $courseId AND
4323
                tool  = '$tool' AND
4324
                ref = $itemId
4325
                $sessionCondition
4326
                $userCondition
4327
                $groupCondition
4328
            ";
4329
4330
    Database::query($sql);
4331
}
4332
4333
/**
4334
 * Updates or adds item properties to the Item_propetry table
4335
 * Tool and lastedit_type are language independant strings (langvars->get_lang!).
4336
 *
4337
 * @param array  $_course        array with course properties
4338
 * @param string $tool           tool id, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4339
 * @param int    $item_id        id of the item itself, linked to key of every tool ('id', ...)
4340
 * @param string $last_edit_type add or update action
4341
 *                               (1) message to be translated (in trad4all) : e.g. DocumentAdded, DocumentUpdated;
4342
 *                               (2) "delete"
4343
 *                               (3) "visible"
4344
 *                               (4) "invisible"
4345
 * @param int    $user_id        id of the editing/adding user
4346
 * @param array  $groupInfo      must include group.iid/group.od
4347
 * @param int    $to_user_id     id of the intended user (always has priority over $to_group_id !), only relevant for $type (1)
4348
 * @param string $start_visible  0000-00-00 00:00:00 format
4349
 * @param string $end_visible    0000-00-00 00:00:00 format
4350
 * @param int    $session_id     The session ID, if any, otherwise will default to 0
4351
 *
4352
 * @return bool false if update fails
4353
 *
4354
 * @author Toon Van Hoecke <[email protected]>, Ghent University
4355
 *
4356
 * @version January 2005
4357
 * @desc update the item_properties table (if entry not exists, insert) of the course
4358
 */
4359
function api_item_property_update(
4360
    $_course,
4361
    $tool,
4362
    $item_id,
4363
    $last_edit_type,
4364
    $user_id,
4365
    $groupInfo = [],
4366
    $to_user_id = null,
4367
    $start_visible = '',
4368
    $end_visible = '',
4369
    $session_id = 0
4370
) {
4371
    if (empty($_course)) {
4372
        return false;
4373
    }
4374
4375
    $course_id = $_course['real_id'];
4376
4377
    if (empty($course_id)) {
4378
        return false;
4379
    }
4380
4381
    $to_group_id = 0;
4382
    if (!empty($groupInfo) && isset($groupInfo['iid'])) {
4383
        $to_group_id = (int) $groupInfo['iid'];
4384
    }
4385
4386
    $em = Database::getManager();
4387
4388
    // Definition of variables.
4389
    $tool = Database::escape_string($tool);
4390
    $item_id = (int) $item_id;
4391
    $lastEditTypeNoFilter = $last_edit_type;
4392
    $last_edit_type = Database::escape_string($last_edit_type);
4393
    $user_id = (int) $user_id;
4394
4395
    $startVisible = "NULL";
4396
    if (!empty($start_visible)) {
4397
        $start_visible = Database::escape_string($start_visible);
4398
        $startVisible = "'$start_visible'";
4399
    }
4400
4401
    $endVisible = "NULL";
4402
    if (!empty($end_visible)) {
4403
        $end_visible = Database::escape_string($end_visible);
4404
        $endVisible = "'$end_visible'";
4405
    }
4406
4407
    $to_filter = '';
4408
    $time = api_get_utc_datetime();
4409
4410
    if (!empty($session_id)) {
4411
        $session_id = (int) $session_id;
4412
    } else {
4413
        $session_id = api_get_session_id();
4414
    }
4415
4416
    // Definition of tables.
4417
    $tableItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
4418
4419
    if ($to_user_id <= 0) {
4420
        $to_user_id = null; // No to_user_id set
4421
    }
4422
4423
    if (!is_null($to_user_id)) {
4424
        // $to_user_id has more priority than $to_group_id
4425
        $to_user_id = (int) $to_user_id;
4426
        $to_field = 'to_user_id';
4427
        $to_value = $to_user_id;
4428
    } else {
4429
        // $to_user_id is not set.
4430
        $to_field = 'to_group_id';
4431
        $to_value = $to_group_id;
4432
    }
4433
4434
    $toValueCondition = empty($to_value) ? 'NULL' : "'$to_value'";
4435
    // Set filters for $to_user_id and $to_group_id, with priority for $to_user_id
4436
    $condition_session = " AND session_id = $session_id ";
4437
    if (empty($session_id)) {
4438
        $condition_session = ' AND (session_id = 0 OR session_id IS NULL) ';
4439
    }
4440
4441
    $filter = " c_id = $course_id AND tool = '$tool' AND ref = $item_id $condition_session ";
4442
4443
    // Check whether $to_user_id and $to_group_id are passed in the function call.
4444
    // If both are not passed (both are null) then it is a message for everybody and $to_group_id should be 0 !
4445
    if (is_null($to_user_id) && is_null($to_group_id)) {
4446
        $to_group_id = 0;
4447
    }
4448
4449
    if (!is_null($to_user_id)) {
4450
        // Set filter to intended user.
4451
        $to_filter = " AND to_user_id = $to_user_id $condition_session";
4452
    } else {
4453
        // Set filter to intended group.
4454
        if (($to_group_id != 0) && $to_group_id == strval(intval($to_group_id))) {
4455
            $to_filter = " AND to_group_id = $to_group_id $condition_session";
4456
        }
4457
    }
4458
4459
    // Adding filter if set.
4460
    $filter .= $to_filter;
4461
4462
    // Update if possible
4463
    $set_type = '';
4464
4465
    switch ($lastEditTypeNoFilter) {
4466
        case 'delete':
4467
            // delete = make item only visible for the platform admin.
4468
            $visibility = '2';
4469
            if (!empty($session_id)) {
4470
                // Check whether session id already exist into item_properties for updating visibility or add it.
4471
                $sql = "SELECT session_id FROM $tableItemProperty
4472
                        WHERE
4473
                            c_id = $course_id AND
4474
                            tool = '$tool' AND
4475
                            ref = $item_id AND
4476
                            session_id = $session_id";
4477
                $rs = Database::query($sql);
4478
                if (Database::num_rows($rs) > 0) {
4479
                    $sql = "UPDATE $tableItemProperty
4480
                            SET lastedit_type       = '".str_replace('_', '', ucwords($tool))."Deleted',
4481
                                lastedit_date       = '$time',
4482
                                lastedit_user_id    = $user_id,
4483
                                visibility          = $visibility,
4484
                                session_id          = $session_id $set_type
4485
                            WHERE $filter";
4486
                    $result = Database::query($sql);
4487
                } else {
4488
                    $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)
4489
                            VALUES ($course_id, '$tool',$item_id, '$time', $user_id, '$time', '$last_edit_type',$user_id, $toValueCondition, $visibility, $startVisible, $endVisible, $session_id)";
4490
                    $result = Database::query($sql);
4491
                    $id = Database::insert_id();
4492
                    if ($id) {
4493
                        $sql = "UPDATE $tableItemProperty SET id = iid WHERE iid = $id";
4494
                        Database::query($sql);
4495
                    }
4496
                }
4497
            } else {
4498
                $sql = "UPDATE $tableItemProperty
4499
                        SET
4500
                            lastedit_type='".str_replace('_', '', ucwords($tool))."Deleted',
4501
                            lastedit_date='$time',
4502
                            lastedit_user_id = $user_id,
4503
                            visibility = $visibility $set_type
4504
                        WHERE $filter";
4505
                $result = Database::query($sql);
4506
            }
4507
            break;
4508
        case 'visible': // Change item to visible.
4509
            $visibility = '1';
4510
            if (!empty($session_id)) {
4511
                // Check whether session id already exist into item_properties for updating visibility or add it.
4512
                $sql = "SELECT session_id FROM $tableItemProperty
4513
                        WHERE
4514
                            c_id = $course_id AND
4515
                            tool = '$tool' AND
4516
                            ref = $item_id AND
4517
                            session_id = $session_id";
4518
                $rs = Database::query($sql);
4519
                if (Database::num_rows($rs) > 0) {
4520
                    $sql = "UPDATE $tableItemProperty
4521
                            SET
4522
                                lastedit_type='".str_replace('_', '', ucwords($tool))."Visible',
4523
                                lastedit_date='$time',
4524
                                lastedit_user_id = $user_id,
4525
                                visibility = $visibility,
4526
                                session_id = $session_id $set_type
4527
                            WHERE $filter";
4528
                    $result = Database::query($sql);
4529
                } else {
4530
                    $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)
4531
                            VALUES ($course_id, '$tool', $item_id, '$time', $user_id, '$time', '$last_edit_type', $user_id, $toValueCondition, $visibility, $startVisible, $endVisible, $session_id)";
4532
                    $result = Database::query($sql);
4533
                    $id = Database::insert_id();
4534
                    if ($id) {
4535
                        $sql = "UPDATE $tableItemProperty SET id = iid WHERE iid = $id";
4536
                        Database::query($sql);
4537
                    }
4538
                }
4539
            } else {
4540
                $sql = "UPDATE $tableItemProperty
4541
                        SET
4542
                            lastedit_type='".str_replace('_', '', ucwords($tool))."Visible',
4543
                            lastedit_date='$time',
4544
                            lastedit_user_id = $user_id,
4545
                            visibility = $visibility $set_type
4546
                        WHERE $filter";
4547
                $result = Database::query($sql);
4548
            }
4549
            break;
4550
        case 'invisible': // Change item to invisible.
4551
            $visibility = '0';
4552
            if (!empty($session_id)) {
4553
                // Check whether session id already exist into item_properties for updating visibility or add it
4554
                $sql = "SELECT session_id FROM $tableItemProperty
4555
                        WHERE
4556
                            c_id = $course_id AND
4557
                            tool = '$tool' AND
4558
                            ref = $item_id AND
4559
                            session_id = $session_id";
4560
                $rs = Database::query($sql);
4561
                if (Database::num_rows($rs) > 0) {
4562
                    $sql = "UPDATE $tableItemProperty
4563
                            SET
4564
                                lastedit_type = '".str_replace('_', '', ucwords($tool))."Invisible',
4565
                                lastedit_date = '$time',
4566
                                lastedit_user_id = $user_id,
4567
                                visibility = $visibility,
4568
                                session_id = $session_id $set_type
4569
                            WHERE $filter";
4570
                    $result = Database::query($sql);
4571
                } else {
4572
                    $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)
4573
                            VALUES ($course_id, '$tool', $item_id, '$time', $user_id, '$time', '$last_edit_type', $user_id, $toValueCondition, $visibility, $startVisible, $endVisible, $session_id)";
4574
                    $result = Database::query($sql);
4575
                    $id = Database::insert_id();
4576
                    if ($id) {
4577
                        $sql = "UPDATE $tableItemProperty SET id = iid WHERE iid = $id";
4578
                        Database::query($sql);
4579
                    }
4580
                }
4581
            } else {
4582
                $sql = "UPDATE $tableItemProperty
4583
                        SET
4584
                            lastedit_type = '".str_replace('_', '', ucwords($tool))."Invisible',
4585
                            lastedit_date = '$time',
4586
                            lastedit_user_id = $user_id,
4587
                            visibility = $visibility $set_type
4588
                        WHERE $filter";
4589
                $result = Database::query($sql);
4590
            }
4591
            break;
4592
        default: // The item will be added or updated.
4593
            $set_type = ", lastedit_type = '$last_edit_type' ";
4594
            $visibility = '1';
4595
            //$filter .= $to_filter; already added
4596
            $sql = "UPDATE $tableItemProperty
4597
                    SET
4598
                      lastedit_date = '$time',
4599
                      lastedit_user_id = $user_id $set_type
4600
                    WHERE $filter";
4601
            $result = Database::query($sql);
4602
    }
4603
4604
    // Insert if no entries are found (can only happen in case of $last_edit_type switch is 'default').
4605
    if ($result == false || Database::affected_rows($result) == 0) {
4606
        $objCourse = $em->find('ChamiloCoreBundle:Course', intval($course_id));
4607
        $objTime = new DateTime('now', new DateTimeZone('UTC'));
4608
        $objUser = api_get_user_entity($user_id);
4609
        if (empty($objUser)) {
4610
            // Use anonymous
4611
            $user_id = api_get_anonymous_id();
4612
            $objUser = api_get_user_entity($user_id);
4613
        }
4614
4615
        $objGroup = null;
4616
        if (!empty($to_group_id)) {
4617
            $objGroup = $em->find('ChamiloCourseBundle:CGroupInfo', $to_group_id);
4618
        }
4619
4620
        $objToUser = api_get_user_entity($to_user_id);
4621
        $objSession = $em->find('ChamiloCoreBundle:Session', intval($session_id));
4622
4623
        $startVisibleDate = !empty($start_visible) ? new DateTime($start_visible, new DateTimeZone('UTC')) : null;
4624
        $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...
4625
4626
        $cItemProperty = new CItemProperty($objCourse);
4627
        $cItemProperty
4628
            ->setTool($tool)
4629
            ->setRef($item_id)
4630
            ->setInsertDate($objTime)
4631
            ->setInsertUser($objUser)
4632
            ->setLasteditDate($objTime)
4633
            ->setLasteditType($last_edit_type)
4634
            ->setGroup($objGroup)
4635
            ->setToUser($objToUser)
4636
            ->setVisibility($visibility)
4637
            ->setStartVisible($startVisibleDate)
4638
            ->setEndVisible($endVisibleDate)
4639
            ->setSession($objSession);
4640
4641
        $em->persist($cItemProperty);
4642
        $em->flush();
4643
4644
        $id = $cItemProperty->getIid();
4645
4646
        if ($id) {
4647
            $cItemProperty->setId($id);
4648
            $em->merge($cItemProperty);
4649
            $em->flush();
4650
4651
            return false;
4652
        }
4653
    }
4654
4655
    return true;
4656
}
4657
4658
/**
4659
 * Gets item property by tool.
4660
 *
4661
 * @param string $tool        tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4662
 * @param string $course_code
4663
 * @param int    $session_id
4664
 *
4665
 * @return array All fields from c_item_property (all rows found) or empty array
4666
 */
4667
function api_get_item_property_by_tool($tool, $course_code, $session_id = null)
4668
{
4669
    $course_info = api_get_course_info($course_code);
4670
    $tool = Database::escape_string($tool);
4671
4672
    // Definition of tables.
4673
    $item_property_table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4674
    $session_id = (int) $session_id;
4675
    $session_condition = ' AND session_id = '.$session_id;
4676
    if (empty($session_id)) {
4677
        $session_condition = " AND (session_id = 0 OR session_id IS NULL) ";
4678
    }
4679
    $course_id = $course_info['real_id'];
4680
4681
    $sql = "SELECT * FROM $item_property_table
4682
            WHERE
4683
                c_id = $course_id AND
4684
                tool = '$tool'
4685
                $session_condition ";
4686
    $rs = Database::query($sql);
4687
    $list = [];
4688
    if (Database::num_rows($rs) > 0) {
4689
        while ($row = Database::fetch_array($rs, 'ASSOC')) {
4690
            $list[] = $row;
4691
        }
4692
    }
4693
4694
    return $list;
4695
}
4696
4697
/**
4698
 * Gets item property by tool and user.
4699
 *
4700
 * @param int $userId
4701
 * @param int $tool
4702
 * @param int $courseId
4703
 * @param int $session_id
4704
 *
4705
 * @return array
4706
 */
4707
function api_get_item_property_list_by_tool_by_user(
4708
    $userId,
4709
    $tool,
4710
    $courseId,
4711
    $session_id = 0
4712
) {
4713
    $userId = intval($userId);
4714
    $tool = Database::escape_string($tool);
4715
    $session_id = intval($session_id);
4716
    $courseId = intval($courseId);
4717
4718
    // Definition of tables.
4719
    $item_property_table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4720
    $session_condition = ' AND session_id = '.$session_id;
4721
    if (empty($session_id)) {
4722
        $session_condition = " AND (session_id = 0 OR session_id IS NULL) ";
4723
    }
4724
    $sql = "SELECT * FROM $item_property_table
4725
            WHERE
4726
                insert_user_id = $userId AND
4727
                c_id = $courseId AND
4728
                tool = '$tool'
4729
                $session_condition ";
4730
4731
    $rs = Database::query($sql);
4732
    $list = [];
4733
    if (Database::num_rows($rs) > 0) {
4734
        while ($row = Database::fetch_array($rs, 'ASSOC')) {
4735
            $list[] = $row;
4736
        }
4737
    }
4738
4739
    return $list;
4740
}
4741
4742
/**
4743
 * Gets item property id from tool of a course.
4744
 *
4745
 * @param string $course_code course code
4746
 * @param string $tool        tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4747
 * @param int    $ref         id of the item itself, linked to key of every tool ('id', ...), "*" = all items of the tool
4748
 * @param int    $sessionId   Session ID (optional)
4749
 *
4750
 * @return int
4751
 */
4752
function api_get_item_property_id($course_code, $tool, $ref, $sessionId = 0)
4753
{
4754
    $course_info = api_get_course_info($course_code);
4755
    $tool = Database::escape_string($tool);
4756
    $ref = (int) $ref;
4757
4758
    // Definition of tables.
4759
    $tableItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
4760
    $course_id = $course_info['real_id'];
4761
    $sessionId = (int) $sessionId;
4762
    $sessionCondition = " AND session_id = $sessionId ";
4763
    if (empty($sessionId)) {
4764
        $sessionCondition = ' AND (session_id = 0 OR session_id IS NULL) ';
4765
    }
4766
    $sql = "SELECT id FROM $tableItemProperty
4767
            WHERE
4768
                c_id = $course_id AND
4769
                tool = '$tool' AND
4770
                ref = $ref
4771
                $sessionCondition";
4772
    $rs = Database::query($sql);
4773
    $item_property_id = '';
4774
    if (Database::num_rows($rs) > 0) {
4775
        $row = Database::fetch_array($rs);
4776
        $item_property_id = $row['id'];
4777
    }
4778
4779
    return $item_property_id;
4780
}
4781
4782
/**
4783
 * Inserts a record in the track_e_item_property table (No update).
4784
 *
4785
 * @param string $tool
4786
 * @param int    $ref
4787
 * @param string $title
4788
 * @param string $content
4789
 * @param int    $progress
4790
 *
4791
 * @return bool|int
4792
 */
4793
function api_track_item_property_update($tool, $ref, $title, $content, $progress)
4794
{
4795
    $tbl_stats_item_property = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ITEM_PROPERTY);
4796
    $course_id = api_get_course_int_id(); //numeric
4797
    $course_code = api_get_course_id(); //alphanumeric
4798
    $item_property_id = api_get_item_property_id($course_code, $tool, $ref);
4799
    if (!empty($item_property_id)) {
4800
        $sql = "INSERT IGNORE INTO $tbl_stats_item_property SET
4801
                course_id           = '$course_id',
4802
                item_property_id    = '$item_property_id',
4803
                title               = '".Database::escape_string($title)."',
4804
                content             = '".Database::escape_string($content)."',
4805
                progress            = '".intval($progress)."',
4806
                lastedit_date       = '".api_get_utc_datetime()."',
4807
                lastedit_user_id    = '".api_get_user_id()."',
4808
                session_id          = '".api_get_session_id()."'";
4809
        $result = Database::query($sql);
4810
        $affected_rows = Database::affected_rows($result);
4811
4812
        return $affected_rows;
4813
    }
4814
4815
    return false;
4816
}
4817
4818
/**
4819
 * @param string $tool
4820
 * @param int    $ref
4821
 *
4822
 * @return array|resource
4823
 */
4824
function api_get_track_item_property_history($tool, $ref)
4825
{
4826
    $tbl_stats_item_property = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ITEM_PROPERTY);
4827
    $course_id = api_get_course_int_id(); //numeric
4828
    $course_code = api_get_course_id(); //alphanumeric
4829
    $item_property_id = api_get_item_property_id($course_code, $tool, $ref);
4830
    $sql = "SELECT * FROM $tbl_stats_item_property
4831
            WHERE item_property_id = $item_property_id AND course_id = $course_id
4832
            ORDER BY lastedit_date DESC";
4833
    $result = Database::query($sql);
4834
    if ($result === false or $result === null) {
4835
        $result = [];
4836
    } else {
4837
        $result = Database::store_result($result, 'ASSOC');
4838
    }
4839
4840
    return $result;
4841
}
4842
4843
/**
4844
 * Gets item property data from tool of a course id.
4845
 *
4846
 * @param int    $course_id
4847
 * @param string $tool       tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4848
 * @param int    $ref        id of the item itself, linked to key of every tool ('id', ...), "*" = all items of the tool
4849
 * @param int    $session_id
4850
 * @param int    $groupId
4851
 *
4852
 * @return array with all fields from c_item_property, empty array if not found or false if course could not be found
4853
 */
4854
function api_get_item_property_info($course_id, $tool, $ref, $session_id = 0, $groupId = 0)
4855
{
4856
    $courseInfo = api_get_course_info_by_id($course_id);
4857
4858
    if (empty($courseInfo)) {
4859
        return false;
4860
    }
4861
4862
    $tool = Database::escape_string($tool);
4863
    $course_id = $courseInfo['real_id'];
4864
    $ref = (int) $ref;
4865
    $session_id = (int) $session_id;
4866
4867
    $sessionCondition = " session_id = $session_id";
4868
    if (empty($session_id)) {
4869
        $sessionCondition = ' (session_id = 0 OR session_id IS NULL) ';
4870
    }
4871
4872
    // Definition of tables.
4873
    $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4874
4875
    $sql = "SELECT * FROM $table
4876
            WHERE
4877
                c_id = $course_id AND
4878
                tool = '$tool' AND
4879
                ref = $ref AND
4880
                $sessionCondition ";
4881
4882
    if (!empty($groupId)) {
4883
        $groupId = (int) $groupId;
4884
        $sql .= " AND to_group_id = $groupId ";
4885
    }
4886
4887
    $rs = Database::query($sql);
4888
    $row = [];
4889
    if (Database::num_rows($rs) > 0) {
4890
        $row = Database::fetch_array($rs, 'ASSOC');
4891
    }
4892
4893
    return $row;
4894
}
4895
4896
/**
4897
 * Displays a combo box so the user can select his/her preferred language.
4898
 *
4899
 * @param string The desired name= value for the select
4900
 * @param bool Whether we use the JQuery Chozen library or not
4901
 * (in some cases, like the indexing language picker, it can alter the presentation)
4902
 *
4903
 * @return string
4904
 */
4905
function api_get_languages_combo($name = 'language')
4906
{
4907
    $ret = '';
4908
    $platformLanguage = api_get_setting('platformLanguage');
4909
4910
    // Retrieve a complete list of all the languages.
4911
    $language_list = api_get_languages();
4912
4913
    if (count($language_list['name']) < 2) {
4914
        return $ret;
4915
    }
4916
4917
    // The the current language of the user so that his/her language occurs as selected in the dropdown menu.
4918
    if (isset($_SESSION['user_language_choice'])) {
4919
        $default = $_SESSION['user_language_choice'];
4920
    } else {
4921
        $default = $platformLanguage;
4922
    }
4923
4924
    $languages = $language_list['name'];
4925
    $folder = $language_list['folder'];
4926
4927
    $ret .= '<select name="'.$name.'" id="language_chosen" class="selectpicker form-control">';
4928
    foreach ($languages as $key => $value) {
4929
        if ($folder[$key] == $default) {
4930
            $selected = ' selected="selected"';
4931
        } else {
4932
            $selected = '';
4933
        }
4934
        $ret .= sprintf('<option value=%s" %s>%s</option>', $folder[$key], $selected, $value);
4935
    }
4936
    $ret .= '</select>';
4937
4938
    return $ret;
4939
}
4940
4941
/**
4942
 * Displays a form (drop down menu) so the user can select his/her preferred language.
4943
 * The form works with or without javascript.
4944
 *
4945
 * @param  bool Hide form if only one language available (defaults to false = show the box anyway)
4946
 * @param bool $showAsButton
4947
 *
4948
 * @return string|null Display the box directly
4949
 */
4950
function api_display_language_form($hide_if_no_choice = false, $showAsButton = false)
4951
{
4952
    // Retrieve a complete list of all the languages.
4953
    $language_list = api_get_languages();
4954
    if (count($language_list['name']) <= 1 && $hide_if_no_choice) {
4955
        return null; //don't show any form
4956
    }
4957
4958
    // The the current language of the user so that his/her language occurs as selected in the dropdown menu.
4959
    if (isset($_SESSION['user_language_choice'])) {
4960
        $user_selected_language = $_SESSION['user_language_choice'];
4961
    }
4962
    if (empty($user_selected_language)) {
4963
        $user_selected_language = api_get_setting('platformLanguage');
4964
    }
4965
4966
    $currentLanguageId = api_get_language_id($user_selected_language);
4967
    $currentLanguageInfo = api_get_language_info($currentLanguageId);
4968
4969
    $countryCode = languageCodeToCountryIsoCodeForFlags($currentLanguageInfo['isocode']);
4970
    $url = api_get_self();
4971
    if ($showAsButton) {
4972
        $html = '<div class="btn-group">
4973
              <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
4974
                <span class="flag-icon flag-icon-'.$countryCode.'"></span>
4975
                '.$currentLanguageInfo['original_name'].'
4976
                <span class="caret">
4977
                </span>
4978
              </button>';
4979
    } else {
4980
        $html = '
4981
            <a href="'.$url.'" class="dropdown-toggle" data-toggle="dropdown" role="button">
4982
                <span class="flag-icon flag-icon-'.$countryCode.'"></span>
4983
                '.$currentLanguageInfo['original_name'].'
4984
                <span class="caret"></span>
4985
            </a>
4986
            ';
4987
    }
4988
4989
    $html .= '<ul class="dropdown-menu" role="menu">';
4990
    foreach ($language_list['all'] as $key => $data) {
4991
        $urlLink = $url.'?language='.$data['english_name'];
4992
        $html .= '<li><a href="'.$urlLink.'"><span class="flag-icon flag-icon-'.languageCodeToCountryIsoCodeForFlags($data['isocode']).'"></span> '.$data['original_name'].'</a></li>';
4993
    }
4994
    $html .= '</ul>';
4995
4996
    if ($showAsButton) {
4997
        $html .= '</div>';
4998
    }
4999
5000
    return $html;
5001
}
5002
5003
/**
5004
 * Return a country code based on a language in order to show a country flag.
5005
 * Note: Showing a "language" flag is arguably a bad idea, as several countries
5006
 * share languages and the right flag cannot be shown for all of them.
5007
 *
5008
 * @param string $languageIsoCode
5009
 *
5010
 * @return string
5011
 */
5012
function languageCodeToCountryIsoCodeForFlags($languageIsoCode)
5013
{
5014
    $allow = api_get_configuration_value('language_flags_by_country');
5015
5016
    // @todo save in DB
5017
    switch ($languageIsoCode) {
5018
        case 'ar':
5019
            $country = 'ae';
5020
            break;
5021
        case 'bs':
5022
            $country = 'ba';
5023
            break;
5024
        case 'ca':
5025
            $country = 'es';
5026
            if ($allow) {
5027
                $country = 'catalan';
5028
            }
5029
            break;
5030
        case 'cs':
5031
            $country = 'cz';
5032
            break;
5033
        case 'da':
5034
            $country = 'dk';
5035
            break;
5036
        case 'el':
5037
            $country = 'gr';
5038
            break;
5039
        case 'en':
5040
            $country = 'gb';
5041
            break;
5042
        case 'eu': // Euskera
5043
            $country = 'es';
5044
            if ($allow) {
5045
                $country = 'basque';
5046
            }
5047
            break;
5048
        case 'gl': // galego
5049
            $country = 'es';
5050
            if ($allow) {
5051
                $country = 'galician';
5052
            }
5053
            break;
5054
        case 'he':
5055
            $country = 'il';
5056
            break;
5057
        case 'ja':
5058
            $country = 'jp';
5059
            break;
5060
        case 'ka':
5061
            $country = 'ge';
5062
            break;
5063
        case 'ko':
5064
            $country = 'kr';
5065
            break;
5066
        case 'ms':
5067
            $country = 'my';
5068
            break;
5069
        case 'pt-BR':
5070
            $country = 'br';
5071
            break;
5072
        case 'qu':
5073
            $country = 'pe';
5074
            break;
5075
        case 'sl':
5076
            $country = 'si';
5077
            break;
5078
        case 'sv':
5079
            $country = 'se';
5080
            break;
5081
        case 'uk': // Ukraine
5082
            $country = 'ua';
5083
            break;
5084
        case 'vi': // Vietnam - GH#4231
5085
            $country = 'vn';
5086
            break;
5087
        case 'zh-TW':
5088
        case 'zh':
5089
            $country = 'cn';
5090
            break;
5091
        default:
5092
            $country = $languageIsoCode;
5093
            break;
5094
    }
5095
    $country = strtolower($country);
5096
5097
    return $country;
5098
}
5099
5100
/**
5101
 * Returns a list of all the languages that are made available by the admin.
5102
 *
5103
 * @return array An array with all languages. Structure of the array is
5104
 *               array['name'] = An array with the name of every language
5105
 *               array['folder'] = An array with the corresponding names of the language-folders in the filesystem
5106
 */
5107
function api_get_languages()
5108
{
5109
    $tbl_language = Database::get_main_table(TABLE_MAIN_LANGUAGE);
5110
    $sql = "SELECT * FROM $tbl_language WHERE available='1'
5111
            ORDER BY original_name ASC";
5112
    $result = Database::query($sql);
5113
    $language_list = [];
5114
    while ($row = Database::fetch_array($result)) {
5115
        $language_list['name'][] = $row['original_name'];
5116
        $language_list['folder'][] = $row['dokeos_folder'];
5117
        $language_list['all'][] = $row;
5118
    }
5119
5120
    return $language_list;
5121
}
5122
5123
/**
5124
 * Returns a list of all the languages that are made available by the admin.
5125
 *
5126
 * @return array
5127
 */
5128
function api_get_languages_to_array()
5129
{
5130
    $tbl_language = Database::get_main_table(TABLE_MAIN_LANGUAGE);
5131
    $sql = "SELECT * FROM $tbl_language
5132
            WHERE available='1' ORDER BY original_name ASC";
5133
    $result = Database::query($sql);
5134
    $languages = [];
5135
    while ($row = Database::fetch_array($result)) {
5136
        $languages[$row['dokeos_folder']] = $row['original_name'];
5137
    }
5138
5139
    return $languages;
5140
}
5141
5142
/**
5143
 * Returns the id (the database id) of a language.
5144
 *
5145
 * @param   string  language name (the corresponding name of the language-folder in the filesystem)
5146
 *
5147
 * @return int id of the language
5148
 */
5149
function api_get_language_id($language)
5150
{
5151
    if (empty($language)) {
5152
        return null;
5153
    }
5154
5155
    static $staticResult = [];
5156
5157
    if (isset($staticResult[$language])) {
5158
        return $staticResult[$language];
5159
    } else {
5160
        $table = Database::get_main_table(TABLE_MAIN_LANGUAGE);
5161
        $language = Database::escape_string($language);
5162
        $sql = "SELECT id FROM $table
5163
                WHERE dokeos_folder = '$language' LIMIT 1";
5164
        $result = Database::query($sql);
5165
        $row = Database::fetch_array($result);
5166
5167
        $staticResult[$language] = $row['id'];
5168
5169
        return $row['id'];
5170
    }
5171
}
5172
5173
/**
5174
 * Gets language of the requested type for the current user. Types are :
5175
 * user_profil_lang : profile language of current user
5176
 * user_select_lang : language selected by user at login
5177
 * course_lang : language of the current course
5178
 * platform_lang : default platform language.
5179
 *
5180
 * @param string $lang_type
5181
 *
5182
 * @return string
5183
 */
5184
function api_get_language_from_type($lang_type)
5185
{
5186
    $return = false;
5187
    switch ($lang_type) {
5188
        case 'platform_lang':
5189
            $temp_lang = api_get_setting('platformLanguage');
5190
            if (!empty($temp_lang)) {
5191
                $return = $temp_lang;
5192
            }
5193
            break;
5194
        case 'user_profil_lang':
5195
            $_user = api_get_user_info();
5196
            if (isset($_user['language']) && !empty($_user['language'])) {
5197
                $return = $_user['language'];
5198
            }
5199
            break;
5200
        case 'user_selected_lang':
5201
            if (isset($_SESSION['user_language_choice']) && !empty($_SESSION['user_language_choice'])) {
5202
                $return = $_SESSION['user_language_choice'];
5203
            }
5204
            break;
5205
        case 'course_lang':
5206
            global $_course;
5207
            $cidReq = null;
5208
            if (empty($_course)) {
5209
                // Code modified because the local.inc.php file it's declarated after this work
5210
                // causing the function api_get_course_info() returns a null value
5211
                $cidReq = isset($_GET["cidReq"]) ? Database::escape_string($_GET["cidReq"]) : null;
5212
                $cDir = (!empty($_GET['cDir']) ? $_GET['cDir'] : null);
5213
                if (empty($cidReq) && !empty($cDir)) {
5214
                    $c = CourseManager::getCourseCodeFromDirectory($cDir);
5215
                    if ($c) {
5216
                        $cidReq = $c;
5217
                    }
5218
                }
5219
            }
5220
            $_course = api_get_course_info($cidReq);
5221
            if (isset($_course['language']) && !empty($_course['language'])) {
5222
                $return = $_course['language'];
5223
                $showCourseInUserLanguage = api_get_course_setting('show_course_in_user_language');
5224
                if ($showCourseInUserLanguage == 1) {
5225
                    $userInfo = api_get_user_info();
5226
                    if (isset($userInfo['language'])) {
5227
                        $return = $userInfo['language'];
5228
                    }
5229
                }
5230
            }
5231
            break;
5232
        default:
5233
            $return = false;
5234
            break;
5235
    }
5236
5237
    return $return;
5238
}
5239
5240
/**
5241
 * Get the language information by its id.
5242
 *
5243
 * @param int $languageId
5244
 *
5245
 * @throws Exception
5246
 *
5247
 * @return array
5248
 */
5249
function api_get_language_info($languageId)
5250
{
5251
    if (empty($languageId)) {
5252
        return [];
5253
    }
5254
5255
    $language = Database::getManager()
5256
        ->find('ChamiloCoreBundle:Language', $languageId);
5257
5258
    if (!$language) {
5259
        return [];
5260
    }
5261
5262
    return [
5263
        'id' => $language->getId(),
5264
        'original_name' => $language->getOriginalName(),
5265
        'english_name' => $language->getEnglishName(),
5266
        'isocode' => $language->getIsocode(),
5267
        'dokeos_folder' => $language->getDokeosFolder(),
5268
        'available' => $language->getAvailable(),
5269
        'parent_id' => $language->getParent() ? $language->getParent()->getId() : null,
5270
    ];
5271
}
5272
5273
/**
5274
 * Returns the name of the visual (CSS) theme to be applied on the current page.
5275
 * The returned name depends on the platform, course or user -wide settings.
5276
 *
5277
 * @return string The visual theme's name, it is the name of a folder inside web/css/themes
5278
 */
5279
function api_get_visual_theme()
5280
{
5281
    static $visual_theme;
5282
5283
    $course_id = api_get_course_id();
5284
    $courseThemeAvailable = false;
5285
    // If called from CLI or from inside a course, it should be reloaded.
5286
    if ('cli' === PHP_SAPI) {
5287
        $visual_theme = null;
5288
    } elseif (!empty($course_id)) {
5289
        $courseThemeAvailable = api_get_setting('allow_course_theme') == 'true';
5290
        if ($courseThemeAvailable) {
5291
            $visual_theme = null;
5292
        }
5293
    }
5294
5295
    if (!isset($visual_theme)) {
5296
        $cacheAvailable = api_get_configuration_value('apc');
5297
        $userThemeAvailable = api_get_setting('user_selected_theme') == 'true';
5298
        // only use a shared cache if no user-based or course-based theme is allowed
5299
        $useCache = ($cacheAvailable && !$userThemeAvailable && !$courseThemeAvailable);
5300
        $apcVar = '';
5301
        if ($useCache) {
5302
            $apcVar = api_get_configuration_value('apc_prefix').'my_campus_visual_theme';
5303
            if (apcu_exists($apcVar)) {
5304
                return apcu_fetch($apcVar);
5305
            }
5306
        }
5307
5308
        $accessUrlId = api_get_current_access_url_id();
5309
        if ('cli' === PHP_SAPI) {
5310
            $accessUrlId = api_get_configuration_value('access_url');
5311
        }
5312
5313
        // Get style directly from DB
5314
        $styleFromDatabase = api_get_settings_params_simple(
5315
            [
5316
                'variable = ? AND access_url = ?' => [
5317
                    'stylesheets',
5318
                    $accessUrlId,
5319
                ],
5320
            ]
5321
        );
5322
        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...
5323
            $platform_theme = $styleFromDatabase['selected_value'];
5324
        } else {
5325
            $platform_theme = api_get_setting('stylesheets');
5326
        }
5327
5328
        // Platform's theme.
5329
        $visual_theme = $platform_theme;
5330
        if ($userThemeAvailable) {
5331
            $user_info = api_get_user_info();
5332
            if (isset($user_info['theme'])) {
5333
                $user_theme = $user_info['theme'];
5334
5335
                if (!empty($user_theme)) {
5336
                    $visual_theme = $user_theme;
5337
                    // User's theme.
5338
                }
5339
            }
5340
        }
5341
5342
        if (!empty($course_id)) {
5343
            if ($courseThemeAvailable) {
5344
                $course_theme = api_get_course_setting('course_theme', api_get_course_info());
5345
5346
                if (!empty($course_theme) && $course_theme != -1) {
5347
                    if (!empty($course_theme)) {
5348
                        // Course's theme.
5349
                        $visual_theme = $course_theme;
5350
                    }
5351
                }
5352
5353
                $allow_lp_theme = api_get_course_setting('allow_learning_path_theme');
5354
                if ($allow_lp_theme == 1) {
5355
                    global $lp_theme_css, $lp_theme_config;
5356
                    // These variables come from the file lp_controller.php.
5357
                    if (!$lp_theme_config) {
5358
                        if (!empty($lp_theme_css)) {
5359
                            // LP's theme.
5360
                            $visual_theme = $lp_theme_css;
5361
                        }
5362
                    }
5363
                }
5364
            }
5365
        }
5366
5367
        if (empty($visual_theme)) {
5368
            $visual_theme = 'chamilo';
5369
        }
5370
5371
        global $lp_theme_log;
5372
        if ($lp_theme_log) {
5373
            $visual_theme = $platform_theme;
5374
        }
5375
        if ($useCache) {
5376
            apcu_store($apcVar, $visual_theme, 120);
5377
        }
5378
    }
5379
5380
    return $visual_theme;
5381
}
5382
5383
/**
5384
 * Returns a list of CSS themes currently available in the CSS folder
5385
 * The folder must have a default.css file.
5386
 *
5387
 * @param bool $getOnlyThemeFromVirtualInstance Used by the vchamilo plugin
5388
 *
5389
 * @return array list of themes directories from the css folder
5390
 *               Note: Directory names (names of themes) in the file system should contain ASCII-characters only
5391
 */
5392
function api_get_themes($getOnlyThemeFromVirtualInstance = false)
5393
{
5394
    // This configuration value is set by the vchamilo plugin
5395
    $virtualTheme = api_get_configuration_value('virtual_css_theme_folder');
5396
5397
    $readCssFolder = function ($dir) use ($virtualTheme) {
5398
        $finder = new Finder();
5399
        $themes = $finder->directories()->in($dir)->depth(0)->sortByName();
5400
        $list = [];
5401
        /** @var Symfony\Component\Finder\SplFileInfo $theme */
5402
        foreach ($themes as $theme) {
5403
            $folder = $theme->getFilename();
5404
            // A theme folder is consider if there's a default.css file
5405
            if (!file_exists($theme->getPathname().'/default.css')) {
5406
                continue;
5407
            }
5408
            $name = ucwords(str_replace('_', ' ', $folder));
5409
            if ($folder == $virtualTheme) {
5410
                continue;
5411
            }
5412
            $list[$folder] = $name;
5413
        }
5414
5415
        return $list;
5416
    };
5417
5418
    $dir = api_get_path(SYS_CSS_PATH).'themes/';
5419
    $list = $readCssFolder($dir);
5420
5421
    if (!empty($virtualTheme)) {
5422
        $newList = $readCssFolder($dir.'/'.$virtualTheme);
5423
        if ($getOnlyThemeFromVirtualInstance) {
5424
            return $newList;
5425
        }
5426
        $list = $list + $newList;
5427
        asort($list);
5428
    }
5429
5430
    return $list;
5431
}
5432
5433
/**
5434
 * Find the largest sort value in a given user_course_category
5435
 * This function is used when we are moving a course to a different category
5436
 * and also when a user subscribes to courses (the new course is added at the end of the main category.
5437
 *
5438
 * @author Patrick Cool <[email protected]>, Ghent University
5439
 *
5440
 * @param int $user_course_category the id of the user_course_category
5441
 * @param int $user_id
5442
 *
5443
 * @return int the value of the highest sort of the user_course_category
5444
 */
5445
function api_max_sort_value($user_course_category, $user_id)
5446
{
5447
    $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
5448
    $sql = "SELECT max(sort) as max_sort FROM $tbl_course_user
5449
            WHERE
5450
                user_id='".intval($user_id)."' AND
5451
                relation_type<>".COURSE_RELATION_TYPE_RRHH." AND
5452
                user_course_cat='".intval($user_course_category)."'";
5453
    $result_max = Database::query($sql);
5454
    if (Database::num_rows($result_max) == 1) {
5455
        $row_max = Database::fetch_array($result_max);
5456
5457
        return $row_max['max_sort'];
5458
    }
5459
5460
    return 0;
5461
}
5462
5463
/**
5464
 * Transforms a number of seconds in hh:mm:ss format.
5465
 *
5466
 * @author Julian Prud'homme
5467
 *
5468
 * @param int    $seconds      number of seconds
5469
 * @param string $space
5470
 * @param bool   $showSeconds
5471
 * @param bool   $roundMinutes
5472
 *
5473
 * @return string the formatted time
5474
 */
5475
function api_time_to_hms($seconds, $space = ':', $showSeconds = true, $roundMinutes = false)
5476
{
5477
    // $seconds = -1 means that we have wrong data in the db.
5478
    if ($seconds == -1) {
5479
        return
5480
            get_lang('Unknown').
5481
            Display::return_icon(
5482
                'info2.gif',
5483
                get_lang('WrongDatasForTimeSpentOnThePlatform'),
5484
                ['align' => 'absmiddle', 'hspace' => '3px']
5485
            );
5486
    }
5487
5488
    // How many hours ?
5489
    $hours = floor($seconds / 3600);
5490
5491
    // How many minutes ?
5492
    $min = floor(($seconds - ($hours * 3600)) / 60);
5493
5494
    if ($roundMinutes) {
5495
        if ($min >= 45) {
5496
            $min = 45;
5497
        }
5498
5499
        if ($min >= 30 && $min <= 44) {
5500
            $min = 30;
5501
        }
5502
5503
        if ($min >= 15 && $min <= 29) {
5504
            $min = 15;
5505
        }
5506
5507
        if ($min >= 0 && $min <= 14) {
5508
            $min = 0;
5509
        }
5510
    }
5511
5512
    // How many seconds
5513
    $sec = floor($seconds - ($hours * 3600) - ($min * 60));
5514
5515
    if ($hours < 10) {
5516
        $hours = "0$hours";
5517
    }
5518
5519
    if ($sec < 10) {
5520
        $sec = "0$sec";
5521
    }
5522
5523
    if ($min < 10) {
5524
        $min = "0$min";
5525
    }
5526
5527
    $seconds = '';
5528
    if ($showSeconds) {
5529
        $seconds = $space.$sec;
5530
    }
5531
5532
    return $hours.$space.$min.$seconds;
5533
}
5534
5535
/* FILE SYSTEM RELATED FUNCTIONS */
5536
5537
/**
5538
 * Returns the permissions to be assigned to every newly created directory by the web-server.
5539
 * The return value is based on the platform administrator's setting
5540
 * "Administration > Configuration settings > Security > Permissions for new directories".
5541
 *
5542
 * @return int returns the permissions in the format "Owner-Group-Others, Read-Write-Execute", as an integer value
5543
 */
5544
function api_get_permissions_for_new_directories()
5545
{
5546
    static $permissions;
5547
    if (!isset($permissions)) {
5548
        $permissions = trim(api_get_setting('permissions_for_new_directories'));
5549
        // The default value 0777 is according to that in the platform administration panel after fresh system installation.
5550
        $permissions = octdec(!empty($permissions) ? $permissions : '0777');
5551
    }
5552
5553
    return $permissions;
5554
}
5555
5556
/**
5557
 * Returns the permissions to be assigned to every newly created directory by the web-server.
5558
 * The return value is based on the platform administrator's setting
5559
 * "Administration > Configuration settings > Security > Permissions for new files".
5560
 *
5561
 * @return int returns the permissions in the format
5562
 *             "Owner-Group-Others, Read-Write-Execute", as an integer value
5563
 */
5564
function api_get_permissions_for_new_files()
5565
{
5566
    static $permissions;
5567
    if (!isset($permissions)) {
5568
        $permissions = trim(api_get_setting('permissions_for_new_files'));
5569
        // The default value 0666 is according to that in the platform
5570
        // administration panel after fresh system installation.
5571
        $permissions = octdec(!empty($permissions) ? $permissions : '0666');
5572
    }
5573
5574
    return $permissions;
5575
}
5576
5577
/**
5578
 * Deletes a file, or a folder and its contents.
5579
 *
5580
 * @author      Aidan Lister <[email protected]>
5581
 *
5582
 * @version     1.0.3
5583
 *
5584
 * @param string $dirname Directory to delete
5585
 * @param       bool     Deletes only the content or not
5586
 * @param bool $strict if one folder/file fails stop the loop
5587
 *
5588
 * @return bool Returns TRUE on success, FALSE on failure
5589
 *
5590
 * @see http://aidanlister.com/2004/04/recursively-deleting-a-folder-in-php/
5591
 *
5592
 * @author      Yannick Warnier, adaptation for the Chamilo LMS, April, 2008
5593
 * @author      Ivan Tcholakov, a sanity check about Directory class creation has been added, September, 2009
5594
 */
5595
function rmdirr($dirname, $delete_only_content_in_folder = false, $strict = false)
5596
{
5597
    $res = true;
5598
    // A sanity check.
5599
    if (!file_exists($dirname)) {
5600
        return false;
5601
    }
5602
    $php_errormsg = '';
5603
    // Simple delete for a file.
5604
    if (is_file($dirname) || is_link($dirname)) {
5605
        $res = unlink($dirname);
5606
        if ($res === false) {
5607
            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);
5608
        }
5609
5610
        return $res;
5611
    }
5612
5613
    // Loop through the folder.
5614
    $dir = dir($dirname);
5615
    // A sanity check.
5616
    $is_object_dir = is_object($dir);
5617
    if ($is_object_dir) {
5618
        while (false !== $entry = $dir->read()) {
5619
            // Skip pointers.
5620
            if ($entry == '.' || $entry == '..') {
5621
                continue;
5622
            }
5623
5624
            // Recurse.
5625
            if ($strict) {
5626
                $result = rmdirr("$dirname/$entry");
5627
                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...
5628
                    $res = false;
5629
                    break;
5630
                }
5631
            } else {
5632
                rmdirr("$dirname/$entry");
5633
            }
5634
        }
5635
    }
5636
5637
    // Clean up.
5638
    if ($is_object_dir) {
5639
        $dir->close();
5640
    }
5641
5642
    if ($delete_only_content_in_folder == false) {
5643
        $res = rmdir($dirname);
5644
        if ($res === false) {
5645
            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);
5646
        }
5647
    }
5648
5649
    return $res;
5650
}
5651
5652
// TODO: This function is to be simplified. File access modes to be implemented.
5653
/**
5654
 * function adapted from a php.net comment
5655
 * copy recursively a folder.
5656
 *
5657
 * @param string $source       the source folder
5658
 * @param string $dest         the dest folder
5659
 * @param array  $exclude      an array of excluded file_name (without extension)
5660
 * @param array  $copied_files the returned array of copied files
5661
 */
5662
function copyr($source, $dest, $exclude = [], $copied_files = [])
5663
{
5664
    if (empty($dest)) {
5665
        return false;
5666
    }
5667
    // Simple copy for a file
5668
    if (is_file($source)) {
5669
        $path_info = pathinfo($source);
5670
        if (!in_array($path_info['filename'], $exclude)) {
5671
            copy($source, $dest);
5672
        }
5673
5674
        return true;
5675
    } elseif (!is_dir($source)) {
5676
        //then source is not a dir nor a file, return
5677
        return false;
5678
    }
5679
5680
    // Make destination directory.
5681
    if (!is_dir($dest)) {
5682
        mkdir($dest, api_get_permissions_for_new_directories());
5683
    }
5684
5685
    // Loop through the folder.
5686
    $dir = dir($source);
5687
    while (false !== $entry = $dir->read()) {
5688
        // Skip pointers
5689
        if ($entry == '.' || $entry == '..') {
5690
            continue;
5691
        }
5692
5693
        // Deep copy directories.
5694
        if ($dest !== "$source/$entry") {
5695
            $files = copyr("$source/$entry", "$dest/$entry", $exclude, $copied_files);
5696
        }
5697
    }
5698
    // Clean up.
5699
    $dir->close();
5700
5701
    return true;
5702
}
5703
5704
/**
5705
 * @param string $pathname
5706
 * @param string $base_path_document
5707
 * @param int    $session_id
5708
 * @param array
5709
 * @param string
5710
 *
5711
 * @return mixed True if directory already exists, false if a file already exists at
5712
 *               the destination and null if everything goes according to plan
5713
 *@todo: Using DIRECTORY_SEPARATOR is not recommended, this is an obsolete approach.
5714
 * Documentation header to be added here.
5715
 */
5716
function copy_folder_course_session(
5717
    $pathname,
5718
    $base_path_document,
5719
    $session_id,
5720
    $course_info,
5721
    $document,
5722
    $source_course_id,
5723
    $originalFolderNameList = [],
5724
    $originalBaseName = ''
5725
) {
5726
    // Check whether directory already exists.
5727
    if (empty($pathname) || is_dir($pathname)) {
5728
        return true;
5729
    }
5730
5731
    // Ensure that a file with the same name does not already exist.
5732
    if (is_file($pathname)) {
5733
        trigger_error('copy_folder_course_session(): File exists', E_USER_WARNING);
5734
5735
        return false;
5736
    }
5737
5738
    //error_log('checking:');
5739
    //error_log(str_replace($base_path_document.DIRECTORY_SEPARATOR, '', $pathname));
5740
    $baseNoDocument = str_replace('document', '', $originalBaseName);
5741
    $folderTitles = explode('/', $baseNoDocument);
5742
    $folderTitles = array_filter($folderTitles);
5743
5744
    //error_log($baseNoDocument);error_log(print_r($folderTitles, 1));
5745
5746
    $table = Database::get_course_table(TABLE_DOCUMENT);
5747
    $session_id = (int) $session_id;
5748
    $source_course_id = (int) $source_course_id;
5749
    $course_id = $course_info['real_id'];
5750
    $folders = explode(DIRECTORY_SEPARATOR, str_replace($base_path_document.DIRECTORY_SEPARATOR, '', $pathname));
5751
    $new_pathname = $base_path_document;
5752
5753
    $path = '';
5754
    foreach ($folders as $index => $folder) {
5755
        $new_pathname .= DIRECTORY_SEPARATOR.$folder;
5756
        $path .= DIRECTORY_SEPARATOR.$folder;
5757
5758
        if (!file_exists($new_pathname)) {
5759
            $path = Database::escape_string($path);
5760
            //error_log("path: $path");
5761
            $sql = "SELECT * FROM $table
5762
                    WHERE
5763
                        c_id = $source_course_id AND
5764
                        path = '$path' AND
5765
                        filetype = 'folder' AND
5766
                        session_id = '$session_id'";
5767
            $rs1 = Database::query($sql);
5768
            $num_rows = Database::num_rows($rs1);
5769
5770
            if (0 == $num_rows) {
5771
                mkdir($new_pathname, api_get_permissions_for_new_directories());
5772
                $title = basename($new_pathname);
5773
5774
                if (isset($folderTitles[$index + 1])) {
5775
                    $checkPath = $folderTitles[$index + 1];
5776
                    //error_log("check $checkPath");
5777
                    if (isset($originalFolderNameList[$checkPath])) {
5778
                        $title = $originalFolderNameList[$checkPath];
5779
                        //error_log('use this name: '.$title);
5780
                    }
5781
                }
5782
5783
                // Insert new folder with destination session_id.
5784
                $params = [
5785
                    'c_id' => $course_id,
5786
                    'path' => $path,
5787
                    'comment' => $document->comment,
5788
                    'title' => $title,
5789
                    'filetype' => 'folder',
5790
                    'size' => '0',
5791
                    'session_id' => $session_id,
5792
                ];
5793
5794
                //error_log("old $folder"); error_log("Add doc $title in $path");
5795
                $document_id = Database::insert($table, $params);
5796
                if ($document_id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $document_id of type false|integer is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.

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

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

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

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
5797
                    $sql = "UPDATE $table SET id = iid WHERE iid = $document_id";
5798
                    Database::query($sql);
5799
5800
                    api_item_property_update(
5801
                        $course_info,
5802
                        TOOL_DOCUMENT,
5803
                        $document_id,
5804
                        'FolderCreated',
5805
                        api_get_user_id(),
5806
                        0,
5807
                        0,
5808
                        null,
5809
                        null,
5810
                        $session_id
5811
                    );
5812
                }
5813
            }
5814
        }
5815
    }
5816
}
5817
5818
// TODO: chmodr() is a better name. Some corrections are needed. Documentation header to be added here.
5819
/**
5820
 * @param string $path
5821
 */
5822
function api_chmod_R($path, $filemode)
5823
{
5824
    if (!is_dir($path)) {
5825
        return chmod($path, $filemode);
5826
    }
5827
5828
    $handler = opendir($path);
5829
    while ($file = readdir($handler)) {
5830
        if ($file != '.' && $file != '..') {
5831
            $fullpath = "$path/$file";
5832
            if (!is_dir($fullpath)) {
5833
                if (!chmod($fullpath, $filemode)) {
5834
                    return false;
5835
                }
5836
            } else {
5837
                if (!api_chmod_R($fullpath, $filemode)) {
5838
                    return false;
5839
                }
5840
            }
5841
        }
5842
    }
5843
5844
    closedir($handler);
5845
5846
    return chmod($path, $filemode);
5847
}
5848
5849
// TODO: Where the following function has been copy/pased from? There is no information about author and license. Style, coding conventions...
5850
/**
5851
 * Parse info file format. (e.g: file.info).
5852
 *
5853
 * Files should use an ini-like format to specify values.
5854
 * White-space generally doesn't matter, except inside values.
5855
 * e.g.
5856
 *
5857
 * @verbatim
5858
 *   key = value
5859
 *   key = "value"
5860
 *   key = 'value'
5861
 *   key = "multi-line
5862
 *
5863
 *   value"
5864
 *   key = 'multi-line
5865
 *
5866
 *   value'
5867
 *   key
5868
 *   =
5869
 *   'value'
5870
 * @endverbatim
5871
 *
5872
 * Arrays are created using a GET-like syntax:
5873
 *
5874
 * @verbatim
5875
 *   key[] = "numeric array"
5876
 *   key[index] = "associative array"
5877
 *   key[index][] = "nested numeric array"
5878
 *   key[index][index] = "nested associative array"
5879
 * @endverbatim
5880
 *
5881
 * PHP constants are substituted in, but only when used as the entire value:
5882
 *
5883
 * Comments should start with a semi-colon at the beginning of a line.
5884
 *
5885
 * This function is NOT for placing arbitrary module-specific settings. Use
5886
 * variable_get() and variable_set() for that.
5887
 *
5888
 * Information stored in the module.info file:
5889
 * - name: The real name of the module for display purposes.
5890
 * - description: A brief description of the module.
5891
 * - dependencies: An array of shortnames of other modules this module depends on.
5892
 * - package: The name of the package of modules this module belongs to.
5893
 *
5894
 * Example of .info file:
5895
 * <code>
5896
 * @verbatim
5897
 *   name = Forum
5898
 *   description = Enables threaded discussions about general topics.
5899
 *   dependencies[] = taxonomy
5900
 *   dependencies[] = comment
5901
 *   package = Core - optional
5902
 *   version = VERSION
5903
 * @endverbatim
5904
 * </code>
5905
 *
5906
 * @param string $filename
5907
 *                         The file we are parsing. Accepts file with relative or absolute path.
5908
 *
5909
 * @return
5910
 *   The info array
5911
 */
5912
function api_parse_info_file($filename)
5913
{
5914
    $info = [];
5915
5916
    if (!file_exists($filename)) {
5917
        return $info;
5918
    }
5919
5920
    $data = file_get_contents($filename);
5921
    if (preg_match_all('
5922
        @^\s*                           # Start at the beginning of a line, ignoring leading whitespace
5923
        ((?:
5924
          [^=;\[\]]|                    # Key names cannot contain equal signs, semi-colons or square brackets,
5925
          \[[^\[\]]*\]                  # unless they are balanced and not nested
5926
        )+?)
5927
        \s*=\s*                         # Key/value pairs are separated by equal signs (ignoring white-space)
5928
        (?:
5929
          ("(?:[^"]|(?<=\\\\)")*")|     # Double-quoted string, which may contain slash-escaped quotes/slashes
5930
          (\'(?:[^\']|(?<=\\\\)\')*\')| # Single-quoted string, which may contain slash-escaped quotes/slashes
5931
          ([^\r\n]*?)                   # Non-quoted string
5932
        )\s*$                           # Stop at the next end of a line, ignoring trailing whitespace
5933
        @msx', $data, $matches, PREG_SET_ORDER)) {
5934
        $key = $value1 = $value2 = $value3 = '';
5935
        foreach ($matches as $match) {
5936
            // Fetch the key and value string.
5937
            $i = 0;
5938
            foreach (['key', 'value1', 'value2', 'value3'] as $var) {
5939
                $$var = isset($match[++$i]) ? $match[$i] : '';
5940
            }
5941
            $value = stripslashes(substr($value1, 1, -1)).stripslashes(substr($value2, 1, -1)).$value3;
5942
5943
            // Parse array syntax.
5944
            $keys = preg_split('/\]?\[/', rtrim($key, ']'));
5945
            $last = array_pop($keys);
5946
            $parent = &$info;
5947
5948
            // Create nested arrays.
5949
            foreach ($keys as $key) {
5950
                if ($key == '') {
5951
                    $key = count($parent);
5952
                }
5953
                if (!isset($parent[$key]) || !is_array($parent[$key])) {
5954
                    $parent[$key] = [];
5955
                }
5956
                $parent = &$parent[$key];
5957
            }
5958
5959
            // Handle PHP constants.
5960
            if (defined($value)) {
5961
                $value = constant($value);
5962
            }
5963
5964
            // Insert actual value.
5965
            if ($last == '') {
5966
                $last = count($parent);
5967
            }
5968
            $parent[$last] = $value;
5969
        }
5970
    }
5971
5972
    return $info;
5973
}
5974
5975
/**
5976
 * Gets Chamilo version from the configuration files.
5977
 *
5978
 * @return string A string of type "1.8.4", or an empty string if the version could not be found
5979
 */
5980
function api_get_version()
5981
{
5982
    return (string) api_get_configuration_value('system_version');
5983
}
5984
5985
/**
5986
 * Gets the software name (the name/brand of the Chamilo-based customized system).
5987
 *
5988
 * @return string
5989
 */
5990
function api_get_software_name()
5991
{
5992
    $name = api_get_configuration_value('software_name');
5993
    if (!empty($name)) {
5994
        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...
5995
    } else {
5996
        return 'Chamilo';
5997
    }
5998
}
5999
6000
/**
6001
 * Checks whether status given in parameter exists in the platform.
6002
 *
6003
 * @param mixed the status (can be either int either string)
6004
 *
6005
 * @return bool if the status exists, else returns false
6006
 */
6007
function api_status_exists($status_asked)
6008
{
6009
    global $_status_list;
6010
6011
    return in_array($status_asked, $_status_list) ? true : isset($_status_list[$status_asked]);
6012
}
6013
6014
/**
6015
 * Checks whether status given in parameter exists in the platform. The function
6016
 * returns the status ID or false if it does not exist, but given the fact there
6017
 * is no "0" status, the return value can be checked against
6018
 * if(api_status_key()) to know if it exists.
6019
 *
6020
 * @param   mixed   The status (can be either int or string)
6021
 *
6022
 * @return mixed Status ID if exists, false otherwise
6023
 */
6024
function api_status_key($status)
6025
{
6026
    global $_status_list;
6027
6028
    return isset($_status_list[$status]) ? $status : array_search($status, $_status_list);
6029
}
6030
6031
/**
6032
 * Gets the status langvars list.
6033
 *
6034
 * @return string[] the list of status with their translations
6035
 */
6036
function api_get_status_langvars()
6037
{
6038
    return [
6039
        COURSEMANAGER => get_lang('Teacher', ''),
6040
        SESSIONADMIN => get_lang('SessionsAdmin', ''),
6041
        DRH => get_lang('Drh', ''),
6042
        STUDENT => get_lang('Student', ''),
6043
        ANONYMOUS => get_lang('Anonymous', ''),
6044
        STUDENT_BOSS => get_lang('RoleStudentBoss', ''),
6045
        INVITEE => get_lang('Invited'),
6046
    ];
6047
}
6048
6049
/**
6050
 * The function that retrieves all the possible settings for a certain config setting.
6051
 *
6052
 * @author Patrick Cool <[email protected]>, Ghent University
6053
 */
6054
function api_get_settings_options($var)
6055
{
6056
    $table_settings_options = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
6057
    $var = Database::escape_string($var);
6058
    $sql = "SELECT * FROM $table_settings_options
6059
            WHERE variable = '$var'
6060
            ORDER BY id";
6061
    $result = Database::query($sql);
6062
    $settings_options_array = [];
6063
    while ($row = Database::fetch_array($result, 'ASSOC')) {
6064
        $settings_options_array[] = $row;
6065
    }
6066
6067
    return $settings_options_array;
6068
}
6069
6070
/**
6071
 * @param array $params
6072
 */
6073
function api_set_setting_option($params)
6074
{
6075
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
6076
    if (empty($params['id'])) {
6077
        Database::insert($table, $params);
6078
    } else {
6079
        Database::update($table, $params, ['id = ? ' => $params['id']]);
6080
    }
6081
}
6082
6083
/**
6084
 * @param array $params
6085
 */
6086
function api_set_setting_simple($params)
6087
{
6088
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
6089
    $url_id = api_get_current_access_url_id();
6090
6091
    if (empty($params['id'])) {
6092
        $params['access_url'] = $url_id;
6093
        Database::insert($table, $params);
6094
    } else {
6095
        Database::update($table, $params, ['id = ? ' => [$params['id']]]);
6096
    }
6097
}
6098
6099
/**
6100
 * @param int $id
6101
 */
6102
function api_delete_setting_option($id)
6103
{
6104
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
6105
    if (!empty($id)) {
6106
        Database::delete($table, ['id = ? ' => $id]);
6107
    }
6108
}
6109
6110
/**
6111
 * Sets a platform configuration setting to a given value.
6112
 *
6113
 * @param string    The variable we want to update
6114
 * @param string    The value we want to record
6115
 * @param string    The sub-variable if any (in most cases, this will remain null)
6116
 * @param string    The category if any (in most cases, this will remain null)
6117
 * @param int       The access_url for which this parameter is valid
6118
 * @param string $cat
6119
 *
6120
 * @return bool|null
6121
 */
6122
function api_set_setting($var, $value, $subvar = null, $cat = null, $access_url = 1)
6123
{
6124
    if (empty($var)) {
6125
        return false;
6126
    }
6127
    $t_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
6128
    $var = Database::escape_string($var);
6129
    $value = Database::escape_string($value);
6130
    $access_url = (int) $access_url;
6131
    if (empty($access_url)) {
6132
        $access_url = 1;
6133
    }
6134
    $select = "SELECT id FROM $t_settings WHERE variable = '$var' ";
6135
    if (!empty($subvar)) {
6136
        $subvar = Database::escape_string($subvar);
6137
        $select .= " AND subkey = '$subvar'";
6138
    }
6139
    if (!empty($cat)) {
6140
        $cat = Database::escape_string($cat);
6141
        $select .= " AND category = '$cat'";
6142
    }
6143
    if ($access_url > 1) {
6144
        $select .= " AND access_url = $access_url";
6145
    } else {
6146
        $select .= " AND access_url = 1 ";
6147
    }
6148
6149
    $res = Database::query($select);
6150
    if (Database::num_rows($res) > 0) {
6151
        // Found item for this access_url.
6152
        $row = Database::fetch_array($res);
6153
        $sql = "UPDATE $t_settings SET selected_value = '$value'
6154
                WHERE id = ".$row['id'];
6155
        Database::query($sql);
6156
    } else {
6157
        // Item not found for this access_url, we have to check if it exist with access_url = 1
6158
        $select = "SELECT * FROM $t_settings
6159
                   WHERE variable = '$var' AND access_url = 1 ";
6160
        // Just in case
6161
        if ($access_url == 1) {
6162
            if (!empty($subvar)) {
6163
                $select .= " AND subkey = '$subvar'";
6164
            }
6165
            if (!empty($cat)) {
6166
                $select .= " AND category = '$cat'";
6167
            }
6168
            $res = Database::query($select);
6169
            if (Database::num_rows($res) > 0) {
6170
                // We have a setting for access_url 1, but none for the current one, so create one.
6171
                $row = Database::fetch_array($res);
6172
                $insert = "INSERT INTO $t_settings (variable, subkey, type,category, selected_value, title, comment, scope, subkeytext, access_url)
6173
                        VALUES
6174
                        ('".$row['variable']."',".(!empty($row['subkey']) ? "'".$row['subkey']."'" : "NULL").",".
6175
                        "'".$row['type']."','".$row['category']."',".
6176
                        "'$value','".$row['title']."',".
6177
                        "".(!empty($row['comment']) ? "'".$row['comment']."'" : "NULL").",".(!empty($row['scope']) ? "'".$row['scope']."'" : "NULL").",".
6178
                        "".(!empty($row['subkeytext']) ? "'".$row['subkeytext']."'" : "NULL").",$access_url)";
6179
                Database::query($insert);
6180
            } else {
6181
                // Such a setting does not exist.
6182
                //error_log(__FILE__.':'.__LINE__.': Attempting to update setting '.$var.' ('.$subvar.') which does not exist at all', 0);
6183
            }
6184
        } else {
6185
            // Other access url.
6186
            if (!empty($subvar)) {
6187
                $select .= " AND subkey = '$subvar'";
6188
            }
6189
            if (!empty($cat)) {
6190
                $select .= " AND category = '$cat'";
6191
            }
6192
            $res = Database::query($select);
6193
6194
            if (Database::num_rows($res) > 0) {
6195
                // We have a setting for access_url 1, but none for the current one, so create one.
6196
                $row = Database::fetch_array($res);
6197
                if ($row['access_url_changeable'] == 1) {
6198
                    $insert = "INSERT INTO $t_settings (variable,subkey, type,category, selected_value,title, comment,scope, subkeytext,access_url, access_url_changeable) VALUES
6199
                            ('".$row['variable']."',".
6200
                            (!empty($row['subkey']) ? "'".$row['subkey']."'" : "NULL").",".
6201
                            "'".$row['type']."','".$row['category']."',".
6202
                            "'$value','".$row['title']."',".
6203
                            "".(!empty($row['comment']) ? "'".$row['comment']."'" : "NULL").",".
6204
                            (!empty($row['scope']) ? "'".$row['scope']."'" : "NULL").",".
6205
                            "".(!empty($row['subkeytext']) ? "'".$row['subkeytext']."'" : "NULL").",$access_url,".$row['access_url_changeable'].")";
6206
                    Database::query($insert);
6207
                }
6208
            } else { // Such a setting does not exist.
6209
                //error_log(__FILE__.':'.__LINE__.': Attempting to update setting '.$var.' ('.$subvar.') which does not exist at all. The access_url is: '.$access_url.' ',0);
6210
            }
6211
        }
6212
    }
6213
}
6214
6215
/**
6216
 * Sets a whole category of settings to one specific value.
6217
 *
6218
 * @param string    Category
6219
 * @param string    Value
6220
 * @param int       Access URL. Optional. Defaults to 1
6221
 * @param array     Optional array of filters on field type
6222
 * @param string $category
6223
 * @param string $value
6224
 *
6225
 * @return bool
6226
 */
6227
function api_set_settings_category($category, $value = null, $access_url = 1, $fieldtype = [])
6228
{
6229
    if (empty($category)) {
6230
        return false;
6231
    }
6232
    $category = Database::escape_string($category);
6233
    $t_s = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
6234
    $access_url = (int) $access_url;
6235
    if (empty($access_url)) {
6236
        $access_url = 1;
6237
    }
6238
    if (isset($value)) {
6239
        $value = Database::escape_string($value);
6240
        $sql = "UPDATE $t_s SET selected_value = '$value'
6241
                WHERE category = '$category' AND access_url = $access_url";
6242
        if (is_array($fieldtype) && count($fieldtype) > 0) {
6243
            $sql .= " AND ( ";
6244
            $i = 0;
6245
            foreach ($fieldtype as $type) {
6246
                if ($i > 0) {
6247
                    $sql .= ' OR ';
6248
                }
6249
                $type = Database::escape_string($type);
6250
                $sql .= " type='".$type."' ";
6251
                $i++;
6252
            }
6253
            $sql .= ")";
6254
        }
6255
        $res = Database::query($sql);
6256
6257
        return $res !== false;
6258
    } else {
6259
        $sql = "UPDATE $t_s SET selected_value = NULL
6260
                WHERE category = '$category' AND access_url = $access_url";
6261
        if (is_array($fieldtype) && count($fieldtype) > 0) {
6262
            $sql .= " AND ( ";
6263
            $i = 0;
6264
            foreach ($fieldtype as $type) {
6265
                if ($i > 0) {
6266
                    $sql .= ' OR ';
6267
                }
6268
                $type = Database::escape_string($type);
6269
                $sql .= " type='".$type."' ";
6270
                $i++;
6271
            }
6272
            $sql .= ")";
6273
        }
6274
        $res = Database::query($sql);
6275
6276
        return $res !== false;
6277
    }
6278
}
6279
6280
/**
6281
 * Gets all available access urls in an array (as in the database).
6282
 *
6283
 * @return array An array of database records
6284
 */
6285
function api_get_access_urls($from = 0, $to = 1000000, $order = 'url', $direction = 'ASC')
6286
{
6287
    $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
6288
    $from = (int) $from;
6289
    $to = (int) $to;
6290
    $order = Database::escape_string($order);
6291
    $direction = Database::escape_string($direction);
6292
    $direction = !in_array(strtolower(trim($direction)), ['asc', 'desc']) ? 'asc' : $direction;
6293
6294
    $sql = "SELECT id, url, description, active, created_by, tms
6295
            FROM $table
6296
            ORDER BY `$order` $direction
6297
            LIMIT $to OFFSET $from";
6298
    $res = Database::query($sql);
6299
6300
    return Database::store_result($res);
6301
}
6302
6303
/**
6304
 * Gets the access url info in an array.
6305
 *
6306
 * @param int  $id            Id of the access url
6307
 * @param bool $returnDefault Set to false if you want the real URL if URL 1 is still 'http://localhost/'
6308
 *
6309
 * @return array All the info (url, description, active, created_by, tms)
6310
 *               from the access_url table
6311
 *
6312
 * @author Julio Montoya
6313
 */
6314
function api_get_access_url($id, $returnDefault = true)
6315
{
6316
    static $staticResult;
6317
    $id = (int) $id;
6318
6319
    if (isset($staticResult[$id])) {
6320
        $result = $staticResult[$id];
6321
    } else {
6322
        // Calling the Database:: library dont work this is handmade.
6323
        $table_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
6324
        $sql = "SELECT url, description, active, created_by, tms
6325
                FROM $table_access_url WHERE id = '$id' ";
6326
        $res = Database::query($sql);
6327
        $result = @Database::fetch_array($res);
6328
        $staticResult[$id] = $result;
6329
    }
6330
6331
    // If the result url is 'http://localhost/' (the default) and the root_web
6332
    // (=current url) is different, and the $id is = 1 (which might mean
6333
    // api_get_current_access_url_id() returned 1 by default), then return the
6334
    // root_web setting instead of the current URL
6335
    // This is provided as an option to avoid breaking the storage of URL-specific
6336
    // homepages in home/localhost/
6337
    if ($id === 1 && $returnDefault === false) {
6338
        $currentUrl = api_get_current_access_url_id();
6339
        // only do this if we are on the main URL (=1), otherwise we could get
6340
        // information on another URL instead of the one asked as parameter
6341
        if ($currentUrl === 1) {
6342
            $rootWeb = api_get_path(WEB_PATH);
6343
            $default = 'http://localhost/';
6344
            if ($result['url'] === $default && $rootWeb != $default) {
6345
                $result['url'] = $rootWeb;
6346
            }
6347
        }
6348
    }
6349
6350
    return $result;
6351
}
6352
6353
/**
6354
 * Gets all the current settings for a specific access url.
6355
 *
6356
 * @param string    The category, if any, that we want to get
6357
 * @param string    Whether we want a simple list (display a category) or
6358
 * a grouped list (group by variable as in settings.php default). Values: 'list' or 'group'
6359
 * @param int       Access URL's ID. Optional. Uses 1 by default, which is the unique URL
6360
 *
6361
 * @return array Array of database results for the current settings of the current access URL
6362
 */
6363
function &api_get_settings($cat = null, $ordering = 'list', $access_url = 1, $url_changeable = 0)
6364
{
6365
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
6366
    $access_url = (int) $access_url;
6367
    $where_condition = '';
6368
    if ($url_changeable == 1) {
6369
        $where_condition = " AND access_url_changeable= '1' ";
6370
    }
6371
    if (empty($access_url) || $access_url == -1) {
6372
        $access_url = 1;
6373
    }
6374
    $sql = "SELECT * FROM $table
6375
            WHERE access_url = $access_url  $where_condition ";
6376
6377
    if (!empty($cat)) {
6378
        $cat = Database::escape_string($cat);
6379
        $sql .= " AND category='$cat' ";
6380
    }
6381
    if ($ordering == 'group') {
6382
        $sql .= " ORDER BY id ASC";
6383
    } else {
6384
        $sql .= " ORDER BY 1,2 ASC";
6385
    }
6386
    $result = Database::query($sql);
6387
    if ($result === null) {
6388
        return [];
6389
    }
6390
    $result = Database::store_result($result, 'ASSOC');
6391
6392
    return $result;
6393
}
6394
6395
/**
6396
 * @param string $value       The value we want to record
6397
 * @param string $variable    The variable name we want to insert
6398
 * @param string $subKey      The subkey for the variable we want to insert
6399
 * @param string $type        The type for the variable we want to insert
6400
 * @param string $category    The category for the variable we want to insert
6401
 * @param string $title       The title
6402
 * @param string $comment     The comment
6403
 * @param string $scope       The scope
6404
 * @param string $subKeyText  The subkey text
6405
 * @param int    $accessUrlId The access_url for which this parameter is valid
6406
 * @param int    $visibility  The changeability of this setting for non-master urls
6407
 *
6408
 * @return int The setting ID
6409
 */
6410
function api_add_setting(
6411
    $value,
6412
    $variable,
6413
    $subKey = '',
6414
    $type = 'textfield',
6415
    $category = '',
6416
    $title = '',
6417
    $comment = '',
6418
    $scope = '',
6419
    $subKeyText = '',
6420
    $accessUrlId = 1,
6421
    $visibility = 0
6422
) {
6423
    $em = Database::getManager();
6424
    $settingRepo = $em->getRepository('ChamiloCoreBundle:SettingsCurrent');
6425
    $accessUrlId = (int) $accessUrlId ?: 1;
6426
6427
    if (is_array($value)) {
6428
        $value = serialize($value);
6429
    } else {
6430
        $value = trim($value);
6431
    }
6432
6433
    $criteria = ['variable' => $variable, 'accessUrl' => $accessUrlId];
6434
6435
    if (!empty($subKey)) {
6436
        $criteria['subkey'] = $subKey;
6437
    }
6438
6439
    // Check if this variable doesn't exist already
6440
    /** @var SettingsCurrent $setting */
6441
    $setting = $settingRepo->findOneBy($criteria);
6442
6443
    if ($setting) {
0 ignored issues
show
introduced by
$setting is of type Chamilo\CoreBundle\Entity\SettingsCurrent, thus it always evaluated to true.
Loading history...
6444
        $setting->setSelectedValue($value);
6445
6446
        $em->persist($setting);
6447
        $em->flush();
6448
6449
        return $setting->getId();
6450
    }
6451
6452
    // Item not found for this access_url, we have to check if the whole thing is missing
6453
    // (in which case we ignore the insert) or if there *is* a record but just for access_url = 1
6454
    $setting = new SettingsCurrent();
6455
    $setting
6456
        ->setVariable($variable)
6457
        ->setSelectedValue($value)
6458
        ->setType($type)
6459
        ->setCategory($category)
6460
        ->setSubkey($subKey)
6461
        ->setTitle($title)
6462
        ->setComment($comment)
6463
        ->setScope($scope)
6464
        ->setSubkeytext($subKeyText)
6465
        ->setAccessUrl($accessUrlId)
6466
        ->setAccessUrlChangeable($visibility);
6467
6468
    $em->persist($setting);
6469
    $em->flush();
6470
6471
    return $setting->getId();
6472
}
6473
6474
/**
6475
 * Checks wether a user can or can't view the contents of a course.
6476
 *
6477
 * @deprecated use CourseManager::is_user_subscribed_in_course
6478
 *
6479
 * @param int $userid User id or NULL to get it from $_SESSION
6480
 * @param int $cid    course id to check whether the user is allowed
6481
 *
6482
 * @return bool
6483
 */
6484
function api_is_course_visible_for_user($userid = null, $cid = null)
6485
{
6486
    if ($userid === null) {
6487
        $userid = api_get_user_id();
6488
    }
6489
    if (empty($userid) || strval(intval($userid)) != $userid) {
6490
        if (api_is_anonymous()) {
6491
            $userid = api_get_anonymous_id();
6492
        } else {
6493
            return false;
6494
        }
6495
    }
6496
    $cid = Database::escape_string($cid);
6497
6498
    $courseInfo = api_get_course_info($cid);
6499
    $courseId = $courseInfo['real_id'];
6500
    $is_platformAdmin = api_is_platform_admin();
6501
6502
    $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
6503
    $course_cat_table = Database::get_main_table(TABLE_MAIN_CATEGORY);
6504
6505
    $sql = "SELECT
6506
                $course_table.category_code,
6507
                $course_table.visibility,
6508
                $course_table.code,
6509
                $course_cat_table.code
6510
            FROM $course_table
6511
            LEFT JOIN $course_cat_table
6512
                ON $course_table.category_code = $course_cat_table.code
6513
            WHERE
6514
                $course_table.code = '$cid'
6515
            LIMIT 1";
6516
6517
    $result = Database::query($sql);
6518
6519
    if (Database::num_rows($result) > 0) {
6520
        $visibility = Database::fetch_array($result);
6521
        $visibility = $visibility['visibility'];
6522
    } else {
6523
        $visibility = 0;
6524
    }
6525
    // Shortcut permissions in case the visibility is "open to the world".
6526
    if ($visibility === COURSE_VISIBILITY_OPEN_WORLD) {
6527
        return true;
6528
    }
6529
6530
    $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
6531
6532
    $sql = "SELECT
6533
                is_tutor, status
6534
            FROM $tbl_course_user
6535
            WHERE
6536
                user_id  = '$userid' AND
6537
                relation_type <> '".COURSE_RELATION_TYPE_RRHH."' AND
6538
                c_id = $courseId
6539
            LIMIT 1";
6540
6541
    $result = Database::query($sql);
6542
6543
    if (Database::num_rows($result) > 0) {
6544
        // This user has got a recorded state for this course.
6545
        $cuData = Database::fetch_array($result);
6546
        $is_courseMember = true;
6547
        $is_courseAdmin = ($cuData['status'] == 1);
6548
    }
6549
6550
    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...
6551
        // This user has no status related to this course.
6552
        // Is it the session coach or the session admin?
6553
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
6554
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
6555
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
6556
6557
        $sql = "SELECT
6558
                    session.id_coach, session_admin_id, session.id
6559
                FROM
6560
                    $tbl_session as session
6561
                INNER JOIN $tbl_session_course
6562
                    ON session_rel_course.session_id = session.id
6563
                    AND session_rel_course.c_id = '$courseId'
6564
                LIMIT 1";
6565
6566
        $result = Database::query($sql);
6567
        $row = Database::store_result($result);
6568
6569
        if ($row[0]['id_coach'] == $userid) {
6570
            $is_courseMember = true;
6571
            $is_courseAdmin = false;
6572
        } elseif ($row[0]['session_admin_id'] == $userid) {
6573
            $is_courseMember = false;
6574
            $is_courseAdmin = false;
6575
        } else {
6576
            // Check if the current user is the course coach.
6577
            $sql = "SELECT 1
6578
                    FROM $tbl_session_course
6579
                    WHERE session_rel_course.c_id = '$courseId'
6580
                    AND session_rel_course.id_coach = '$userid'
6581
                    LIMIT 1";
6582
6583
            $result = Database::query($sql);
6584
6585
            //if ($row = Database::fetch_array($result)) {
6586
            if (Database::num_rows($result) > 0) {
6587
                $is_courseMember = true;
6588
                $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
6589
6590
                $sql = "SELECT status FROM $tbl_user
6591
                        WHERE user_id = $userid
6592
                        LIMIT 1";
6593
6594
                $result = Database::query($sql);
6595
6596
                if (Database::result($result, 0, 0) == 1) {
6597
                    $is_courseAdmin = true;
6598
                } else {
6599
                    $is_courseAdmin = false;
6600
                }
6601
            } else {
6602
                // Check if the user is a student is this session.
6603
                $sql = "SELECT  id
6604
                        FROM $tbl_session_course_user
6605
                        WHERE
6606
                            user_id  = '$userid' AND
6607
                            c_id = '$courseId'
6608
                        LIMIT 1";
6609
6610
                if (Database::num_rows($result) > 0) {
6611
                    // This user haa got a recorded state for this course.
6612
                    while ($row = Database::fetch_array($result)) {
6613
                        $is_courseMember = true;
6614
                        $is_courseAdmin = false;
6615
                    }
6616
                }
6617
            }
6618
        }
6619
    }
6620
6621
    switch ($visibility) {
6622
        case COURSE_VISIBILITY_OPEN_WORLD:
6623
            return true;
6624
        case COURSE_VISIBILITY_OPEN_PLATFORM:
6625
            return isset($userid);
6626
        case COURSE_VISIBILITY_REGISTERED:
6627
        case COURSE_VISIBILITY_CLOSED:
6628
            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...
6629
        case COURSE_VISIBILITY_HIDDEN:
6630
            return $is_platformAdmin;
6631
    }
6632
6633
    return false;
6634
}
6635
6636
/**
6637
 * Returns whether an element (forum, message, survey ...) belongs to a session or not.
6638
 *
6639
 * @param string the tool of the element
6640
 * @param int the element id in database
6641
 * @param int the session_id to compare with element session id
6642
 *
6643
 * @return bool true if the element is in the session, false else
6644
 */
6645
function api_is_element_in_the_session($tool, $element_id, $session_id = null)
6646
{
6647
    if (is_null($session_id)) {
6648
        $session_id = api_get_session_id();
6649
    }
6650
6651
    $element_id = (int) $element_id;
6652
6653
    if (empty($element_id)) {
6654
        return false;
6655
    }
6656
6657
    // Get information to build query depending of the tool.
6658
    switch ($tool) {
6659
        case TOOL_SURVEY:
6660
            $table_tool = Database::get_course_table(TABLE_SURVEY);
6661
            $key_field = 'survey_id';
6662
            break;
6663
        case TOOL_ANNOUNCEMENT:
6664
            $table_tool = Database::get_course_table(TABLE_ANNOUNCEMENT);
6665
            $key_field = 'id';
6666
            break;
6667
        case TOOL_AGENDA:
6668
            $table_tool = Database::get_course_table(TABLE_AGENDA);
6669
            $key_field = 'id';
6670
            break;
6671
        case TOOL_GROUP:
6672
            $table_tool = Database::get_course_table(TABLE_GROUP);
6673
            $key_field = 'id';
6674
            break;
6675
        default:
6676
            return false;
6677
    }
6678
    $course_id = api_get_course_int_id();
6679
6680
    $sql = "SELECT session_id FROM $table_tool
6681
            WHERE c_id = $course_id AND $key_field =  ".$element_id;
6682
    $rs = Database::query($sql);
6683
    if ($element_session_id = Database::result($rs, 0, 0)) {
6684
        if ($element_session_id == intval($session_id)) {
6685
            // The element belongs to the session.
6686
            return true;
6687
        }
6688
    }
6689
6690
    return false;
6691
}
6692
6693
/**
6694
 * Replaces "forbidden" characters in a filename string.
6695
 *
6696
 * @param string $filename
6697
 * @param bool   $treat_spaces_as_hyphens
6698
 *
6699
 * @return string
6700
 */
6701
function api_replace_dangerous_char($filename, $treat_spaces_as_hyphens = true)
6702
{
6703
    // Some non-properly encoded file names can cause the whole file to be
6704
    // skipped when uploaded. Avoid this by detecting the encoding and
6705
    // converting to UTF-8, setting the source as ASCII (a reasonably
6706
    // limited characters set) if nothing could be found (BT#
6707
    $encoding = api_detect_encoding($filename);
6708
    if (empty($encoding)) {
6709
        $encoding = 'ASCII';
6710
        if (!api_is_valid_ascii($filename)) {
6711
            // try iconv and try non standard ASCII a.k.a CP437
6712
            // see BT#15022
6713
            if (function_exists('iconv')) {
6714
                $result = iconv('CP437', 'UTF-8', $filename);
6715
                if (api_is_valid_utf8($result)) {
6716
                    $filename = $result;
6717
                    $encoding = 'UTF-8';
6718
                }
6719
            }
6720
        }
6721
    }
6722
6723
    $filename = api_to_system_encoding($filename, $encoding);
6724
6725
    $url = URLify::filter(
6726
        $filename,
6727
        250,
6728
        '',
6729
        true,
6730
        false,
6731
        false,
6732
        false,
6733
        $treat_spaces_as_hyphens
6734
    );
6735
6736
    // Replace multiple dots at the end.
6737
    $regex = "/\.+$/";
6738
    $url = preg_replace($regex, '', $url);
6739
6740
    return $url;
6741
}
6742
6743
/**
6744
 * Fixes the $_SERVER['REQUEST_URI'] that is empty in IIS6.
6745
 *
6746
 * @author Ivan Tcholakov, 28-JUN-2006.
6747
 */
6748
function api_request_uri()
6749
{
6750
    if (!empty($_SERVER['REQUEST_URI'])) {
6751
        return $_SERVER['REQUEST_URI'];
6752
    }
6753
    $uri = $_SERVER['SCRIPT_NAME'];
6754
    if (!empty($_SERVER['QUERY_STRING'])) {
6755
        $uri .= '?'.$_SERVER['QUERY_STRING'];
6756
    }
6757
    $_SERVER['REQUEST_URI'] = $uri;
6758
6759
    return $uri;
6760
}
6761
6762
/**
6763
 * Gets the current access_url id of the Chamilo Platform.
6764
 *
6765
 * @return int access_url_id of the current Chamilo Installation or 1 if multiple_access_urls is not enabled
6766
 *
6767
 * @author Julio Montoya <[email protected]>
6768
 */
6769
function api_get_current_access_url_id()
6770
{
6771
    if ('cli' === PHP_SAPI) {
6772
        $accessUrlId = api_get_configuration_value('access_url');
6773
        if (!empty($accessUrlId)) {
6774
            return $accessUrlId;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $accessUrlId also could return the type boolean which is incompatible with the documented return type integer.
Loading history...
6775
        }
6776
    }
6777
6778
    static $id;
6779
    if (!empty($id)) {
6780
        return (int) $id;
6781
    }
6782
6783
    if (!api_get_multiple_access_url()) {
6784
        // If the feature is not enabled, assume 1 and return before querying
6785
        // the database
6786
        return 1;
6787
    }
6788
6789
    $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
6790
    $path = Database::escape_string(api_get_path(WEB_PATH));
6791
    $sql = "SELECT id FROM $table WHERE url = '".$path."'";
6792
    $result = Database::query($sql);
6793
    if (Database::num_rows($result) > 0) {
6794
        $id = Database::result($result, 0, 0);
6795
        if ($id === false) {
6796
            return -1;
6797
        }
6798
6799
        return (int) $id;
6800
    }
6801
6802
    $id = 1;
6803
6804
    //if the url in WEB_PATH was not found, it can only mean that there is
6805
    // either a configuration problem or the first URL has not been defined yet
6806
    // (by default it is http://localhost/). Thus the more sensible thing we can
6807
    // do is return 1 (the main URL) as the user cannot hack this value anyway
6808
    return 1;
6809
}
6810
6811
/**
6812
 * Gets the registered urls from a given user id.
6813
 *
6814
 * @param int $user_id
6815
 *
6816
 * @return array
6817
 *
6818
 * @author Julio Montoya <[email protected]>
6819
 */
6820
function api_get_access_url_from_user($user_id)
6821
{
6822
    $user_id = (int) $user_id;
6823
    $table_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
6824
    $table_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
6825
    $sql = "SELECT access_url_id
6826
            FROM $table_url_rel_user url_rel_user
6827
            INNER JOIN $table_url u
6828
            ON (url_rel_user.access_url_id = u.id)
6829
            WHERE user_id = ".intval($user_id);
6830
    $result = Database::query($sql);
6831
    $list = [];
6832
    while ($row = Database::fetch_array($result, 'ASSOC')) {
6833
        $list[] = $row['access_url_id'];
6834
    }
6835
6836
    return $list;
6837
}
6838
6839
/**
6840
 * Gets the status of a user in a course.
6841
 *
6842
 * @param int $user_id
6843
 * @param int $courseId
6844
 *
6845
 * @return int user status
6846
 */
6847
function api_get_status_of_user_in_course($user_id, $courseId)
6848
{
6849
    $tbl_rel_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
6850
    if (!empty($user_id) && !empty($courseId)) {
6851
        $user_id = intval($user_id);
6852
        $courseId = intval($courseId);
6853
        $sql = 'SELECT status
6854
                FROM '.$tbl_rel_course_user.'
6855
                WHERE user_id='.$user_id.' AND c_id = '.$courseId;
6856
        $result = Database::query($sql);
6857
        $row_status = Database::fetch_array($result, 'ASSOC');
6858
6859
        return $row_status['status'];
6860
    } else {
6861
        return 0;
6862
    }
6863
}
6864
6865
/**
6866
 * Checks whether the curent user is in a group or not.
6867
 *
6868
 * @param string        The group id - optional (takes it from session if not given)
6869
 * @param string        The course code - optional (no additional check by course if course code is not given)
6870
 *
6871
 * @return bool
6872
 *
6873
 * @author Ivan Tcholakov
6874
 */
6875
function api_is_in_group($groupIdParam = null, $courseCodeParam = null)
6876
{
6877
    if (!empty($courseCodeParam)) {
6878
        $courseCode = api_get_course_id();
6879
        if (!empty($courseCode)) {
6880
            if ($courseCodeParam != $courseCode) {
6881
                return false;
6882
            }
6883
        } else {
6884
            return false;
6885
        }
6886
    }
6887
6888
    $groupId = api_get_group_id();
6889
6890
    if (!empty($groupId)) {
6891
        if (!empty($groupIdParam)) {
6892
            return $groupIdParam == $groupId;
6893
        } else {
6894
            return true;
6895
        }
6896
    }
6897
6898
    return false;
6899
}
6900
6901
/**
6902
 * Checks whether a secret key is valid.
6903
 *
6904
 * @param string $original_key_secret - secret key from (webservice) client
6905
 * @param string $security_key        - security key from Chamilo
6906
 *
6907
 * @return bool - true if secret key is valid, false otherwise
6908
 */
6909
function api_is_valid_secret_key($original_key_secret, $security_key)
6910
{
6911
    if (empty($original_key_secret) || empty($security_key)) {
6912
        return false;
6913
    }
6914
6915
    return (string) $original_key_secret === sha1($security_key);
6916
}
6917
6918
/**
6919
 * Checks whether a user is into course.
6920
 *
6921
 * @param int $course_id - the course id
6922
 * @param int $user_id   - the user id
6923
 *
6924
 * @return bool
6925
 */
6926
function api_is_user_of_course($course_id, $user_id)
6927
{
6928
    $tbl_course_rel_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
6929
    $sql = 'SELECT user_id FROM '.$tbl_course_rel_user.'
6930
            WHERE
6931
                c_id ="'.intval($course_id).'" AND
6932
                user_id = "'.intval($user_id).'" AND
6933
                relation_type <> '.COURSE_RELATION_TYPE_RRHH.' ';
6934
    $result = Database::query($sql);
6935
6936
    return Database::num_rows($result) == 1;
6937
}
6938
6939
/**
6940
 * Checks whether the server's operating system is Windows (TM).
6941
 *
6942
 * @return bool - true if the operating system is Windows, false otherwise
6943
 */
6944
function api_is_windows_os()
6945
{
6946
    if (function_exists('php_uname')) {
6947
        // php_uname() exists as of PHP 4.0.2, according to the documentation.
6948
        // We expect that this function will always work for Chamilo 1.8.x.
6949
        $os = php_uname();
6950
    }
6951
    // The following methods are not needed, but let them stay, just in case.
6952
    elseif (isset($_ENV['OS'])) {
6953
        // Sometimes $_ENV['OS'] may not be present (bugs?)
6954
        $os = $_ENV['OS'];
6955
    } elseif (defined('PHP_OS')) {
6956
        // PHP_OS means on which OS PHP was compiled, this is why
6957
        // using PHP_OS is the last choice for detection.
6958
        $os = PHP_OS;
6959
    } else {
6960
        return false;
6961
    }
6962
6963
    return strtolower(substr((string) $os, 0, 3)) == 'win';
6964
}
6965
6966
/**
6967
 * This function informs whether the sent request is XMLHttpRequest.
6968
 */
6969
function api_is_xml_http_request()
6970
{
6971
    return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest';
6972
}
6973
6974
/**
6975
 * This wrapper function has been implemented for avoiding some known problems about the function getimagesize().
6976
 *
6977
 * @see http://php.net/manual/en/function.getimagesize.php
6978
 * @see http://www.dokeos.com/forum/viewtopic.php?t=12345
6979
 * @see http://www.dokeos.com/forum/viewtopic.php?t=16355
6980
 *
6981
 * @return int
6982
 */
6983
function api_getimagesize($path)
6984
{
6985
    $image = new Image($path);
6986
6987
    return $image->get_image_size();
6988
}
6989
6990
/**
6991
 * This function resizes an image, with preserving its proportions (or aspect ratio).
6992
 *
6993
 * @author Ivan Tcholakov, MAY-2009.
6994
 *
6995
 * @param int $image         System path or URL of the image
6996
 * @param int $target_width  Targeted width
6997
 * @param int $target_height Targeted height
6998
 *
6999
 * @return array Calculated new width and height
7000
 */
7001
function api_resize_image($image, $target_width, $target_height)
7002
{
7003
    $image_properties = api_getimagesize($image);
7004
7005
    return api_calculate_image_size(
7006
        $image_properties['width'],
7007
        $image_properties['height'],
7008
        $target_width,
7009
        $target_height
7010
    );
7011
}
7012
7013
/**
7014
 * This function calculates new image size, with preserving image's proportions (or aspect ratio).
7015
 *
7016
 * @author Ivan Tcholakov, MAY-2009.
7017
 * @author The initial idea has been taken from code by Patrick Cool, MAY-2004.
7018
 *
7019
 * @param int $image_width   Initial width
7020
 * @param int $image_height  Initial height
7021
 * @param int $target_width  Targeted width
7022
 * @param int $target_height Targeted height
7023
 *
7024
 * @return array Calculated new width and height
7025
 */
7026
function api_calculate_image_size(
7027
    $image_width,
7028
    $image_height,
7029
    $target_width,
7030
    $target_height
7031
) {
7032
    // Only maths is here.
7033
    $result = ['width' => $image_width, 'height' => $image_height];
7034
    if ($image_width <= 0 || $image_height <= 0) {
7035
        return $result;
7036
    }
7037
    $resize_factor_width = $target_width / $image_width;
7038
    $resize_factor_height = $target_height / $image_height;
7039
    $delta_width = $target_width - $image_width * $resize_factor_height;
7040
    $delta_height = $target_height - $image_height * $resize_factor_width;
7041
    if ($delta_width > $delta_height) {
7042
        $result['width'] = ceil($image_width * $resize_factor_height);
7043
        $result['height'] = ceil($image_height * $resize_factor_height);
7044
    } elseif ($delta_width < $delta_height) {
7045
        $result['width'] = ceil($image_width * $resize_factor_width);
7046
        $result['height'] = ceil($image_height * $resize_factor_width);
7047
    } else {
7048
        $result['width'] = ceil($target_width);
7049
        $result['height'] = ceil($target_height);
7050
    }
7051
7052
    return $result;
7053
}
7054
7055
/**
7056
 * Returns a list of Chamilo's tools or
7057
 * checks whether a given identificator is a valid Chamilo's tool.
7058
 *
7059
 * @author Isaac flores paz
7060
 *
7061
 * @param string The tool name to filter
7062
 *
7063
 * @return mixed Filtered string or array
7064
 */
7065
function api_get_tools_lists($my_tool = null)
7066
{
7067
    $tools_list = [
7068
        TOOL_DOCUMENT,
7069
        TOOL_THUMBNAIL,
7070
        TOOL_HOTPOTATOES,
7071
        TOOL_CALENDAR_EVENT,
7072
        TOOL_LINK,
7073
        TOOL_COURSE_DESCRIPTION,
7074
        TOOL_SEARCH,
7075
        TOOL_LEARNPATH,
7076
        TOOL_ANNOUNCEMENT,
7077
        TOOL_FORUM,
7078
        TOOL_THREAD,
7079
        TOOL_POST,
7080
        TOOL_DROPBOX,
7081
        TOOL_QUIZ,
7082
        TOOL_USER,
7083
        TOOL_GROUP,
7084
        TOOL_BLOGS,
7085
        TOOL_CHAT,
7086
        TOOL_STUDENTPUBLICATION,
7087
        TOOL_TRACKING,
7088
        TOOL_HOMEPAGE_LINK,
7089
        TOOL_COURSE_SETTING,
7090
        TOOL_BACKUP,
7091
        TOOL_COPY_COURSE_CONTENT,
7092
        TOOL_RECYCLE_COURSE,
7093
        TOOL_COURSE_HOMEPAGE,
7094
        TOOL_COURSE_RIGHTS_OVERVIEW,
7095
        TOOL_UPLOAD,
7096
        TOOL_COURSE_MAINTENANCE,
7097
        TOOL_SURVEY,
7098
        TOOL_WIKI,
7099
        TOOL_GLOSSARY,
7100
        TOOL_GRADEBOOK,
7101
        TOOL_NOTEBOOK,
7102
        TOOL_ATTENDANCE,
7103
        TOOL_COURSE_PROGRESS,
7104
    ];
7105
    if (empty($my_tool)) {
7106
        return $tools_list;
7107
    }
7108
7109
    return in_array($my_tool, $tools_list) ? $my_tool : '';
7110
}
7111
7112
/**
7113
 * Checks whether we already approved the last version term and condition.
7114
 *
7115
 * @param int user id
7116
 *
7117
 * @return bool true if we pass false otherwise
7118
 */
7119
function api_check_term_condition($userId)
7120
{
7121
    if (api_get_setting('allow_terms_conditions') === 'true') {
7122
        // Check if exists terms and conditions
7123
        if (LegalManager::count() == 0) {
7124
            return true;
7125
        }
7126
7127
        $extraFieldValue = new ExtraFieldValue('user');
7128
        $data = $extraFieldValue->get_values_by_handler_and_field_variable(
7129
            $userId,
7130
            'legal_accept'
7131
        );
7132
7133
        if (!empty($data) && isset($data['value']) && !empty($data['value'])) {
7134
            $result = $data['value'];
7135
            $user_conditions = explode(':', $result);
7136
            $version = $user_conditions[0];
7137
            $langId = $user_conditions[1];
7138
            $realVersion = LegalManager::get_last_version($langId);
7139
7140
            return $version >= $realVersion;
7141
        }
7142
7143
        return false;
7144
    }
7145
7146
    return false;
7147
}
7148
7149
/**
7150
 * Gets all information of a tool into course.
7151
 *
7152
 * @param int The tool id
7153
 *
7154
 * @return array
7155
 */
7156
function api_get_tool_information_by_name($name)
7157
{
7158
    $t_tool = Database::get_course_table(TABLE_TOOL_LIST);
7159
    $course_id = api_get_course_int_id();
7160
    $sql = "SELECT * FROM $t_tool
7161
            WHERE c_id = $course_id  AND name = '".Database::escape_string($name)."' ";
7162
    $rs = Database::query($sql);
7163
7164
    return Database::fetch_array($rs, 'ASSOC');
7165
}
7166
7167
/**
7168
 * Function used to protect a "global" admin script.
7169
 * The function blocks access when the user has no global platform admin rights.
7170
 * Global admins are the admins that are registered in the main.admin table
7171
 * AND the users who have access to the "principal" portal.
7172
 * That means that there is a record in the main.access_url_rel_user table
7173
 * with his user id and the access_url_id=1.
7174
 *
7175
 * @author Julio Montoya
7176
 *
7177
 * @param int $user_id
7178
 *
7179
 * @return bool
7180
 */
7181
function api_is_global_platform_admin($user_id = null)
7182
{
7183
    $user_id = (int) $user_id;
7184
    if (empty($user_id)) {
7185
        $user_id = api_get_user_id();
7186
    }
7187
    if (api_is_platform_admin_by_id($user_id)) {
7188
        $urlList = api_get_access_url_from_user($user_id);
7189
        // The admin is registered in the first "main" site with access_url_id = 1
7190
        if (in_array(1, $urlList)) {
7191
            return true;
7192
        } else {
7193
            return false;
7194
        }
7195
    }
7196
7197
    return false;
7198
}
7199
7200
/**
7201
 * @param int  $admin_id_to_check
7202
 * @param int  $my_user_id
7203
 * @param bool $allow_session_admin
7204
 *
7205
 * @return bool
7206
 */
7207
function api_global_admin_can_edit_admin(
7208
    $admin_id_to_check,
7209
    $my_user_id = null,
7210
    $allow_session_admin = false
7211
) {
7212
    if (empty($my_user_id)) {
7213
        $my_user_id = api_get_user_id();
7214
    }
7215
7216
    $iam_a_global_admin = api_is_global_platform_admin($my_user_id);
7217
    $user_is_global_admin = api_is_global_platform_admin($admin_id_to_check);
7218
7219
    if ($iam_a_global_admin) {
7220
        // Global admin can edit everything
7221
        return true;
7222
    } else {
7223
        // If i'm a simple admin
7224
        $is_platform_admin = api_is_platform_admin_by_id($my_user_id);
7225
7226
        if ($allow_session_admin) {
7227
            $is_platform_admin = api_is_platform_admin_by_id($my_user_id) || (api_get_user_status($my_user_id) == SESSIONADMIN);
7228
        }
7229
7230
        if ($is_platform_admin) {
7231
            if ($user_is_global_admin) {
7232
                return false;
7233
            } else {
7234
                return true;
7235
            }
7236
        } else {
7237
            return false;
7238
        }
7239
    }
7240
}
7241
7242
/**
7243
 * @param int  $admin_id_to_check
7244
 * @param int  $my_user_id
7245
 * @param bool $allow_session_admin
7246
 *
7247
 * @return bool|null
7248
 */
7249
function api_protect_super_admin($admin_id_to_check, $my_user_id = null, $allow_session_admin = false)
7250
{
7251
    if (api_global_admin_can_edit_admin($admin_id_to_check, $my_user_id, $allow_session_admin)) {
7252
        return true;
7253
    } else {
7254
        api_not_allowed();
7255
    }
7256
}
7257
7258
/**
7259
 * Function used to protect a global admin script.
7260
 * The function blocks access when the user has no global platform admin rights.
7261
 * See also the api_is_global_platform_admin() function wich defines who's a "global" admin.
7262
 *
7263
 * @author Julio Montoya
7264
 */
7265
function api_protect_global_admin_script()
7266
{
7267
    if (!api_is_global_platform_admin()) {
7268
        api_not_allowed();
7269
7270
        return false;
7271
    }
7272
7273
    return true;
7274
}
7275
7276
/**
7277
 * Get active template.
7278
 *
7279
 * @param string    theme type (optional: default)
7280
 * @param string    path absolute(abs) or relative(rel) (optional:rel)
7281
 *
7282
 * @return string actived template path
7283
 */
7284
function api_get_template($path_type = 'rel')
7285
{
7286
    $path_types = ['rel', 'abs'];
7287
    $template_path = '';
7288
    if (in_array($path_type, $path_types)) {
7289
        if ($path_type == 'rel') {
7290
            $template_path = api_get_path(SYS_TEMPLATE_PATH);
7291
        } else {
7292
            $template_path = api_get_path(WEB_TEMPLATE_PATH);
7293
        }
7294
    }
7295
    $actived_theme = 'default';
7296
    if (api_get_setting('active_template')) {
7297
        $actived_theme = api_get_setting('active_template');
7298
    }
7299
    $actived_theme_path = $template_path.$actived_theme.DIRECTORY_SEPARATOR;
7300
7301
    return $actived_theme_path;
7302
}
7303
7304
/**
7305
 * Check browser support for specific file types or features
7306
 * This function checks if the user's browser supports a file format or given
7307
 * feature, or returns the current browser and major version when
7308
 * $format=check_browser. Only a limited number of formats and features are
7309
 * checked by this method. Make sure you check its definition first.
7310
 *
7311
 * @param string $format Can be a file format (extension like svg, webm, ...) or a feature (like autocapitalize, ...)
7312
 *
7313
 * @return bool or return text array if $format=check_browser
7314
 *
7315
 * @author Juan Carlos Raña Trabado
7316
 */
7317
function api_browser_support($format = '')
7318
{
7319
    $browser = new Browser();
7320
    $current_browser = $browser->getBrowser();
7321
    $a_versiontemp = explode('.', $browser->getVersion());
7322
    $current_majorver = $a_versiontemp[0];
7323
7324
    static $result;
7325
7326
    if (isset($result[$format])) {
7327
        return $result[$format];
7328
    }
7329
7330
    // Native svg support
7331
    if ($format == 'svg') {
7332
        if (($current_browser == 'Internet Explorer' && $current_majorver >= 9) ||
7333
            ($current_browser == 'Firefox' && $current_majorver > 1) ||
7334
            ($current_browser == 'Safari' && $current_majorver >= 4) ||
7335
            ($current_browser == 'Chrome' && $current_majorver >= 1) ||
7336
            ($current_browser == 'Opera' && $current_majorver >= 9)
7337
        ) {
7338
            $result[$format] = true;
7339
7340
            return true;
7341
        } else {
7342
            $result[$format] = false;
7343
7344
            return false;
7345
        }
7346
    } elseif ($format == 'pdf') {
7347
        // native pdf support
7348
        if (($current_browser == 'Chrome' && $current_majorver >= 6) ||
7349
            ('Firefox' === $current_browser && $current_majorver >= 15)
7350
        ) {
7351
            $result[$format] = true;
7352
7353
            return true;
7354
        } else {
7355
            $result[$format] = false;
7356
7357
            return false;
7358
        }
7359
    } elseif ($format == 'tif' || $format == 'tiff') {
7360
        //native tif support
7361
        if ($current_browser == 'Safari' && $current_majorver >= 5) {
7362
            $result[$format] = true;
7363
7364
            return true;
7365
        } else {
7366
            $result[$format] = false;
7367
7368
            return false;
7369
        }
7370
    } elseif ($format == 'ogg' || $format == 'ogx' || $format == 'ogv' || $format == 'oga') {
7371
        //native ogg, ogv,oga support
7372
        if (($current_browser == 'Firefox' && $current_majorver >= 3) ||
7373
            ($current_browser == 'Chrome' && $current_majorver >= 3) ||
7374
            ($current_browser == 'Opera' && $current_majorver >= 9)) {
7375
            $result[$format] = true;
7376
7377
            return true;
7378
        } else {
7379
            $result[$format] = false;
7380
7381
            return false;
7382
        }
7383
    } elseif ($format == 'mpg' || $format == 'mpeg') {
7384
        //native mpg support
7385
        if (($current_browser == 'Safari' && $current_majorver >= 5)) {
7386
            $result[$format] = true;
7387
7388
            return true;
7389
        } else {
7390
            $result[$format] = false;
7391
7392
            return false;
7393
        }
7394
    } elseif ($format == 'mp4') {
7395
        //native mp4 support (TODO: Android, iPhone)
7396
        if ($current_browser == 'Android' || $current_browser == 'iPhone') {
7397
            $result[$format] = true;
7398
7399
            return true;
7400
        } else {
7401
            $result[$format] = false;
7402
7403
            return false;
7404
        }
7405
    } elseif ($format == 'mov') {
7406
        //native mov support( TODO:check iPhone)
7407
        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...
7408
            $result[$format] = true;
7409
7410
            return true;
7411
        } else {
7412
            $result[$format] = false;
7413
7414
            return false;
7415
        }
7416
    } elseif ($format == 'avi') {
7417
        //native avi support
7418
        if ($current_browser == 'Safari' && $current_majorver >= 5) {
7419
            $result[$format] = true;
7420
7421
            return true;
7422
        } else {
7423
            $result[$format] = false;
7424
7425
            return false;
7426
        }
7427
    } elseif ($format == 'wmv') {
7428
        //native wmv support
7429
        if ($current_browser == 'Firefox' && $current_majorver >= 4) {
7430
            $result[$format] = true;
7431
7432
            return true;
7433
        } else {
7434
            $result[$format] = false;
7435
7436
            return false;
7437
        }
7438
    } elseif ($format == 'webm') {
7439
        //native webm support (TODO:check IE9, Chrome9, Android)
7440
        if (($current_browser == 'Firefox' && $current_majorver >= 4) ||
7441
            ($current_browser == 'Opera' && $current_majorver >= 9) ||
7442
            ($current_browser == 'Internet Explorer' && $current_majorver >= 9) ||
7443
            ($current_browser == 'Chrome' && $current_majorver >= 9) ||
7444
            $current_browser == 'Android'
7445
        ) {
7446
            $result[$format] = true;
7447
7448
            return true;
7449
        } else {
7450
            $result[$format] = false;
7451
7452
            return false;
7453
        }
7454
    } elseif ($format == 'wav') {
7455
        //native wav support (only some codecs !)
7456
        if (($current_browser == 'Firefox' && $current_majorver >= 4) ||
7457
            ($current_browser == 'Safari' && $current_majorver >= 5) ||
7458
            ($current_browser == 'Opera' && $current_majorver >= 9) ||
7459
            ($current_browser == 'Internet Explorer' && $current_majorver >= 9) ||
7460
            ($current_browser == 'Chrome' && $current_majorver > 9) ||
7461
            $current_browser == 'Android' ||
7462
            $current_browser == 'iPhone'
7463
        ) {
7464
            $result[$format] = true;
7465
7466
            return true;
7467
        } else {
7468
            $result[$format] = false;
7469
7470
            return false;
7471
        }
7472
    } elseif ($format == 'mid' || $format == 'kar') {
7473
        //native midi support (TODO:check Android)
7474
        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...
7475
            $result[$format] = true;
7476
7477
            return true;
7478
        } else {
7479
            $result[$format] = false;
7480
7481
            return false;
7482
        }
7483
    } elseif ($format == 'wma') {
7484
        //native wma support
7485
        if ($current_browser == 'Firefox' && $current_majorver >= 4) {
7486
            $result[$format] = true;
7487
7488
            return true;
7489
        } else {
7490
            $result[$format] = false;
7491
7492
            return false;
7493
        }
7494
    } elseif ($format == 'au') {
7495
        //native au support
7496
        if ($current_browser == 'Safari' && $current_majorver >= 5) {
7497
            $result[$format] = true;
7498
7499
            return true;
7500
        } else {
7501
            $result[$format] = false;
7502
7503
            return false;
7504
        }
7505
    } elseif ($format == 'mp3') {
7506
        //native mp3 support (TODO:check Android, iPhone)
7507
        if (($current_browser == 'Safari' && $current_majorver >= 5) ||
7508
            ($current_browser == 'Chrome' && $current_majorver >= 6) ||
7509
            ($current_browser == 'Internet Explorer' && $current_majorver >= 9) ||
7510
            $current_browser == 'Android' ||
7511
            $current_browser == 'iPhone' ||
7512
            $current_browser == 'Firefox'
7513
        ) {
7514
            $result[$format] = true;
7515
7516
            return true;
7517
        } else {
7518
            $result[$format] = false;
7519
7520
            return false;
7521
        }
7522
    } elseif ($format == 'autocapitalize') {
7523
        // Help avoiding showing the autocapitalize option if the browser doesn't
7524
        // support it: this attribute is against the HTML5 standard
7525
        if ($current_browser == 'Safari' || $current_browser == 'iPhone') {
7526
            return true;
7527
        } else {
7528
            return false;
7529
        }
7530
    } elseif ($format == "check_browser") {
7531
        $array_check_browser = [$current_browser, $current_majorver];
7532
7533
        return $array_check_browser;
7534
    } else {
7535
        $result[$format] = false;
7536
7537
        return false;
7538
    }
7539
}
7540
7541
/**
7542
 * This function checks if exist path and file browscap.ini
7543
 * In order for this to work, your browscap configuration setting in php.ini
7544
 * must point to the correct location of the browscap.ini file on your system
7545
 * http://php.net/manual/en/function.get-browser.php.
7546
 *
7547
 * @return bool
7548
 *
7549
 * @author Juan Carlos Raña Trabado
7550
 */
7551
function api_check_browscap()
7552
{
7553
    $setting = ini_get('browscap');
7554
    if ($setting) {
7555
        $browser = get_browser($_SERVER['HTTP_USER_AGENT'], true);
7556
        if (strpos($setting, 'browscap.ini') && !empty($browser)) {
7557
            return true;
7558
        }
7559
    }
7560
7561
    return false;
7562
}
7563
7564
/**
7565
 * Returns the <script> HTML tag.
7566
 */
7567
function api_get_js($file)
7568
{
7569
    return '<script src="'.api_get_path(WEB_LIBRARY_PATH).'javascript/'.$file.'"></script>'."\n";
7570
}
7571
7572
/**
7573
 * Returns the <script> HTML tag.
7574
 *
7575
 * @return string
7576
 */
7577
function api_get_asset($file)
7578
{
7579
    return '<script src="'.api_get_path(WEB_PUBLIC_PATH).'assets/'.$file.'"></script>'."\n";
7580
}
7581
7582
/**
7583
 * Returns the <script> HTML tag.
7584
 *
7585
 * @param string $file
7586
 * @param string $media
7587
 *
7588
 * @return string
7589
 */
7590
function api_get_css_asset($file, $media = 'screen')
7591
{
7592
    return '<link href="'.api_get_path(WEB_PUBLIC_PATH).'assets/'.$file.'" rel="stylesheet" media="'.$media.'" type="text/css" />'."\n";
7593
}
7594
7595
/**
7596
 * Returns the <link> HTML tag.
7597
 *
7598
 * @param string $file
7599
 * @param string $media
7600
 */
7601
function api_get_css($file, $media = 'screen')
7602
{
7603
    return '<link href="'.$file.'" rel="stylesheet" media="'.$media.'" type="text/css" />'."\n";
7604
}
7605
7606
/**
7607
 * Returns the js header to include the jquery library.
7608
 */
7609
function api_get_jquery_js()
7610
{
7611
    return api_get_asset('jquery/dist/jquery.min.js');
7612
}
7613
7614
/**
7615
 * Returns the jquery path.
7616
 *
7617
 * @return string
7618
 */
7619
function api_get_jquery_web_path()
7620
{
7621
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery/dist/jquery.min.js';
7622
}
7623
7624
/**
7625
 * @return string
7626
 */
7627
function api_get_jquery_ui_js_web_path()
7628
{
7629
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery-ui/jquery-ui.min.js';
7630
}
7631
7632
/**
7633
 * @return string
7634
 */
7635
function api_get_jquery_ui_css_web_path()
7636
{
7637
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery-ui/themes/smoothness/jquery-ui.min.css';
7638
}
7639
7640
/**
7641
 * Returns the jquery-ui library js headers.
7642
 *
7643
 * @param   bool    add the jqgrid library
7644
 *
7645
 * @return string html tags
7646
 */
7647
function api_get_jquery_ui_js($include_jqgrid = false)
7648
{
7649
    $libraries = [];
7650
    if ($include_jqgrid) {
7651
        $libraries[] = 'jqgrid';
7652
    }
7653
7654
    return api_get_jquery_libraries_js($libraries);
7655
}
7656
7657
function api_get_jqgrid_js()
7658
{
7659
    return api_get_jquery_libraries_js(['jqgrid']);
7660
}
7661
7662
/**
7663
 * Returns the jquery library js and css headers.
7664
 *
7665
 * @param   array   list of jquery libraries supported jquery-ui, jqgrid
7666
 * @param   bool    add the jquery library
7667
 *
7668
 * @return string html tags
7669
 */
7670
function api_get_jquery_libraries_js($libraries)
7671
{
7672
    $js = '';
7673
    $js_path = api_get_path(WEB_LIBRARY_PATH).'javascript/';
7674
7675
    //jqgrid js and css
7676
    if (in_array('jqgrid', $libraries)) {
7677
        $languaje = 'en';
7678
        $platform_isocode = strtolower(api_get_language_isocode());
7679
7680
        //languages supported by jqgrid see files in main/inc/lib/javascript/jqgrid/js/i18n
7681
        $jqgrid_langs = [
7682
            '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',
7683
        ];
7684
7685
        if (in_array($platform_isocode, $jqgrid_langs)) {
7686
            $languaje = $platform_isocode;
7687
        }
7688
        //$js .= '<link rel="stylesheet" href="'.$js_path.'jqgrid/css/ui.jqgrid.css" type="text/css">';
7689
        $js .= api_get_css($js_path.'jqgrid/css/ui.jqgrid.css');
7690
        $js .= api_get_js('jqgrid/js/i18n/grid.locale-'.$languaje.'.js');
7691
        $js .= api_get_js('jqgrid/js/jquery.jqGrid.min.js');
7692
    }
7693
7694
    //Document multiple upload funcionality
7695
    if (in_array('jquery-upload', $libraries)) {
7696
        $js .= api_get_asset('blueimp-load-image/js/load-image.all.min.js');
7697
        $js .= api_get_asset('blueimp-canvas-to-blob/js/canvas-to-blob.min.js');
7698
        $js .= api_get_asset('jquery-file-upload/js/jquery.iframe-transport.js');
7699
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload.js');
7700
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-process.js');
7701
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-image.js');
7702
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-audio.js');
7703
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-video.js');
7704
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-validate.js');
7705
7706
        $js .= api_get_css(api_get_path(WEB_PUBLIC_PATH).'assets/jquery-file-upload/css/jquery.fileupload.css');
7707
        $js .= api_get_css(api_get_path(WEB_PUBLIC_PATH).'assets/jquery-file-upload/css/jquery.fileupload-ui.css');
7708
    }
7709
7710
    // jquery datepicker
7711
    if (in_array('datepicker', $libraries)) {
7712
        $languaje = 'en-GB';
7713
        $platform_isocode = strtolower(api_get_language_isocode());
7714
7715
        // languages supported by jqgrid see files in main/inc/lib/javascript/jqgrid/js/i18n
7716
        $datapicker_langs = [
7717
            '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',
7718
        ];
7719
        if (in_array($platform_isocode, $datapicker_langs)) {
7720
            $languaje = $platform_isocode;
7721
        }
7722
7723
        $js .= api_get_js('jquery-ui/jquery-ui-i18n.min.js');
7724
        $script = '<script>
7725
        $(function(){
7726
            $.datepicker.setDefaults($.datepicker.regional["'.$languaje.'"]);
7727
            $.datepicker.regional["local"] = $.datepicker.regional["'.$languaje.'"];
7728
        });
7729
        </script>
7730
        ';
7731
        $js .= $script;
7732
    }
7733
7734
    return $js;
7735
}
7736
7737
/**
7738
 * Returns the URL to the course or session, removing the complexity of the URL
7739
 * building piece by piece.
7740
 *
7741
 * This function relies on api_get_course_info()
7742
 *
7743
 * @param string $courseCode The course code - optional (takes it from context if not given)
7744
 * @param int    $sessionId  The session ID  - optional (takes it from context if not given)
7745
 * @param int    $groupId    The group ID - optional (takes it from context if not given)
7746
 *
7747
 * @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
7748
 *
7749
 * @author  Julio Montoya <[email protected]>
7750
 */
7751
function api_get_course_url($courseCode = null, $sessionId = null, $groupId = null)
7752
{
7753
    $courseDirectory = '';
7754
    $url = '';
7755
    // If courseCode not set, get context or []
7756
    if (empty($courseCode)) {
7757
        $courseInfo = api_get_course_info();
7758
    } else {
7759
        $courseInfo = api_get_course_info($courseCode);
7760
    }
7761
7762
    // If course defined, get directory, otherwise keep empty string
7763
    if (!empty($courseInfo['directory'])) {
7764
        $courseDirectory = $courseInfo['directory'];
7765
    }
7766
7767
    // If sessionId not set, get context or 0
7768
    if (empty($sessionId)) {
7769
        $sessionId = api_get_session_id();
7770
    }
7771
7772
    // If groupId not set, get context or 0
7773
    if (empty($groupId)) {
7774
        $groupId = api_get_group_id();
7775
    }
7776
7777
    // Build the URL
7778
    if (!empty($courseDirectory)) {
7779
        // directory not empty, so we do have a course
7780
        $url = api_get_path(WEB_COURSE_PATH).$courseDirectory.'/index.php?id_session='.$sessionId.'&gidReq='.$groupId;
7781
    } elseif (!empty($sessionId) && api_get_configuration_value('remove_session_url') !== true) {
7782
        // if the course was unset and the session was set, send directly to the session
7783
        $url = api_get_path(WEB_CODE_PATH).'session/index.php?session_id='.$sessionId;
7784
    }
7785
    // if not valid combination was found, return an empty string
7786
    return $url;
7787
}
7788
7789
/**
7790
 * Check if the current portal has the $_configuration['multiple_access_urls'] parameter on.
7791
 *
7792
 * @return bool true if multi site is enabled
7793
 */
7794
function api_get_multiple_access_url()
7795
{
7796
    global $_configuration;
7797
    if (isset($_configuration['multiple_access_urls']) && $_configuration['multiple_access_urls']) {
7798
        return true;
7799
    }
7800
7801
    return false;
7802
}
7803
7804
/**
7805
 * Just a synonym for api_get_multiple_access_url().
7806
 *
7807
 * @return bool
7808
 */
7809
function api_is_multiple_url_enabled()
7810
{
7811
    return api_get_multiple_access_url();
7812
}
7813
7814
/**
7815
 * Returns a md5 unique id.
7816
 *
7817
 * @todo add more parameters
7818
 */
7819
function api_get_unique_id()
7820
{
7821
    $id = md5(time().uniqid().api_get_user_id().api_get_course_id().api_get_session_id());
7822
7823
    return $id;
7824
}
7825
7826
/**
7827
 * Get home path.
7828
 *
7829
 * @return string
7830
 */
7831
function api_get_home_path()
7832
{
7833
    // FIX : Start the routing determination from central path definition
7834
    $home = api_get_path(SYS_HOME_PATH);
7835
    if (api_get_multiple_access_url()) {
7836
        $access_url_id = api_get_current_access_url_id();
7837
        $url_info = api_get_access_url($access_url_id);
7838
        $url = api_remove_trailing_slash(preg_replace('/https?:\/\//i', '', $url_info['url']));
7839
        $clean_url = api_replace_dangerous_char($url);
7840
        $clean_url = str_replace('/', '-', $clean_url);
7841
        $clean_url .= '/';
7842
        if ($clean_url != 'localhost/') {
7843
            // means that the multiple URL was not well configured we don't rename the $home variable
7844
            return "{$home}{$clean_url}";
7845
        }
7846
    }
7847
7848
    return $home;
7849
}
7850
7851
/**
7852
 * @param int Course id
7853
 * @param int tool id: TOOL_QUIZ, TOOL_FORUM, TOOL_STUDENTPUBLICATION, TOOL_LEARNPATH
7854
 * @param int the item id (tool id, exercise id, lp id)
7855
 *
7856
 * @return bool
7857
 */
7858
function api_resource_is_locked_by_gradebook($item_id, $link_type, $course_code = null)
7859
{
7860
    if (api_is_platform_admin()) {
7861
        return false;
7862
    }
7863
    if (api_get_setting('gradebook_locking_enabled') == 'true') {
7864
        if (empty($course_code)) {
7865
            $course_code = api_get_course_id();
7866
        }
7867
        $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_LINK);
7868
        $item_id = intval($item_id);
7869
        $link_type = intval($link_type);
7870
        $course_code = Database::escape_string($course_code);
7871
        $sql = "SELECT locked FROM $table
7872
                WHERE locked = 1 AND ref_id = $item_id AND type = $link_type AND course_code = '$course_code' ";
7873
        $result = Database::query($sql);
7874
        if (Database::num_rows($result)) {
7875
            return true;
7876
        }
7877
    }
7878
7879
    return false;
7880
}
7881
7882
/**
7883
 * Blocks a page if the item was added in a gradebook.
7884
 *
7885
 * @param int       exercise id, work id, thread id,
7886
 * @param int       LINK_EXERCISE, LINK_STUDENTPUBLICATION, LINK_LEARNPATH LINK_FORUM_THREAD, LINK_ATTENDANCE
7887
 * see gradebook/lib/be/linkfactory
7888
 * @param string    course code
7889
 *
7890
 * @return false|null
7891
 */
7892
function api_block_course_item_locked_by_gradebook($item_id, $link_type, $course_code = null)
7893
{
7894
    if (api_is_platform_admin()) {
7895
        return false;
7896
    }
7897
7898
    if (api_resource_is_locked_by_gradebook($item_id, $link_type, $course_code)) {
7899
        $message = Display::return_message(get_lang('ResourceLockedByGradebook'), 'warning');
7900
        api_not_allowed(true, $message);
7901
    }
7902
}
7903
7904
/**
7905
 * Checks the PHP version installed is enough to run Chamilo.
7906
 *
7907
 * @param string Include path (used to load the error page)
7908
 */
7909
function api_check_php_version($my_inc_path = null)
7910
{
7911
    if (!function_exists('version_compare') || version_compare(phpversion(), REQUIRED_PHP_VERSION, '<')) {
7912
        $global_error_code = 1;
7913
        // Incorrect PHP version
7914
        $global_page = $my_inc_path.'global_error_message.inc.php';
7915
        if (file_exists($global_page)) {
7916
            require $global_page;
7917
        }
7918
        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...
7919
    }
7920
}
7921
7922
/**
7923
 * Checks whether the Archive directory is present and writeable. If not,
7924
 * prints a warning message.
7925
 */
7926
function api_check_archive_dir()
7927
{
7928
    if (is_dir(api_get_path(SYS_ARCHIVE_PATH)) && !is_writable(api_get_path(SYS_ARCHIVE_PATH))) {
7929
        $message = Display::return_message(get_lang('ArchivesDirectoryNotWriteableContactAdmin'), 'warning');
7930
        api_not_allowed(true, $message);
7931
    }
7932
}
7933
7934
/**
7935
 * Returns an array of global configuration settings which should be ignored
7936
 * when printing the configuration settings screens.
7937
 *
7938
 * @return array Array of strings, each identifying one of the excluded settings
7939
 */
7940
function api_get_locked_settings()
7941
{
7942
    return [
7943
        'server_type',
7944
        'permanently_remove_deleted_files',
7945
        'account_valid_duration',
7946
        'service_ppt2lp',
7947
        'wcag_anysurfer_public_pages',
7948
        'upload_extensions_list_type',
7949
        'upload_extensions_blacklist',
7950
        'upload_extensions_whitelist',
7951
        'upload_extensions_skip',
7952
        'upload_extensions_replace_by',
7953
        'hide_dltt_markup',
7954
        'split_users_upload_directory',
7955
        'permissions_for_new_directories',
7956
        'permissions_for_new_files',
7957
        'platform_charset',
7958
        'ldap_description',
7959
        'cas_activate',
7960
        'cas_server',
7961
        'cas_server_uri',
7962
        'cas_port',
7963
        'cas_protocol',
7964
        'cas_add_user_activate',
7965
        'update_user_info_cas_with_ldap',
7966
        'languagePriority1',
7967
        'languagePriority2',
7968
        'languagePriority3',
7969
        'languagePriority4',
7970
        'login_is_email',
7971
        'chamilo_database_version',
7972
    ];
7973
}
7974
7975
/**
7976
 * Checks if the user is corrently logged in. Returns the user ID if he is, or
7977
 * false if he isn't. If the user ID is given and is an integer, then the same
7978
 * ID is simply returned.
7979
 *
7980
 * @param  int User ID
7981
 *
7982
 * @return bool Integer User ID is logged in, or false otherwise
7983
 */
7984
function api_user_is_login($user_id = null)
7985
{
7986
    $user_id = empty($user_id) ? api_get_user_id() : (int) $user_id;
7987
7988
    return $user_id && !api_is_anonymous();
7989
}
7990
7991
/**
7992
 * Guess the real ip for register in the database, even in reverse proxy cases.
7993
 * To be recognized, the IP has to be found in either $_SERVER['REMOTE_ADDR'] or
7994
 * in $_SERVER['HTTP_X_FORWARDED_FOR'], which is in common use with rproxies.
7995
 * Note: the result of this function is not SQL-safe. Please escape it before
7996
 * inserting in a database.
7997
 *
7998
 * @return string the user's real ip (unsafe - escape it before inserting to db)
7999
 *
8000
 * @author Jorge Frisancho Jibaja <[email protected]>, USIL - Some changes to allow the use of real IP using reverse proxy
8001
 *
8002
 * @version CEV CHANGE 24APR2012
8003
 */
8004
function api_get_real_ip()
8005
{
8006
    $ip = trim($_SERVER['REMOTE_ADDR']);
8007
    if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
8008
        if (preg_match('/,/', $_SERVER['HTTP_X_FORWARDED_FOR'])) {
8009
            @list($ip1, $ip2) = @explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
8010
        } else {
8011
            $ip1 = $_SERVER['HTTP_X_FORWARDED_FOR'];
8012
        }
8013
        $ip = trim($ip1);
8014
    }
8015
8016
    return $ip;
8017
}
8018
8019
/**
8020
 * Checks whether an IP is included inside an IP range.
8021
 *
8022
 * @param string IP address
8023
 * @param string IP range
8024
 * @param string $ip
8025
 *
8026
 * @return bool True if IP is in the range, false otherwise
8027
 *
8028
 * @author claudiu at cnixs dot com  on http://www.php.net/manual/fr/ref.network.php#55230
8029
 * @author Yannick Warnier for improvements and managment of multiple ranges
8030
 *
8031
 * @todo check for IPv6 support
8032
 */
8033
function api_check_ip_in_range($ip, $range)
8034
{
8035
    if (empty($ip) or empty($range)) {
8036
        return false;
8037
    }
8038
    $ip_ip = ip2long($ip);
8039
    // divide range param into array of elements
8040
    if (strpos($range, ',') !== false) {
8041
        $ranges = explode(',', $range);
8042
    } else {
8043
        $ranges = [$range];
8044
    }
8045
    foreach ($ranges as $range) {
0 ignored issues
show
introduced by
$range is overwriting one of the parameters of this function.
Loading history...
8046
        $range = trim($range);
8047
        if (empty($range)) {
8048
            continue;
8049
        }
8050
        if (strpos($range, '/') === false) {
8051
            if (strcmp($ip, $range) === 0) {
8052
                return true; // there is a direct IP match, return OK
8053
            }
8054
            continue; //otherwise, get to the next range
8055
        }
8056
        // the range contains a "/", so analyse completely
8057
        list($net, $mask) = explode("/", $range);
8058
8059
        $ip_net = ip2long($net);
8060
        // mask binary magic
8061
        $ip_mask = ~((1 << (32 - $mask)) - 1);
8062
8063
        $ip_ip_net = $ip_ip & $ip_mask;
8064
        if ($ip_ip_net == $ip_net) {
8065
            return true;
8066
        }
8067
    }
8068
8069
    return false;
8070
}
8071
8072
function api_check_user_access_to_legal($courseInfo)
8073
{
8074
    if (empty($courseInfo)) {
8075
        return false;
8076
    }
8077
8078
    $visibility = (int) $courseInfo['visibility'];
8079
    $visibilityList = [COURSE_VISIBILITY_OPEN_WORLD, COURSE_VISIBILITY_OPEN_PLATFORM];
8080
8081
    return
8082
        in_array($visibility, $visibilityList) ||
8083
        api_is_drh() ||
8084
        (COURSE_VISIBILITY_REGISTERED === $visibility && 1 === (int) $courseInfo['subscribe']);
8085
}
8086
8087
/**
8088
 * Checks if the global chat is enabled or not.
8089
 *
8090
 * @return bool
8091
 */
8092
function api_is_global_chat_enabled()
8093
{
8094
    return
8095
        !api_is_anonymous() &&
8096
        api_get_setting('allow_global_chat') === 'true' &&
8097
        api_get_setting('allow_social_tool') === 'true';
8098
}
8099
8100
/**
8101
 * @todo Fix tool_visible_by_default_at_creation labels
8102
 *
8103
 * @param int   $item_id
8104
 * @param int   $tool_id
8105
 * @param int   $group_id   id
8106
 * @param array $courseInfo
8107
 * @param int   $sessionId
8108
 * @param int   $userId
8109
 */
8110
function api_set_default_visibility(
8111
    $item_id,
8112
    $tool_id,
8113
    $group_id = 0,
8114
    $courseInfo = [],
8115
    $sessionId = 0,
8116
    $userId = 0
8117
) {
8118
    $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
8119
    $courseId = $courseInfo['real_id'];
8120
    $courseCode = $courseInfo['code'];
8121
    $sessionId = empty($sessionId) ? api_get_session_id() : $sessionId;
8122
    $userId = empty($userId) ? api_get_user_id() : $userId;
8123
8124
    // if group is null force group_id = 0, this force is needed to create a LP folder with group = 0
8125
    if (is_null($group_id)) {
8126
        $group_id = 0;
8127
    } else {
8128
        $group_id = empty($group_id) ? api_get_group_id() : $group_id;
8129
    }
8130
8131
    $groupInfo = [];
8132
    if (!empty($group_id)) {
8133
        $groupInfo = GroupManager::get_group_properties($group_id);
8134
    }
8135
    $original_tool_id = $tool_id;
8136
8137
    switch ($tool_id) {
8138
        case TOOL_LINK:
8139
        case TOOL_LINK_CATEGORY:
8140
            $tool_id = 'links';
8141
            break;
8142
        case TOOL_DOCUMENT:
8143
            $tool_id = 'documents';
8144
            break;
8145
        case TOOL_LEARNPATH:
8146
            $tool_id = 'learning';
8147
            break;
8148
        case TOOL_ANNOUNCEMENT:
8149
            $tool_id = 'announcements';
8150
            break;
8151
        case TOOL_FORUM:
8152
        case TOOL_FORUM_CATEGORY:
8153
        case TOOL_FORUM_THREAD:
8154
            $tool_id = 'forums';
8155
            break;
8156
        case TOOL_QUIZ:
8157
            $tool_id = 'quiz';
8158
            break;
8159
    }
8160
    $setting = api_get_setting('tool_visible_by_default_at_creation');
8161
8162
    if (isset($setting[$tool_id])) {
8163
        $visibility = 'invisible';
8164
        if ($setting[$tool_id] == 'true') {
8165
            $visibility = 'visible';
8166
        }
8167
8168
        // Read the portal and course default visibility
8169
        if ($tool_id === 'documents') {
8170
            $visibility = DocumentManager::getDocumentDefaultVisibility($courseInfo);
8171
        }
8172
8173
        api_item_property_update(
8174
            $courseInfo,
8175
            $original_tool_id,
8176
            $item_id,
8177
            $visibility,
8178
            $userId,
8179
            $groupInfo,
8180
            null,
8181
            null,
8182
            null,
8183
            $sessionId
8184
        );
8185
8186
        // Fixes default visibility for tests
8187
        switch ($original_tool_id) {
8188
            case TOOL_QUIZ:
8189
                if (empty($sessionId)) {
8190
                    $objExerciseTmp = new Exercise($courseId);
8191
                    $objExerciseTmp->read($item_id);
8192
                    if ($visibility == 'visible') {
8193
                        $objExerciseTmp->enable();
8194
                        $objExerciseTmp->save();
8195
                    } else {
8196
                        $objExerciseTmp->disable();
8197
                        $objExerciseTmp->save();
8198
                    }
8199
                }
8200
                break;
8201
        }
8202
    }
8203
}
8204
8205
/**
8206
 * @return string
8207
 */
8208
function api_get_security_key()
8209
{
8210
    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...
8211
}
8212
8213
/**
8214
 * @param int $user_id
8215
 * @param int $courseId
8216
 * @param int $session_id
8217
 *
8218
 * @return array
8219
 */
8220
function api_detect_user_roles($user_id, $courseId, $session_id = 0)
8221
{
8222
    $user_roles = [];
8223
    $courseInfo = api_get_course_info_by_id($courseId);
8224
    $course_code = $courseInfo['code'];
8225
8226
    $url_id = api_get_current_access_url_id();
8227
    if (api_is_platform_admin_by_id($user_id, $url_id)) {
8228
        $user_roles[] = PLATFORM_ADMIN;
8229
    }
8230
8231
    /*if (api_is_drh()) {
8232
        $user_roles[] = DRH;
8233
    }*/
8234
8235
    if (!empty($session_id)) {
8236
        if (SessionManager::user_is_general_coach($user_id, $session_id)) {
8237
            $user_roles[] = SESSION_GENERAL_COACH;
8238
        }
8239
    }
8240
8241
    if (!empty($course_code)) {
8242
        if (empty($session_id)) {
8243
            if (CourseManager::is_course_teacher($user_id, $course_code)) {
8244
                $user_roles[] = COURSEMANAGER;
8245
            }
8246
            if (CourseManager::get_tutor_in_course_status($user_id, $courseInfo['real_id'])) {
8247
                $user_roles[] = COURSE_TUTOR;
8248
            }
8249
8250
            if (CourseManager::is_user_subscribed_in_course($user_id, $course_code)) {
8251
                $user_roles[] = COURSE_STUDENT;
8252
            }
8253
        } else {
8254
            $user_status_in_session = SessionManager::get_user_status_in_course_session(
8255
                $user_id,
8256
                $courseId,
8257
                $session_id
8258
            );
8259
8260
            if (!empty($user_status_in_session)) {
8261
                if ($user_status_in_session == 0) {
8262
                    $user_roles[] = SESSION_STUDENT;
8263
                }
8264
                if ($user_status_in_session == 2) {
8265
                    $user_roles[] = SESSION_COURSE_COACH;
8266
                }
8267
            }
8268
8269
            /*if (api_is_course_session_coach($user_id, $course_code, $session_id)) {
8270
               $user_roles[] = SESSION_COURSE_COACH;
8271
            }*/
8272
        }
8273
    }
8274
8275
    return $user_roles;
8276
}
8277
8278
/**
8279
 * @param int $courseId
8280
 * @param int $session_id
8281
 *
8282
 * @return bool
8283
 */
8284
function api_coach_can_edit_view_results($courseId = null, $session_id = null)
8285
{
8286
    if (api_is_platform_admin()) {
8287
        return true;
8288
    }
8289
8290
    $user_id = api_get_user_id();
8291
8292
    if (empty($courseId)) {
8293
        $courseId = api_get_course_int_id();
8294
    }
8295
8296
    if (empty($session_id)) {
8297
        $session_id = api_get_session_id();
8298
    }
8299
8300
    $roles = api_detect_user_roles($user_id, $courseId, $session_id);
8301
8302
    if (in_array(SESSION_COURSE_COACH, $roles)) {
8303
        //return api_get_setting('session_tutor_reports_visibility') == 'true';
8304
        return true;
8305
    } else {
8306
        if (in_array(COURSEMANAGER, $roles)) {
8307
            return true;
8308
        }
8309
8310
        return false;
8311
    }
8312
}
8313
8314
/**
8315
 * @param string $file
8316
 *
8317
 * @return string
8318
 */
8319
function api_get_js_simple($file)
8320
{
8321
    return '<script src="'.$file.'"></script>'."\n";
8322
}
8323
8324
function api_set_settings_and_plugins()
8325
{
8326
    global $_configuration;
8327
    $_setting = [];
8328
    $_plugins = [];
8329
8330
    // access_url == 1 is the default chamilo location
8331
    $settings_by_access_list = [];
8332
    $access_url_id = api_get_current_access_url_id();
8333
    if ($access_url_id != 1) {
8334
        $url_info = api_get_access_url($_configuration['access_url']);
8335
        if ($url_info['active'] == 1) {
8336
            $settings_by_access = &api_get_settings(null, 'list', $_configuration['access_url'], 1);
8337
            foreach ($settings_by_access as &$row) {
8338
                if (empty($row['variable'])) {
8339
                    $row['variable'] = 0;
8340
                }
8341
                if (empty($row['subkey'])) {
8342
                    $row['subkey'] = 0;
8343
                }
8344
                if (empty($row['category'])) {
8345
                    $row['category'] = 0;
8346
                }
8347
                $settings_by_access_list[$row['variable']][$row['subkey']][$row['category']] = $row;
8348
            }
8349
        }
8350
    }
8351
8352
    $result = api_get_settings(null, 'list', 1);
8353
8354
    foreach ($result as &$row) {
8355
        if ($access_url_id != 1) {
8356
            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...
8357
                $var = empty($row['variable']) ? 0 : $row['variable'];
8358
                $subkey = empty($row['subkey']) ? 0 : $row['subkey'];
8359
                $category = empty($row['category']) ? 0 : $row['category'];
8360
            }
8361
8362
            if ($row['access_url_changeable'] == 1 && $url_info['active'] == 1) {
8363
                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...
8364
                    $settings_by_access_list[$var][$subkey][$category]['selected_value'] != '') {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $subkey does not seem to be defined for all execution paths leading up to this point.
Loading history...
Comprehensibility Best Practice introduced by
The variable $category does not seem to be defined for all execution paths leading up to this point.
Loading history...
8365
                    if ($row['subkey'] == null) {
8366
                        $_setting[$row['variable']] = $settings_by_access_list[$var][$subkey][$category]['selected_value'];
8367
                    } else {
8368
                        $_setting[$row['variable']][$row['subkey']] = $settings_by_access_list[$var][$subkey][$category]['selected_value'];
8369
                    }
8370
                } else {
8371
                    if ($row['subkey'] == null) {
8372
                        $_setting[$row['variable']] = $row['selected_value'];
8373
                    } else {
8374
                        $_setting[$row['variable']][$row['subkey']] = $row['selected_value'];
8375
                    }
8376
                }
8377
            } else {
8378
                if ($row['subkey'] == null) {
8379
                    $_setting[$row['variable']] = $row['selected_value'];
8380
                } else {
8381
                    $_setting[$row['variable']][$row['subkey']] = $row['selected_value'];
8382
                }
8383
            }
8384
        } else {
8385
            if ($row['subkey'] == null) {
8386
                $_setting[$row['variable']] = $row['selected_value'];
8387
            } else {
8388
                $_setting[$row['variable']][$row['subkey']] = $row['selected_value'];
8389
            }
8390
        }
8391
    }
8392
8393
    $result = api_get_settings('Plugins', 'list', $access_url_id);
8394
    $_plugins = [];
8395
    foreach ($result as &$row) {
8396
        $key = &$row['variable'];
8397
        if (is_string($_setting[$key])) {
8398
            $_setting[$key] = [];
8399
        }
8400
        $_setting[$key][] = $row['selected_value'];
8401
        $_plugins[$key][] = $row['selected_value'];
8402
    }
8403
8404
    $_SESSION['_setting'] = $_setting;
8405
    $_SESSION['_plugins'] = $_plugins;
8406
}
8407
8408
/**
8409
 * Modify default memory_limit and max_execution_time limits
8410
 * Needed when processing long tasks.
8411
 */
8412
function api_set_more_memory_and_time_limits()
8413
{
8414
    if (function_exists('ini_set')) {
8415
        api_set_memory_limit('2048M');
8416
        ini_set('max_execution_time', 3600);
8417
    }
8418
}
8419
8420
/**
8421
 * Tries to set memory limit, if authorized and new limit is higher than current.
8422
 *
8423
 * @param string $mem New memory limit
8424
 *
8425
 * @return bool True on success, false on failure or current is higher than suggested
8426
 * @assert (null) === false
8427
 * @assert (-1) === false
8428
 * @assert (0) === true
8429
 * @assert ('1G') === true
8430
 */
8431
function api_set_memory_limit($mem)
8432
{
8433
    //if ini_set() not available, this function is useless
8434
    if (!function_exists('ini_set') || is_null($mem) || $mem == -1) {
8435
        return false;
8436
    }
8437
8438
    $memory_limit = ini_get('memory_limit');
8439
    if (api_get_bytes_memory_limit($mem) > api_get_bytes_memory_limit($memory_limit)) {
8440
        ini_set('memory_limit', $mem);
8441
8442
        return true;
8443
    }
8444
8445
    return false;
8446
}
8447
8448
/**
8449
 * Gets memory limit in bytes.
8450
 *
8451
 * @param string The memory size (128M, 1G, 1000K, etc)
8452
 *
8453
 * @return int
8454
 * @assert (null) === false
8455
 * @assert ('1t')  === 1099511627776
8456
 * @assert ('1g')  === 1073741824
8457
 * @assert ('1m')  === 1048576
8458
 * @assert ('100k') === 102400
8459
 */
8460
function api_get_bytes_memory_limit($mem)
8461
{
8462
    $size = strtolower(substr($mem, -1));
8463
8464
    switch ($size) {
8465
        case 't':
8466
            $mem = intval(substr($mem, -1)) * 1024 * 1024 * 1024 * 1024;
8467
            break;
8468
        case 'g':
8469
            $mem = intval(substr($mem, 0, -1)) * 1024 * 1024 * 1024;
8470
            break;
8471
        case 'm':
8472
            $mem = intval(substr($mem, 0, -1)) * 1024 * 1024;
8473
            break;
8474
        case 'k':
8475
            $mem = intval(substr($mem, 0, -1)) * 1024;
8476
            break;
8477
        default:
8478
            // we assume it's integer only
8479
            $mem = intval($mem);
8480
            break;
8481
    }
8482
8483
    return $mem;
8484
}
8485
8486
/**
8487
 * Finds all the information about a user from username instead of user id.
8488
 *
8489
 * @param string $officialCode
8490
 *
8491
 * @return array $user_info user_id, lastname, firstname, username, email, ...
8492
 *
8493
 * @author Yannick Warnier <[email protected]>
8494
 */
8495
function api_get_user_info_from_official_code($officialCode)
8496
{
8497
    if (empty($officialCode)) {
8498
        return false;
8499
    }
8500
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
8501
            WHERE official_code ='".Database::escape_string($officialCode)."'";
8502
    $result = Database::query($sql);
8503
    if (Database::num_rows($result) > 0) {
8504
        $result_array = Database::fetch_array($result);
8505
8506
        return _api_format_user($result_array);
8507
    }
8508
8509
    return false;
8510
}
8511
8512
/**
8513
 * @param string $usernameInputId
8514
 * @param string $passwordInputId
8515
 *
8516
 * @return string|null
8517
 */
8518
function api_get_password_checker_js($usernameInputId, $passwordInputId)
8519
{
8520
    $checkPass = api_get_setting('allow_strength_pass_checker');
8521
    $useStrengthPassChecker = $checkPass === 'true';
8522
8523
    if ($useStrengthPassChecker === false) {
8524
        return null;
8525
    }
8526
8527
    $translations = [
8528
        'wordLength' => get_lang('PasswordIsTooShort'),
8529
        'wordNotEmail' => get_lang('YourPasswordCannotBeTheSameAsYourEmail'),
8530
        'wordSimilarToUsername' => get_lang('YourPasswordCannotContainYourUsername'),
8531
        'wordTwoCharacterClasses' => get_lang('WordTwoCharacterClasses'),
8532
        'wordRepetitions' => get_lang('TooManyRepetitions'),
8533
        'wordSequences' => get_lang('YourPasswordContainsSequences'),
8534
        'errorList' => get_lang('ErrorsFound'),
8535
        'veryWeak' => get_lang('PasswordVeryWeak'),
8536
        'weak' => get_lang('PasswordWeak'),
8537
        'normal' => get_lang('PasswordNormal'),
8538
        'medium' => get_lang('PasswordMedium'),
8539
        'strong' => get_lang('PasswordStrong'),
8540
        'veryStrong' => get_lang('PasswordVeryStrong'),
8541
    ];
8542
8543
    $js = api_get_asset('pwstrength-bootstrap/dist/pwstrength-bootstrap.min.js');
8544
    $js .= "<script>
8545
    var errorMessages = {
8546
        password_to_short : \"".get_lang('PasswordIsTooShort')."\",
8547
        same_as_username : \"".get_lang('YourPasswordCannotBeTheSameAsYourUsername')."\"
8548
    };
8549
8550
    $(function() {
8551
        var lang = ".json_encode($translations).";
8552
        var options = {
8553
            common: {
8554
                onLoad: function () {
8555
                    //$('#messages').text('Start typing password');
8556
8557
                    var inputGroup = $('".$passwordInputId."').parents('.input-group');
8558
8559
                    if (inputGroup.length > 0) {
8560
                        inputGroup.find('.progress').insertAfter(inputGroup);
8561
                    }
8562
                }
8563
            },
8564
            ui: {
8565
                showVerdictsInsideProgressBar: true
8566
            },
8567
            onKeyUp: function (evt) {
8568
                $(evt.target).pwstrength('outputErrorList');
8569
            },
8570
            errorMessages : errorMessages,
8571
            viewports: {
8572
                progress: '#password_progress',
8573
                verdict: '#password-verdict',
8574
                errors: '#password-errors'
8575
            },
8576
            usernameField: '$usernameInputId'
8577
        };
8578
        options.i18n = {
8579
            t: function (key) {
8580
                var result = lang[key];
8581
                return result === key ? '' : result; // This assumes you return the
8582
            }
8583
        };
8584
        $('".$passwordInputId."').pwstrength(options);
8585
    });
8586
    </script>";
8587
8588
    return $js;
8589
}
8590
8591
/**
8592
 * create an user extra field called 'captcha_blocked_until_date'.
8593
 *
8594
 * @param string $username
8595
 *
8596
 * @return bool
8597
 */
8598
function api_block_account_captcha($username)
8599
{
8600
    $userInfo = api_get_user_info_from_username($username);
8601
    if (empty($userInfo)) {
8602
        return false;
8603
    }
8604
    $minutesToBlock = api_get_setting('captcha_time_to_block');
8605
    $time = time() + $minutesToBlock * 60;
8606
    UserManager::update_extra_field_value(
8607
        $userInfo['user_id'],
8608
        'captcha_blocked_until_date',
8609
        api_get_utc_datetime($time)
8610
    );
8611
8612
    return true;
8613
}
8614
8615
/**
8616
 * @param string $username
8617
 *
8618
 * @return bool
8619
 */
8620
function api_clean_account_captcha($username)
8621
{
8622
    $userInfo = api_get_user_info_from_username($username);
8623
    if (empty($userInfo)) {
8624
        return false;
8625
    }
8626
    Session::erase('loginFailedCount');
8627
    UserManager::update_extra_field_value(
8628
        $userInfo['user_id'],
8629
        'captcha_blocked_until_date',
8630
        null
8631
    );
8632
8633
    return true;
8634
}
8635
8636
/**
8637
 * @param string $username
8638
 *
8639
 * @return bool
8640
 */
8641
function api_get_user_blocked_by_captcha($username)
8642
{
8643
    $userInfo = api_get_user_info_from_username($username);
8644
    if (empty($userInfo)) {
8645
        return false;
8646
    }
8647
    $data = UserManager::get_extra_user_data_by_field(
8648
        $userInfo['user_id'],
8649
        'captcha_blocked_until_date'
8650
    );
8651
    if (isset($data) && isset($data['captcha_blocked_until_date'])) {
8652
        return $data['captcha_blocked_until_date'];
8653
    }
8654
8655
    return false;
8656
}
8657
8658
/**
8659
 * Remove tags from HTML anf return the $in_number_char first non-HTML char
8660
 * Postfix the text with "..." if it has been truncated.
8661
 *
8662
 * @param string $text
8663
 * @param int    $number
8664
 *
8665
 * @return string
8666
 *
8667
 * @author hubert borderiou
8668
 */
8669
function api_get_short_text_from_html($text, $number)
8670
{
8671
    // Delete script and style tags
8672
    $text = preg_replace('/(<(script|style)\b[^>]*>).*?(<\/\2>)/is', "$1$3", $text);
8673
    $text = api_html_entity_decode($text);
8674
    $out_res = api_remove_tags_with_space($text, false);
8675
    $postfix = "...";
8676
    if (strlen($out_res) > $number) {
8677
        $out_res = substr($out_res, 0, $number).$postfix;
8678
    }
8679
8680
    return $out_res;
8681
}
8682
8683
/**
8684
 * Replace tags with a space in a text.
8685
 * If $in_double_quote_replace, replace " with '' (for HTML attribute purpose, for exemple).
8686
 *
8687
 * @return string
8688
 *
8689
 * @author hubert borderiou
8690
 */
8691
function api_remove_tags_with_space($in_html, $in_double_quote_replace = true)
8692
{
8693
    $out_res = $in_html;
8694
    if ($in_double_quote_replace) {
8695
        $out_res = str_replace('"', "''", $out_res);
8696
    }
8697
    // avoid text stuck together when tags are removed, adding a space after >
8698
    $out_res = str_replace(">", "> ", $out_res);
8699
    $out_res = strip_tags($out_res);
8700
8701
    return $out_res;
8702
}
8703
8704
/**
8705
 * If true, the drh can access all content (courses, users) inside a session.
8706
 *
8707
 * @return bool
8708
 */
8709
function api_drh_can_access_all_session_content()
8710
{
8711
    return api_get_setting('drh_can_access_all_session_content') === 'true';
8712
}
8713
8714
/**
8715
 * @param string $tool
8716
 * @param string $setting
8717
 * @param int    $defaultValue
8718
 *
8719
 * @return string
8720
 */
8721
function api_get_default_tool_setting($tool, $setting, $defaultValue)
8722
{
8723
    global $_configuration;
8724
    if (isset($_configuration[$tool]) &&
8725
        isset($_configuration[$tool]['default_settings']) &&
8726
        isset($_configuration[$tool]['default_settings'][$setting])
8727
    ) {
8728
        return $_configuration[$tool]['default_settings'][$setting];
8729
    }
8730
8731
    return $defaultValue;
8732
}
8733
8734
/**
8735
 * Checks if user can login as another user.
8736
 *
8737
 * @param int $loginAsUserId the user id to log in
8738
 * @param int $userId        my user id
8739
 *
8740
 * @return bool
8741
 */
8742
function api_can_login_as($loginAsUserId, $userId = null)
8743
{
8744
    if (empty($userId)) {
8745
        $userId = api_get_user_id();
8746
    }
8747
    if ($loginAsUserId == $userId) {
8748
        return false;
8749
    }
8750
8751
    if (empty($loginAsUserId)) {
8752
        return false;
8753
    }
8754
8755
    if ($loginAsUserId != strval(intval($loginAsUserId))) {
8756
        return false;
8757
    }
8758
8759
    // Check if the user to login is an admin
8760
    if (api_is_platform_admin_by_id($loginAsUserId)) {
8761
        // Only super admins can login to admin accounts
8762
        if (!api_global_admin_can_edit_admin($loginAsUserId)) {
8763
            return false;
8764
        }
8765
    }
8766
8767
    $userInfo = api_get_user_info($loginAsUserId);
8768
    $isDrh = function () use ($loginAsUserId) {
8769
        if (api_is_drh()) {
8770
            if (api_drh_can_access_all_session_content()) {
8771
                $users = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus(
8772
                    'drh_all',
8773
                    api_get_user_id()
8774
                );
8775
                $userList = [];
8776
                if (is_array($users)) {
8777
                    foreach ($users as $user) {
8778
                        $userList[] = $user['user_id'];
8779
                    }
8780
                }
8781
                if (in_array($loginAsUserId, $userList)) {
8782
                    return true;
8783
                }
8784
            } else {
8785
                if (api_is_drh() &&
8786
                    UserManager::is_user_followed_by_drh($loginAsUserId, api_get_user_id())
8787
                ) {
8788
                    return true;
8789
                }
8790
            }
8791
        }
8792
8793
        return false;
8794
    };
8795
8796
    $loginAsStatusForSessionAdmins = [STUDENT];
8797
8798
    if (api_get_configuration_value('allow_session_admin_login_as_teacher')) {
8799
        $loginAsStatusForSessionAdmins[] = COURSEMANAGER;
8800
    }
8801
8802
    return api_is_platform_admin() ||
8803
        (api_is_session_admin() && in_array($userInfo['status'], $loginAsStatusForSessionAdmins)) ||
8804
        $isDrh();
8805
}
8806
8807
/**
8808
 * @return bool
8809
 */
8810
function api_is_allowed_in_course()
8811
{
8812
    if (api_is_platform_admin()) {
8813
        return true;
8814
    }
8815
8816
    return Session::read('is_allowed_in_course');
8817
}
8818
8819
function api_set_cookie($name, $value, $expires = 0)
8820
{
8821
    $expires = (int) $expires;
8822
    setcookie($name, $value, $expires, '', '', api_is_https(), true);
8823
}
8824
8825
/**
8826
 * Set the cookie to go directly to the course code $in_firstpage
8827
 * after login.
8828
 *
8829
 * @param string $value is the course code of the course to go
8830
 */
8831
function api_set_firstpage_parameter($value)
8832
{
8833
    api_set_cookie('GotoCourse', $value);
8834
}
8835
8836
/**
8837
 * Delete the cookie to go directly to the course code $in_firstpage
8838
 * after login.
8839
 */
8840
function api_delete_firstpage_parameter()
8841
{
8842
    api_set_cookie('GotoCourse', '', time() - 3600);
8843
}
8844
8845
/**
8846
 * @return bool if course_code for direct course access after login is set
8847
 */
8848
function exist_firstpage_parameter()
8849
{
8850
    return isset($_COOKIE['GotoCourse']) && $_COOKIE['GotoCourse'] != '';
8851
}
8852
8853
/**
8854
 * @return string return the course_code of the course where user login
8855
 */
8856
function api_get_firstpage_parameter()
8857
{
8858
    return $_COOKIE['GotoCourse'];
8859
}
8860
8861
/**
8862
 * Return true on https install.
8863
 *
8864
 * @return bool
8865
 */
8866
function api_is_https()
8867
{
8868
    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...
8869
        $_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...
8870
    ) {
8871
        $isSecured = true;
8872
    } else {
8873
        if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') {
8874
            $isSecured = true;
8875
        } else {
8876
            $isSecured = false;
8877
            // last chance
8878
            if (!empty($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443) {
8879
                $isSecured = true;
8880
            }
8881
        }
8882
    }
8883
8884
    return $isSecured;
8885
}
8886
8887
/**
8888
 * Return protocol (http or https).
8889
 *
8890
 * @return string
8891
 */
8892
function api_get_protocol()
8893
{
8894
    return api_is_https() ? 'https' : 'http';
8895
}
8896
8897
/**
8898
 * Return a string where " are replaced with 2 '
8899
 * It is useful when you pass a PHP variable in a Javascript browser dialog
8900
 * e.g. : alert("<?php get_lang('Message') ?>");
8901
 * and message contains character ".
8902
 *
8903
 * @param string $in_text
8904
 *
8905
 * @return string
8906
 */
8907
function convert_double_quote_to_single($in_text)
8908
{
8909
    return api_preg_replace('/"/', "''", $in_text);
8910
}
8911
8912
/**
8913
 * Get origin.
8914
 *
8915
 * @param string
8916
 *
8917
 * @return string
8918
 */
8919
function api_get_origin()
8920
{
8921
    return isset($_REQUEST['origin']) ? urlencode(Security::remove_XSS(urlencode($_REQUEST['origin']))) : '';
8922
}
8923
8924
/**
8925
 * Warns an user that the portal reach certain limit.
8926
 *
8927
 * @param string $limitName
8928
 */
8929
function api_warn_hosting_contact($limitName)
8930
{
8931
    $hostingParams = api_get_configuration_value(1);
8932
    $email = null;
8933
8934
    if (!empty($hostingParams)) {
8935
        if (isset($hostingParams['hosting_contact_mail'])) {
8936
            $email = $hostingParams['hosting_contact_mail'];
8937
        }
8938
    }
8939
8940
    if (!empty($email)) {
8941
        $subject = get_lang('HostingWarningReached');
8942
        $body = get_lang('PortalName').': '.api_get_path(WEB_PATH)." \n ";
8943
        $body .= get_lang('PortalLimitType').': '.$limitName." \n ";
8944
        if (isset($hostingParams[$limitName])) {
8945
            $body .= get_lang('Value').': '.$hostingParams[$limitName];
8946
        }
8947
        api_mail_html(null, $email, $subject, $body);
8948
    }
8949
}
8950
8951
/**
8952
 * Gets value of a variable from app/config/configuration.php
8953
 * Variables that are not set in the configuration.php file but set elsewhere:
8954
 * - virtual_css_theme_folder (vchamilo plugin)
8955
 * - access_url (global.inc.php)
8956
 * - apc/apc_prefix (global.inc.php).
8957
 *
8958
 * @param string $variable
8959
 *
8960
 * @return bool|mixed
8961
 */
8962
function api_get_configuration_value($variable)
8963
{
8964
    global $_configuration;
8965
    // Check the current url id, id = 1 by default
8966
    $urlId = isset($_configuration['access_url']) ? (int) $_configuration['access_url'] : 1;
8967
8968
    $variable = trim($variable);
8969
8970
    // Check if variable exists
8971
    if (isset($_configuration[$variable])) {
8972
        if (is_array($_configuration[$variable])) {
8973
            // Check if it exists for the sub portal
8974
            if (array_key_exists($urlId, $_configuration[$variable])) {
8975
                return $_configuration[$variable][$urlId];
8976
            } else {
8977
                // Try to found element with id = 1 (master portal)
8978
                if (array_key_exists(1, $_configuration[$variable])) {
8979
                    return $_configuration[$variable][1];
8980
                }
8981
            }
8982
        }
8983
8984
        return $_configuration[$variable];
8985
    }
8986
8987
    return false;
8988
}
8989
8990
/**
8991
 * Retreives and returns a value in a hierarchical configuration array
8992
 * api_get_configuration_sub_value('a/b/c') returns api_get_configuration_value('a')['b']['c'].
8993
 *
8994
 * @param string $path      the successive array keys, separated by the separator
8995
 * @param mixed  $default   value to be returned if not found, null by default
8996
 * @param string $separator '/' by default
8997
 * @param array  $array     the active configuration array by default
8998
 *
8999
 * @return mixed the found value or $default
9000
 */
9001
function api_get_configuration_sub_value($path, $default = null, $separator = '/', $array = null)
9002
{
9003
    $pos = strpos($path, $separator);
9004
    if (false === $pos) {
9005
        if (is_null($array)) {
9006
            return api_get_configuration_value($path);
9007
        }
9008
        if (is_array($array) && array_key_exists($path, $array)) {
9009
            return $array[$path];
9010
        }
9011
9012
        return $default;
9013
    }
9014
    $key = substr($path, 0, $pos);
9015
    if (is_null($array)) {
9016
        $newArray = api_get_configuration_value($key);
9017
    } elseif (is_array($array) && array_key_exists($key, $array)) {
9018
        $newArray = $array[$key];
9019
    } else {
9020
        return $default;
9021
    }
9022
    if (is_array($newArray)) {
9023
        $newPath = substr($path, $pos + 1);
9024
9025
        return api_get_configuration_sub_value($newPath, $default, $separator, $newArray);
9026
    }
9027
9028
    return $default;
9029
}
9030
9031
/**
9032
 * Retrieves and returns a value in a hierarchical configuration array
9033
 * api_array_sub_value($array, 'a/b/c') returns $array['a']['b']['c'].
9034
 *
9035
 * @param array  $array     the recursive array that contains the value to be returned (or not)
9036
 * @param string $path      the successive array keys, separated by the separator
9037
 * @param mixed  $default   the value to be returned if not found
9038
 * @param string $separator the separator substring
9039
 *
9040
 * @return mixed the found value or $default
9041
 */
9042
function api_array_sub_value($array, $path, $default = null, $separator = '/')
9043
{
9044
    $pos = strpos($path, $separator);
9045
    if (false === $pos) {
9046
        if (is_array($array) && array_key_exists($path, $array)) {
9047
            return $array[$path];
9048
        }
9049
9050
        return $default;
9051
    }
9052
    $key = substr($path, 0, $pos);
9053
    if (is_array($array) && array_key_exists($key, $array)) {
9054
        $newArray = $array[$key];
9055
    } else {
9056
        return $default;
9057
    }
9058
    if (is_array($newArray)) {
9059
        $newPath = substr($path, $pos + 1);
9060
9061
        return api_array_sub_value($newArray, $newPath, $default);
9062
    }
9063
9064
    return $default;
9065
}
9066
9067
/**
9068
 * Returns supported image extensions in the portal.
9069
 *
9070
 * @param bool $supportVectors Whether vector images should also be accepted or not
9071
 *
9072
 * @return array Supported image extensions in the portal
9073
 */
9074
function api_get_supported_image_extensions($supportVectors = true)
9075
{
9076
    // jpg can also be called jpeg, jpe, jfif and jif. See https://en.wikipedia.org/wiki/JPEG#JPEG_filename_extensions
9077
    $supportedImageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'jpe', 'jfif', 'jif'];
9078
    if ($supportVectors) {
9079
        array_push($supportedImageExtensions, 'svg');
9080
    }
9081
    if (version_compare(PHP_VERSION, '5.5.0', '>=')) {
9082
        array_push($supportedImageExtensions, 'webp');
9083
    }
9084
9085
    return $supportedImageExtensions;
9086
}
9087
9088
/**
9089
 * This setting changes the registration status for the campus.
9090
 *
9091
 * @author Patrick Cool <[email protected]>, Ghent University
9092
 *
9093
 * @version August 2006
9094
 *
9095
 * @param bool $listCampus Whether we authorize
9096
 *
9097
 * @todo the $_settings should be reloaded here. => write api function for this and use this in global.inc.php also.
9098
 */
9099
function api_register_campus($listCampus = true)
9100
{
9101
    $tbl_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
9102
9103
    $sql = "UPDATE $tbl_settings SET selected_value='true' WHERE variable='registered'";
9104
    Database::query($sql);
9105
9106
    if (!$listCampus) {
9107
        $sql = "UPDATE $tbl_settings SET selected_value='true' WHERE variable='donotlistcampus'";
9108
        Database::query($sql);
9109
    }
9110
}
9111
9112
/**
9113
 * Checks whether current user is a student boss.
9114
 *
9115
 * @global array $_user
9116
 *
9117
 * @return bool
9118
 */
9119
function api_is_student_boss()
9120
{
9121
    $_user = api_get_user_info();
9122
9123
    return isset($_user['status']) && $_user['status'] == STUDENT_BOSS;
9124
}
9125
9126
/**
9127
 * Check whether the user type should be exclude.
9128
 * Such as invited or anonymous users.
9129
 *
9130
 * @param bool $checkDB Optional. Whether check the user status
9131
 * @param int  $userId  Options. The user id
9132
 *
9133
 * @return bool
9134
 */
9135
function api_is_excluded_user_type($checkDB = false, $userId = 0)
9136
{
9137
    if ($checkDB) {
9138
        $userId = empty($userId) ? api_get_user_id() : (int) $userId;
9139
9140
        if ($userId == 0) {
9141
            return true;
9142
        }
9143
9144
        $userInfo = api_get_user_info($userId);
9145
9146
        switch ($userInfo['status']) {
9147
            case INVITEE:
9148
            case ANONYMOUS:
9149
                return true;
9150
            default:
9151
                return false;
9152
        }
9153
    }
9154
9155
    $isInvited = api_is_invitee();
9156
    $isAnonymous = api_is_anonymous();
9157
9158
    if ($isInvited || $isAnonymous) {
9159
        return true;
9160
    }
9161
9162
    return false;
9163
}
9164
9165
/**
9166
 * Get the user status to ignore in reports.
9167
 *
9168
 * @param string $format Optional. The result type (array or string)
9169
 *
9170
 * @return array|string
9171
 */
9172
function api_get_users_status_ignored_in_reports($format = 'array')
9173
{
9174
    $excludedTypes = [
9175
        INVITEE,
9176
        ANONYMOUS,
9177
    ];
9178
9179
    if ($format == 'string') {
9180
        return implode(', ', $excludedTypes);
9181
    }
9182
9183
    return $excludedTypes;
9184
}
9185
9186
/**
9187
 * Set the Site Use Cookie Warning for 1 year.
9188
 */
9189
function api_set_site_use_cookie_warning_cookie()
9190
{
9191
    api_set_cookie('ChamiloUsesCookies', 'ok', time() + 31556926);
9192
}
9193
9194
/**
9195
 * Return true if the Site Use Cookie Warning Cookie warning exists.
9196
 *
9197
 * @return bool
9198
 */
9199
function api_site_use_cookie_warning_cookie_exist()
9200
{
9201
    return isset($_COOKIE['ChamiloUsesCookies']);
9202
}
9203
9204
/**
9205
 * Given a number of seconds, format the time to show hours, minutes and seconds.
9206
 *
9207
 * @param int    $time         The time in seconds
9208
 * @param string $originFormat Optional. PHP o JS
9209
 *
9210
 * @return string (00h00'00")
9211
 */
9212
function api_format_time($time, $originFormat = 'php')
9213
{
9214
    $h = get_lang('h');
9215
    $hours = $time / 3600;
9216
    $mins = ($time % 3600) / 60;
9217
    $secs = ($time % 60);
9218
9219
    if ($time < 0) {
9220
        $hours = 0;
9221
        $mins = 0;
9222
        $secs = 0;
9223
    }
9224
9225
    if ($originFormat == 'js') {
9226
        $formattedTime = trim(sprintf("%02d : %02d : %02d", $hours, $mins, $secs));
9227
    } else {
9228
        $formattedTime = trim(sprintf("%02d$h%02d'%02d\"", $hours, $mins, $secs));
9229
    }
9230
9231
    return $formattedTime;
9232
}
9233
9234
/**
9235
 * Create a new empty directory with index.html file.
9236
 *
9237
 * @param string $name            The new directory name
9238
 * @param string $parentDirectory Directory parent directory name
9239
 *
9240
 * @return bool Return true if the directory was create. Otherwise return false
9241
 */
9242
function api_create_protected_dir($name, $parentDirectory)
9243
{
9244
    $isCreated = false;
9245
9246
    if (!is_writable($parentDirectory)) {
9247
        return false;
9248
    }
9249
9250
    $fullPath = $parentDirectory.api_replace_dangerous_char($name);
9251
9252
    if (mkdir($fullPath, api_get_permissions_for_new_directories(), true)) {
9253
        $fp = fopen($fullPath.'/index.html', 'w');
9254
9255
        if ($fp) {
0 ignored issues
show
introduced by
$fp is of type resource, thus it always evaluated to false.
Loading history...
9256
            if (fwrite($fp, '<html><head><title></title></head><body></body></html>')) {
9257
                $isCreated = true;
9258
            }
9259
        }
9260
9261
        fclose($fp);
9262
    }
9263
9264
    return $isCreated;
9265
}
9266
9267
/**
9268
 * Sends an HTML email using the phpmailer class (and multipart/alternative to downgrade gracefully)
9269
 * Sender name and email can be specified, if not specified
9270
 * name and email of the platform admin are used.
9271
 *
9272
 * @author Bert Vanderkimpen ICT&O UGent
9273
 * @author Yannick Warnier <[email protected]>
9274
 *
9275
 * @param string    name of recipient
9276
 * @param string    email of recipient
9277
 * @param string    email subject
9278
 * @param string    email body
9279
 * @param string    sender name
9280
 * @param string    sender e-mail
9281
 * @param array  $extra_headers        in form $headers = array($name => $value) to allow parsing
9282
 * @param array  $data_file            (path and filename)
9283
 * @param bool   $embedded_image       True for attaching a embedded file inside content html (optional)
9284
 * @param array  $additionalParameters
9285
 * @param string $sendErrorTo          If there's an error while sending the email, $sendErrorTo will receive a notification
9286
 *
9287
 * @return int true if mail was sent
9288
 *
9289
 * @see             PHPMailer.php
9290
 */
9291
function api_mail_html(
9292
    $recipient_name,
9293
    $recipient_email,
9294
    $subject,
9295
    $message,
9296
    $senderName = '',
9297
    $senderEmail = '',
9298
    $extra_headers = [],
9299
    $data_file = [],
9300
    $embedded_image = false,
9301
    $additionalParameters = [],
9302
    $sendErrorTo = ''
9303
) {
9304
    global $platform_email;
9305
9306
    if (true === api_get_configuration_value('disable_send_mail')) {
9307
        return true;
9308
    }
9309
9310
    $mail = new PHPMailer();
9311
    $mail->Mailer = $platform_email['SMTP_MAILER'];
9312
    $mail->Host = $platform_email['SMTP_HOST'];
9313
    $mail->Port = $platform_email['SMTP_PORT'];
9314
    $mail->CharSet = isset($platform_email['SMTP_CHARSET']) ? $platform_email['SMTP_CHARSET'] : 'UTF-8';
9315
    // Stay far below SMTP protocol 980 chars limit.
9316
    $mail->WordWrap = 200;
9317
    $mail->SMTPOptions = $platform_email['SMTPOptions'] ?? [];
9318
9319
    if ($platform_email['SMTP_AUTH']) {
9320
        $mail->SMTPAuth = 1;
9321
        $mail->Username = $platform_email['SMTP_USER'];
9322
        $mail->Password = $platform_email['SMTP_PASS'];
9323
        if (isset($platform_email['SMTP_SECURE'])) {
9324
            $mail->SMTPSecure = $platform_email['SMTP_SECURE'];
9325
        }
9326
    }
9327
    $mail->SMTPDebug = isset($platform_email['SMTP_DEBUG']) ? $platform_email['SMTP_DEBUG'] : 0;
9328
9329
    // 5 = low, 1 = high
9330
    $mail->Priority = 3;
9331
    $mail->SMTPKeepAlive = true;
9332
9333
    api_set_noreply_and_from_address_to_mailer(
9334
        $mail,
9335
        ['name' => $senderName, 'email' => $senderEmail],
9336
        !empty($extra_headers['reply_to']) ? $extra_headers['reply_to'] : []
9337
    );
9338
9339
    if (!empty($sendErrorTo) && PHPMailer::ValidateAddress($sendErrorTo)) {
9340
        $mail->AddCustomHeader('Errors-To', $sendErrorTo);
9341
    }
9342
9343
    unset($extra_headers['reply_to']);
9344
9345
    $mail->Subject = $subject;
9346
    $mail->AltBody = strip_tags(
9347
        str_replace('<br />', "\n", api_html_entity_decode($message))
9348
    );
9349
9350
    $list = api_get_configuration_value('send_all_emails_to');
9351
    if (!empty($list) && isset($list['emails'])) {
9352
        foreach ($list['emails'] as $email) {
9353
            $mail->AddAddress($email);
9354
        }
9355
    }
9356
9357
    // Send embedded image.
9358
    if ($embedded_image) {
9359
        // Get all images html inside content.
9360
        preg_match_all("/<img\s+.*?src=[\"\']?([^\"\' >]*)[\"\']?[^>]*>/i", $message, $m);
9361
        // Prepare new tag images.
9362
        $new_images_html = [];
9363
        $i = 1;
9364
        if (!empty($m[1])) {
9365
            foreach ($m[1] as $image_path) {
9366
                $real_path = realpath($image_path);
9367
                $filename = basename($image_path);
9368
                $image_cid = $filename.'_'.$i;
9369
                $encoding = 'base64';
9370
                $image_type = mime_content_type($real_path);
9371
                $mail->AddEmbeddedImage(
9372
                    $real_path,
9373
                    $image_cid,
9374
                    $filename,
9375
                    $encoding,
9376
                    $image_type
9377
                );
9378
                $new_images_html[] = '<img src="cid:'.$image_cid.'" />';
9379
                $i++;
9380
            }
9381
        }
9382
9383
        // Replace origin image for new embedded image html.
9384
        $x = 0;
9385
        if (!empty($m[0])) {
9386
            foreach ($m[0] as $orig_img) {
9387
                $message = str_replace($orig_img, $new_images_html[$x], $message);
9388
                $x++;
9389
            }
9390
        }
9391
    }
9392
9393
    $mailView = new Template(null, false, false, false, false, false, false);
9394
9395
    $noReply = api_get_setting('noreply_email_address');
9396
    if (!empty($noReply)) {
9397
        $message .= '<br />'.get_lang('ThisIsAutomaticEmailNoReply');
9398
    }
9399
    $mailView->assign('content', $message);
9400
9401
    if (isset($additionalParameters['link'])) {
9402
        $mailView->assign('link', $additionalParameters['link']);
9403
    }
9404
    $mailView->assign('mail_header_style', api_get_configuration_value('mail_header_style'));
9405
    $mailView->assign('mail_content_style', api_get_configuration_value('mail_content_style'));
9406
    $mailView->assign('include_ldjson', (empty($platform_email['EXCLUDE_JSON']) ? true : false));
9407
    $layout = $mailView->get_template('mail/mail.tpl');
9408
    $mail->Body = $mailView->fetch($layout);
9409
9410
    // Attachment.
9411
    if (!empty($data_file)) {
9412
        foreach ($data_file as $file_attach) {
9413
            if (!empty($file_attach['path']) && !empty($file_attach['filename'])) {
9414
                $mail->AddAttachment($file_attach['path'], $file_attach['filename']);
9415
            }
9416
        }
9417
    }
9418
9419
    // Only valid addresses are accepted.
9420
    if (is_array($recipient_email)) {
9421
        foreach ($recipient_email as $dest) {
9422
            if (api_valid_email($dest)) {
9423
                $mail->AddAddress($dest, $recipient_name);
9424
            }
9425
        }
9426
    } else {
9427
        if (api_valid_email($recipient_email)) {
9428
            $mail->AddAddress($recipient_email, $recipient_name);
9429
        } else {
9430
            return 0;
9431
        }
9432
    }
9433
9434
    if (is_array($extra_headers) && count($extra_headers) > 0) {
9435
        foreach ($extra_headers as $key => $value) {
9436
            switch (strtolower($key)) {
9437
                case 'encoding':
9438
                case 'content-transfer-encoding':
9439
                    $mail->Encoding = $value;
9440
                    break;
9441
                case 'charset':
9442
                    $mail->CharSet = $value;
9443
                    break;
9444
                case 'contenttype':
9445
                case 'content-type':
9446
                    $mail->ContentType = $value;
9447
                    break;
9448
                default:
9449
                    $mail->AddCustomHeader($key, $value);
9450
                    break;
9451
            }
9452
        }
9453
    } else {
9454
        if (!empty($extra_headers)) {
9455
            $mail->AddCustomHeader($extra_headers);
9456
        }
9457
    }
9458
9459
    // WordWrap the html body (phpMailer only fixes AltBody) FS#2988
9460
    $mail->Body = $mail->WrapText($mail->Body, $mail->WordWrap);
9461
9462
    if (!empty($platform_email['DKIM']) &&
9463
        !empty($platform_email['DKIM_SELECTOR']) &&
9464
        !empty($platform_email['DKIM_DOMAIN']) &&
9465
        (!empty($platform_email['DKIM_PRIVATE_KEY_STRING']) || !empty($platform_email['DKIM_PRIVATE_KEY']))) {
9466
        $mail->DKIM_selector = $platform_email['DKIM_SELECTOR'];
9467
        $mail->DKIM_domain = $platform_email['DKIM_DOMAIN'];
9468
        if (!empty($platform_email['SMTP_UNIQUE_SENDER'])) {
9469
            $mail->DKIM_identity = $platform_email['SMTP_FROM_EMAIL'];
9470
        }
9471
        $mail->DKIM_private_string = $platform_email['DKIM_PRIVATE_KEY_STRING'];
9472
        $mail->DKIM_private = $platform_email['DKIM_PRIVATE_KEY'];
9473
    }
9474
9475
    // Send the mail message.
9476
    $sent = $mail->Send();
9477
    if (!$sent) {
9478
        error_log('ERROR: mail not sent to '.$recipient_name.' ('.$recipient_email.') because of '.$mail->ErrorInfo.'<br />');
9479
    }
9480
9481
    if ($mail->SMTPDebug > 1) {
9482
        error_log(
9483
            "Mail debug:: ".
9484
            "Protocol: ".$mail->Mailer.' :: '.
9485
            "Host/Port: ".$mail->Host.':'.$mail->Port.' :: '.
9486
            "Authent/Open: ".($mail->SMTPAuth ? 'Authent' : 'Open').' :: '.
9487
            ($mail->SMTPAuth ? "  User/Pass: ".$mail->Username.':'.$mail->Password : '').' :: '.
9488
            "Sender: ".$mail->Sender.
9489
            "Recipient email: ".$recipient_email.
9490
            "Subject: ".$subject
9491
        );
9492
    }
9493
9494
    if (!$sent) {
9495
        return 0;
9496
    }
9497
9498
    if (!empty($additionalParameters)) {
9499
        $plugin = new AppPlugin();
9500
        $smsPlugin = $plugin->getSMSPluginLibrary();
9501
        if ($smsPlugin) {
0 ignored issues
show
introduced by
$smsPlugin is of type SmsPluginLibraryInterface, thus it always evaluated to true.
Loading history...
9502
            $smsPlugin->send($additionalParameters);
9503
        }
9504
    }
9505
9506
    // Clear all the addresses.
9507
    $mail->ClearAddresses();
9508
9509
    // Clear all attachments
9510
    $mail->ClearAttachments();
9511
9512
    return 1;
9513
}
9514
9515
/**
9516
 * Checks access to a course group.
9517
 *
9518
 * @param string $tool       Possible values: GroupManager::GROUP_TOOL_*
9519
 * @param bool   $showHeader
9520
 */
9521
function api_protect_course_group($tool, $showHeader = true)
9522
{
9523
    $groupId = api_get_group_id();
9524
    if (!empty($groupId)) {
9525
        if (api_is_platform_admin()) {
9526
            return true;
9527
        }
9528
9529
        if (api_is_allowed_to_edit(false, true, true)) {
9530
            return true;
9531
        }
9532
9533
        $userId = api_get_user_id();
9534
        $sessionId = api_get_session_id();
9535
        if (!empty($sessionId)) {
9536
            if (api_is_coach($sessionId, api_get_course_int_id())) {
9537
                return true;
9538
            }
9539
9540
            if (api_is_drh()) {
9541
                if (SessionManager::isUserSubscribedAsHRM($sessionId, $userId)) {
9542
                    return true;
9543
                }
9544
            }
9545
        }
9546
9547
        $groupInfo = GroupManager::get_group_properties($groupId);
9548
9549
        // Group doesn't exists
9550
        if (empty($groupInfo)) {
9551
            api_not_allowed($showHeader);
9552
        }
9553
9554
        // Check group access
9555
        $allow = GroupManager::user_has_access(
9556
            $userId,
9557
            $groupInfo['iid'],
9558
            $tool
9559
        );
9560
9561
        if (!$allow) {
9562
            api_not_allowed($showHeader);
9563
        }
9564
    }
9565
9566
    return false;
9567
}
9568
9569
/**
9570
 * Check if a date is in a date range.
9571
 *
9572
 * @param datetime $startDate
9573
 * @param datetime $endDate
9574
 * @param datetime $currentDate
9575
 *
9576
 * @return bool true if date is in rage, false otherwise
9577
 */
9578
function api_is_date_in_date_range($startDate, $endDate, $currentDate = null)
9579
{
9580
    $startDate = strtotime(api_get_local_time($startDate));
9581
    $endDate = strtotime(api_get_local_time($endDate));
9582
    $currentDate = strtotime(api_get_local_time($currentDate));
9583
9584
    if ($currentDate >= $startDate && $currentDate <= $endDate) {
9585
        return true;
9586
    }
9587
9588
    return false;
9589
}
9590
9591
/**
9592
 * Eliminate the duplicates of a multidimensional array by sending the key.
9593
 *
9594
 * @param array $array multidimensional array
9595
 * @param int   $key   key to find to compare
9596
 *
9597
 * @return array
9598
 */
9599
function api_unique_multidim_array($array, $key)
9600
{
9601
    $temp_array = [];
9602
    $i = 0;
9603
    $key_array = [];
9604
9605
    foreach ($array as $val) {
9606
        if (!in_array($val[$key], $key_array)) {
9607
            $key_array[$i] = $val[$key];
9608
            $temp_array[$i] = $val;
9609
        }
9610
        $i++;
9611
    }
9612
9613
    return $temp_array;
9614
}
9615
9616
/**
9617
 * Limit the access to Session Admins when the limit_session_admin_role
9618
 * configuration variable is set to true.
9619
 */
9620
function api_protect_limit_for_session_admin()
9621
{
9622
    $limitAdmin = api_get_setting('limit_session_admin_role');
9623
    if (api_is_session_admin() && $limitAdmin === 'true') {
9624
        api_not_allowed(true);
9625
    }
9626
}
9627
9628
/**
9629
 * Limits that a session admin has access to list users.
9630
 * When limit_session_admin_list_users configuration variable is set to true.
9631
 */
9632
function api_protect_session_admin_list_users()
9633
{
9634
    $limitAdmin = api_get_configuration_value('limit_session_admin_list_users');
9635
9636
    if (api_is_session_admin() && true === $limitAdmin) {
9637
        api_not_allowed(true);
9638
    }
9639
}
9640
9641
/**
9642
 * @return bool
9643
 */
9644
function api_is_student_view_active()
9645
{
9646
    $studentView = Session::read('studentview');
9647
9648
    return $studentView == 'studentview';
9649
}
9650
9651
/**
9652
 * Adds a file inside the upload/$type/id.
9653
 *
9654
 * @param string $type
9655
 * @param array  $file
9656
 * @param int    $itemId
9657
 * @param string $cropParameters
9658
 *
9659
 * @return array|bool
9660
 */
9661
function api_upload_file($type, $file, $itemId, $cropParameters = '')
9662
{
9663
    $upload = process_uploaded_file($file);
9664
    if ($upload) {
9665
        $name = api_replace_dangerous_char($file['name']);
9666
9667
        // No "dangerous" files
9668
        $name = disable_dangerous_file($name);
9669
9670
        $pathId = '/'.substr((string) $itemId, 0, 1).'/'.$itemId.'/';
9671
        $path = api_get_path(SYS_UPLOAD_PATH).$type.$pathId;
9672
9673
        if (!is_dir($path)) {
9674
            mkdir($path, api_get_permissions_for_new_directories(), true);
9675
        }
9676
9677
        $pathToSave = $path.$name;
9678
        $result = moveUploadedFile($file, $pathToSave);
9679
9680
        if ($result) {
9681
            if (!empty($cropParameters)) {
9682
                $image = new Image($pathToSave);
9683
                $image->crop($cropParameters);
9684
            }
9685
9686
            return ['path_to_save' => $pathId.$name];
9687
        }
9688
    }
9689
9690
    return false;
9691
}
9692
9693
/**
9694
 * @param string $type
9695
 * @param int    $itemId
9696
 * @param string $file
9697
 *
9698
 * @return bool
9699
 */
9700
function api_get_uploaded_web_url($type, $itemId, $file)
9701
{
9702
    return api_get_uploaded_file($type, $itemId, $file, true);
9703
}
9704
9705
/**
9706
 * @param string $type
9707
 * @param int    $itemId
9708
 * @param string $file
9709
 * @param bool   $getUrl
9710
 *
9711
 * @return bool
9712
 */
9713
function api_get_uploaded_file($type, $itemId, $file, $getUrl = false)
9714
{
9715
    $itemId = (int) $itemId;
9716
    $pathId = '/'.substr((string) $itemId, 0, 1).'/'.$itemId.'/';
9717
    $path = api_get_path(SYS_UPLOAD_PATH).$type.$pathId;
9718
    $file = basename($file);
9719
    $file = $path.'/'.$file;
9720
    if (Security::check_abs_path($file, $path) && is_file($file) && file_exists($file)) {
9721
        if ($getUrl) {
9722
            return str_replace(api_get_path(SYS_UPLOAD_PATH), api_get_path(WEB_UPLOAD_PATH), $file);
9723
        }
9724
9725
        return $file;
9726
    }
9727
9728
    return false;
9729
}
9730
9731
/**
9732
 * @param string $type
9733
 * @param int    $itemId
9734
 * @param string $file
9735
 * @param string $title
9736
 */
9737
function api_download_uploaded_file($type, $itemId, $file, $title = '')
9738
{
9739
    $file = api_get_uploaded_file($type, $itemId, $file);
9740
    if ($file) {
9741
        if (Security::check_abs_path($file, api_get_path(SYS_UPLOAD_PATH).$type)) {
9742
            DocumentManager::file_send_for_download($file, true, $title);
9743
            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...
9744
        }
9745
    }
9746
    api_not_allowed(true);
9747
}
9748
9749
/**
9750
 * @param string $type
9751
 * @param string $file
9752
 */
9753
function api_remove_uploaded_file($type, $file)
9754
{
9755
    $typePath = api_get_path(SYS_UPLOAD_PATH).$type;
9756
    $path = $typePath.'/'.$file;
9757
    if (Security::check_abs_path($path, $typePath) && file_exists($path) && is_file($path)) {
9758
        unlink($path);
9759
    }
9760
}
9761
9762
/**
9763
 * @param string $type
9764
 * @param int    $itemId
9765
 * @param string $file
9766
 *
9767
 * @return bool
9768
 */
9769
function api_remove_uploaded_file_by_id($type, $itemId, $file)
9770
{
9771
    $file = api_get_uploaded_file($type, $itemId, $file, false);
9772
    $typePath = api_get_path(SYS_UPLOAD_PATH).$type;
9773
    if (Security::check_abs_path($file, $typePath) && file_exists($file) && is_file($file)) {
9774
        unlink($file);
9775
9776
        return true;
9777
    }
9778
9779
    return false;
9780
}
9781
9782
/**
9783
 * Converts string value to float value.
9784
 *
9785
 * 3.141516 => 3.141516
9786
 * 3,141516 => 3.141516
9787
 *
9788
 * @todo WIP
9789
 *
9790
 * @param string $number
9791
 *
9792
 * @return float
9793
 */
9794
function api_float_val($number)
9795
{
9796
    $number = (float) str_replace(',', '.', trim($number));
9797
9798
    return $number;
9799
}
9800
9801
/**
9802
 * Converts float values
9803
 * Example if $decimals = 2.
9804
 *
9805
 * 3.141516 => 3.14
9806
 * 3,141516 => 3,14
9807
 *
9808
 * @param string $number            number in iso code
9809
 * @param int    $decimals
9810
 * @param string $decimalSeparator
9811
 * @param string $thousandSeparator
9812
 *
9813
 * @return bool|string
9814
 */
9815
function api_number_format($number, $decimals = 0, $decimalSeparator = '.', $thousandSeparator = ',')
9816
{
9817
    $number = api_float_val($number);
9818
9819
    return number_format($number, $decimals, $decimalSeparator, $thousandSeparator);
9820
}
9821
9822
/**
9823
 * Set location url with a exit break by default.
9824
 *
9825
 * @param string $url
9826
 * @param bool   $exit
9827
 */
9828
function api_location($url, $exit = true)
9829
{
9830
    header('Location: '.$url);
9831
9832
    if ($exit) {
9833
        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...
9834
    }
9835
}
9836
9837
/**
9838
 * @return string
9839
 */
9840
function api_get_web_url()
9841
{
9842
    if (api_get_setting('server_type') === 'test') {
9843
        return api_get_path(WEB_PATH).'web/app_dev.php/';
9844
    } else {
9845
        return api_get_path(WEB_PATH).'web/';
9846
    }
9847
}
9848
9849
/**
9850
 * @param string $from
9851
 * @param string $to
9852
 *
9853
 * @return string
9854
 */
9855
function api_get_relative_path($from, $to)
9856
{
9857
    // some compatibility fixes for Windows paths
9858
    $from = is_dir($from) ? rtrim($from, '\/').'/' : $from;
9859
    $to = is_dir($to) ? rtrim($to, '\/').'/' : $to;
9860
    $from = str_replace('\\', '/', $from);
9861
    $to = str_replace('\\', '/', $to);
9862
9863
    $from = explode('/', $from);
9864
    $to = explode('/', $to);
9865
    $relPath = $to;
9866
9867
    foreach ($from as $depth => $dir) {
9868
        // find first non-matching dir
9869
        if ($dir === $to[$depth]) {
9870
            // ignore this directory
9871
            array_shift($relPath);
9872
        } else {
9873
            // get number of remaining dirs to $from
9874
            $remaining = count($from) - $depth;
9875
            if ($remaining > 1) {
9876
                // add traversals up to first matching dir
9877
                $padLength = (count($relPath) + $remaining - 1) * -1;
9878
                $relPath = array_pad($relPath, $padLength, '..');
9879
                break;
9880
            } else {
9881
                $relPath[0] = './'.$relPath[0];
9882
            }
9883
        }
9884
    }
9885
9886
    return implode('/', $relPath);
9887
}
9888
9889
/**
9890
 * Unserialize content using Brummann\Polyfill\Unserialize.
9891
 *
9892
 * @param string $type
9893
 * @param string $serialized
9894
 *
9895
 * @return mixed
9896
 */
9897
function api_unserialize_content($type, $serialized, $ignoreErrors = false)
9898
{
9899
    switch ($type) {
9900
        case 'career':
9901
        case 'sequence_graph':
9902
            $allowedClasses = [Graph::class, VerticesMap::class, Vertices::class, Edges::class];
9903
            break;
9904
        case 'lp':
9905
            $allowedClasses = [
9906
                learnpath::class,
9907
                learnpathItem::class,
9908
                aicc::class,
9909
                aiccBlock::class,
9910
                aiccItem::class,
9911
                aiccObjective::class,
9912
                aiccResource::class,
9913
                scorm::class,
9914
                scormItem::class,
9915
                scormMetadata::class,
9916
                scormOrganization::class,
9917
                scormResource::class,
9918
                Link::class,
9919
                LpItem::class,
9920
            ];
9921
            break;
9922
        case 'course':
9923
            $allowedClasses = [
9924
                Course::class,
9925
                Announcement::class,
9926
                Attendance::class,
9927
                CalendarEvent::class,
9928
                CourseCopyLearnpath::class,
9929
                CourseCopyTestCategory::class,
9930
                CourseDescription::class,
9931
                CourseSession::class,
9932
                Document::class,
9933
                Forum::class,
9934
                ForumCategory::class,
9935
                ForumPost::class,
9936
                ForumTopic::class,
9937
                Glossary::class,
9938
                GradeBookBackup::class,
9939
                Link::class,
9940
                LinkCategory::class,
9941
                Quiz::class,
9942
                QuizQuestion::class,
9943
                QuizQuestionOption::class,
9944
                ScormDocument::class,
9945
                Survey::class,
9946
                SurveyInvitation::class,
9947
                SurveyQuestion::class,
9948
                Thematic::class,
9949
                ToolIntro::class,
9950
                Wiki::class,
9951
                Work::class,
9952
                stdClass::class,
9953
            ];
9954
            break;
9955
        case 'not_allowed_classes':
9956
        default:
9957
            $allowedClasses = false;
9958
    }
9959
9960
    if ($ignoreErrors) {
9961
        return @Unserialize::unserialize(
9962
            $serialized,
9963
            ['allowed_classes' => $allowedClasses]
9964
        );
9965
    }
9966
9967
    return Unserialize::unserialize(
9968
        $serialized,
9969
        ['allowed_classes' => $allowedClasses]
9970
    );
9971
}
9972
9973
/**
9974
 * Set the From and ReplyTo properties to PHPMailer instance.
9975
 *
9976
 * @throws \PHPMailer\PHPMailer\Exception
9977
 */
9978
function api_set_noreply_and_from_address_to_mailer(PHPMailer $mailer, array $sender, array $replyToAddress = [])
9979
{
9980
    $platformEmail = $GLOBALS['platform_email'];
9981
9982
    $noReplyAddress = api_get_setting('noreply_email_address');
9983
    $avoidReplyToAddress = false;
9984
9985
    if (!empty($noReplyAddress)) {
9986
        $avoidReplyToAddress = api_get_configuration_value('mail_no_reply_avoid_reply_to');
9987
    }
9988
9989
    $notification = new Notification();
9990
    // If the parameter is set don't use the admin.
9991
    $senderName = !empty($sender['name']) ? $sender['name'] : $notification->getDefaultPlatformSenderName();
9992
    $senderEmail = !empty($sender['email']) ? $sender['email'] : $notification->getDefaultPlatformSenderEmail();
9993
9994
    // Send errors to the platform admin
9995
    $adminEmail = api_get_setting('emailAdministrator');
9996
    if (PHPMailer::ValidateAddress($adminEmail)) {
9997
        $mailer->AddCustomHeader('Errors-To: '.$adminEmail);
9998
    }
9999
10000
    // Reply to first
10001
    if (!$avoidReplyToAddress) {
10002
        if (
10003
            !empty($replyToAddress) &&
10004
            PHPMailer::ValidateAddress($replyToAddress['mail'])
10005
        ) {
10006
            $mailer->AddReplyTo($replyToAddress['mail'], $replyToAddress['name']);
10007
            //$mailer->Sender = $replyToAddress['mail'];
10008
        }
10009
    }
10010
10011
    //If the SMTP configuration only accept one sender
10012
    if (
10013
        isset($platformEmail['SMTP_UNIQUE_SENDER']) &&
10014
        $platformEmail['SMTP_UNIQUE_SENDER']
10015
    ) {
10016
        $senderName = $notification->getDefaultPlatformSenderName();
10017
        $senderEmail = $notification->getDefaultPlatformSenderEmail();
10018
10019
        if (PHPMailer::ValidateAddress($senderEmail)) {
10020
            //force-set Sender to $senderEmail, otherwise SetFrom only does it if it is currently empty
10021
            $mailer->Sender = $senderEmail;
10022
        }
10023
    }
10024
10025
    $mailer->SetFrom($senderEmail, $senderName, !$avoidReplyToAddress);
10026
}
10027
10028
/**
10029
 * @param string $template
10030
 *
10031
 * @return string
10032
 */
10033
function api_find_template($template)
10034
{
10035
    return Template::findTemplateFilePath($template);
10036
}
10037
10038
/**
10039
 * Returns an array of languages (English names like "english", "french", etc)
10040
 * to ISO 639-1 codes (fr, es, etc) for use (for example) to show flags
10041
 * Note: 'english' is returned as 'gb'.
10042
 *
10043
 * @return array
10044
 */
10045
function api_get_language_list_for_flag()
10046
{
10047
    $table = Database::get_main_table(TABLE_MAIN_LANGUAGE);
10048
    $sql = "SELECT english_name, isocode FROM $table
10049
            ORDER BY original_name ASC";
10050
    static $languages = [];
10051
    if (empty($languages)) {
10052
        $result = Database::query($sql);
10053
        while ($row = Database::fetch_array($result)) {
10054
            $languages[$row['english_name']] = $row['isocode'];
10055
        }
10056
        $languages['english'] = 'gb';
10057
    }
10058
10059
    return $languages;
10060
}
10061
10062
/**
10063
 * Generate the Javascript required for the on-page translation of
10064
 * multi-language strings.
10065
 *
10066
 * @throws Exception
10067
 *
10068
 * @return string
10069
 */
10070
function api_get_language_translate_html()
10071
{
10072
    $translate = api_get_configuration_value('translate_html');
10073
10074
    if (!$translate) {
10075
        return '';
10076
    }
10077
10078
    $languageList = api_get_languages();
10079
    $hideAll = '';
10080
    foreach ($languageList['all'] as $language) {
10081
        $hideAll .= '
10082
        $("span:lang('.$language['isocode'].')").filter(
10083
            function(e, val) {
10084
                // Only find the spans if they have set the lang
10085
                if ($(this).attr("lang") == null) {
10086
                    return false;
10087
                }
10088
10089
                // Ignore ckeditor classes
10090
                return !this.className.match(/cke(.*)/);
10091
        }).hide();'."\n";
10092
    }
10093
10094
    $userInfo = api_get_user_info();
10095
    $languageId = 0;
10096
    if (!empty($userInfo['language'])) {
10097
        $languageId = api_get_language_id($userInfo['language']);
10098
    } elseif (!empty($_GET['language'])) {
10099
        $languageId = api_get_language_id($_GET['language']);
10100
    }
10101
    $languageInfo = api_get_language_info($languageId);
10102
    $isoCode = 'en';
10103
10104
    if (!empty($languageInfo)) {
10105
        $isoCode = $languageInfo['isocode'];
10106
    }
10107
10108
    return '
10109
            $(function() {
10110
                '.$hideAll.'
10111
                var defaultLanguageFromUser = "'.$isoCode.'";
10112
10113
                $("span:lang('.$isoCode.')").filter(
10114
                    function() {
10115
                        // Ignore ckeditor classes
10116
                        return !this.className.match(/cke(.*)/);
10117
                }).show();
10118
10119
                var defaultLanguage = "";
10120
                var langFromUserFound = false;
10121
10122
                $(this).find("span").filter(
10123
                    function() {
10124
                        // Ignore ckeditor classes
10125
                        return !this.className.match(/cke(.*)/);
10126
                }).each(function() {
10127
                    defaultLanguage = $(this).attr("lang");
10128
                    if (defaultLanguage) {
10129
                        $(this).before().next("br").remove();
10130
                        if (defaultLanguageFromUser == defaultLanguage) {
10131
                            langFromUserFound = true;
10132
                        }
10133
                    }
10134
                });
10135
10136
                // Show default language
10137
                if (langFromUserFound == false && defaultLanguage) {
10138
                    $("span:lang("+defaultLanguage+")").filter(
10139
                    function() {
10140
                            // Ignore ckeditor classes
10141
                            return !this.className.match(/cke(.*)/);
10142
                    }).show();
10143
                }
10144
            });
10145
    ';
10146
}
10147
10148
/**
10149
 * Filter a multi-language HTML string (for the multi-language HTML
10150
 * feature) into the given language (strip the rest).
10151
 *
10152
 * @param string $htmlString The HTML string to "translate". Usually <p><span lang="en">Some string</span></p><p><span lang="fr">Une chaîne</span></p>
10153
 * @param string $language   The language in which we want to get the
10154
 *
10155
 * @throws Exception
10156
 *
10157
 * @return string The filtered string in the given language, or the full string if no translated string was identified
10158
 */
10159
function api_get_filtered_multilingual_HTML_string($htmlString, $language = null)
10160
{
10161
    if (api_get_configuration_value('translate_html') != true) {
10162
        return $htmlString;
10163
    }
10164
    $userInfo = api_get_user_info();
10165
    $languageId = 0;
10166
    if (!empty($language)) {
10167
        $languageId = api_get_language_id($language);
10168
    } elseif (!empty($userInfo['language'])) {
10169
        $languageId = api_get_language_id($userInfo['language']);
10170
    }
10171
    $languageInfo = api_get_language_info($languageId);
10172
    $isoCode = 'en';
10173
10174
    if (!empty($languageInfo)) {
10175
        $isoCode = $languageInfo['isocode'];
10176
    }
10177
10178
    // Split HTML in the separate language strings
10179
    // Note: some strings might look like <p><span ..>...</span></p> but others might be like combine 2 <span> in 1 <p>
10180
    if (!preg_match('/<span.*?lang="(\w\w)">/is', $htmlString)) {
10181
        return $htmlString;
10182
    }
10183
    $matches = [];
10184
    preg_match_all('/<span.*?lang="(\w\w)">(.*?)<\/span>/is', $htmlString, $matches);
10185
    if (!empty($matches)) {
10186
        // matches[0] are the full string
10187
        // matches[1] are the languages
10188
        // matches[2] are the strings
10189
        foreach ($matches[1] as $id => $match) {
10190
            if ($match == $isoCode) {
10191
                return $matches[2][$id];
10192
            }
10193
        }
10194
        // Could find the pattern but could not find our language. Return the first language found.
10195
        return $matches[2][0];
10196
    }
10197
    // Could not find pattern. Just return the whole string. We shouldn't get here.
10198
    return $htmlString;
10199
}
10200
10201
/**
10202
 * Get the print.css file for current theme.
10203
 * Only the file path or the file contents when $getFileContents is true.
10204
 */
10205
function api_get_print_css(bool $getFileContents = true, bool $useWebPath = false): string
10206
{
10207
    $sysCssPath = api_get_path(SYS_CSS_PATH);
10208
    $cssFile = $sysCssPath.'themes/'.api_get_visual_theme().'/print.css';
10209
10210
    if (!file_exists($cssFile)) {
10211
        $cssFile = $sysCssPath.'print.css';
10212
    }
10213
10214
    if ($getFileContents) {
10215
        return file_get_contents($cssFile);
10216
    }
10217
10218
    if ($useWebPath) {
10219
        return str_replace($sysCssPath, api_get_path(WEB_CSS_PATH), $cssFile);
10220
    }
10221
10222
    return $cssFile;
10223
}
10224
10225
function api_protect_webservices()
10226
{
10227
    if (api_get_configuration_value('disable_webservices')) {
10228
        echo "Webservices are disabled. \n";
10229
        echo "To enable, add \$_configuration['disable_webservices'] = true; in configuration.php";
10230
        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...
10231
    }
10232
}
10233
10234
function api_filename_has_blacklisted_stream_wrapper(string $filename)
10235
{
10236
    if (strpos($filename, '://') > 0) {
10237
        $wrappers = stream_get_wrappers();
10238
        $allowedWrappers = ['http', 'https', 'file'];
10239
10240
        foreach ($wrappers as $wrapper) {
10241
            if (in_array($wrapper, $allowedWrappers)) {
10242
                continue;
10243
            }
10244
10245
            if (stripos($filename, $wrapper.'://') === 0) {
10246
                return true;
10247
            }
10248
        }
10249
    }
10250
10251
    return false;
10252
}
10253