Passed
Pull Request — 1.11.x (#4388)
by Angel Fernando Quiroz
08:33
created

api_get_password_checker_js()   B

Complexity

Conditions 7
Paths 33

Size

Total Lines 78
Code Lines 46

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 46
c 1
b 0
f 0
nc 33
nop 2
dl 0
loc 78
rs 8.2448

How to fix   Long Method   

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

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