Passed
Push — master ( 5a5c46...59256e )
by Julito
08:25
created

api_user_has_role()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 5
c 1
b 0
f 0
nc 4
nop 2
dl 0
loc 11
rs 10
1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
use Chamilo\CoreBundle\Entity\AccessUrl;
6
use Chamilo\CoreBundle\Entity\Course;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Course. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
7
use Chamilo\CoreBundle\Entity\Language;
8
use Chamilo\CoreBundle\Entity\Session as SessionEntity;
9
use Chamilo\CoreBundle\Entity\SettingsCurrent;
10
use Chamilo\CoreBundle\Entity\User;
11
use Chamilo\CoreBundle\Entity\UserCourseCategory;
12
use Chamilo\CoreBundle\Framework\Container;
13
use Chamilo\CourseBundle\Entity\CGroup;
14
use Chamilo\CourseBundle\Entity\CLp;
15
use ChamiloSession as Session;
16
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
17
use Symfony\Component\Finder\Finder;
18
use Symfony\Component\Mime\Address;
19
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
20
use Symfony\Component\Security\Core\User\UserInterface;
21
use ZipStream\Option\Archive;
22
use ZipStream\ZipStream;
23
24
/**
25
 * This is a code library for Chamilo.
26
 * It is included by default in every Chamilo file (through including the global.inc.php)
27
 * This library is in process of being transferred to src/Chamilo/CoreBundle/Component/Utils/ChamiloApi.
28
 * Whenever a function is transferred to the ChamiloApi class, the places where it is used should include
29
 * the "use Chamilo\CoreBundle\Component\Utils\ChamiloApi;" statement.
30
 */
31
32
// PHP version requirement.
33
define('REQUIRED_PHP_VERSION', '8.0');
34
define('REQUIRED_MIN_MEMORY_LIMIT', '128');
35
define('REQUIRED_MIN_UPLOAD_MAX_FILESIZE', '10');
36
define('REQUIRED_MIN_POST_MAX_SIZE', '10');
37
38
// USER STATUS CONSTANTS
39
/** global status of a user: student */
40
define('STUDENT', 5);
41
/** global status of a user: course manager */
42
define('COURSEMANAGER', 1);
43
/** global status of a user: session admin */
44
define('SESSIONADMIN', 3);
45
/** global status of a user: human ressource manager */
46
define('DRH', 4);
47
/** global status of a user: human ressource manager */
48
define('ANONYMOUS', 6);
49
/** global status of a user: low security, necessary for inserting data from
50
 * the teacher through HTMLPurifier */
51
define('COURSEMANAGERLOWSECURITY', 10);
52
// Soft user status
53
define('PLATFORM_ADMIN', 11);
54
define('SESSION_COURSE_COACH', 12);
55
define('SESSION_GENERAL_COACH', 13);
56
define('COURSE_STUDENT', 14); //student subscribed in a course
57
define('SESSION_STUDENT', 15); //student subscribed in a session course
58
define('COURSE_TUTOR', 16); // student is tutor of a course (NOT in session)
59
define('STUDENT_BOSS', 17); // student is boss
60
define('INVITEE', 20);
61
define('HRM_REQUEST', 21); //HRM has request for vinculation with user
62
63
// COURSE VISIBILITY CONSTANTS
64
/** only visible for course admin */
65
define('COURSE_VISIBILITY_CLOSED', 0);
66
/** only visible for users registered in the course */
67
define('COURSE_VISIBILITY_REGISTERED', 1);
68
/** Open for all registered users on the platform */
69
define('COURSE_VISIBILITY_OPEN_PLATFORM', 2);
70
/** Open for the whole world */
71
define('COURSE_VISIBILITY_OPEN_WORLD', 3);
72
/** Invisible to all except admin */
73
define('COURSE_VISIBILITY_HIDDEN', 4);
74
75
define('COURSE_REQUEST_PENDING', 0);
76
define('COURSE_REQUEST_ACCEPTED', 1);
77
define('COURSE_REQUEST_REJECTED', 2);
78
define('DELETE_ACTION_ENABLED', false);
79
80
// EMAIL SENDING RECIPIENT CONSTANTS
81
define('SEND_EMAIL_EVERYONE', 1);
82
define('SEND_EMAIL_STUDENTS', 2);
83
define('SEND_EMAIL_TEACHERS', 3);
84
85
// SESSION VISIBILITY CONSTANTS
86
define('SESSION_VISIBLE_READ_ONLY', 1);
87
define('SESSION_VISIBLE', 2);
88
define('SESSION_INVISIBLE', 3); // not available
89
define('SESSION_AVAILABLE', 4);
90
91
define('SESSION_LINK_TARGET', '_self');
92
93
define('SUBSCRIBE_ALLOWED', 1);
94
define('SUBSCRIBE_NOT_ALLOWED', 0);
95
define('UNSUBSCRIBE_ALLOWED', 1);
96
define('UNSUBSCRIBE_NOT_ALLOWED', 0);
97
98
// SURVEY VISIBILITY CONSTANTS
99
define('SURVEY_VISIBLE_TUTOR', 0);
100
define('SURVEY_VISIBLE_TUTOR_STUDENT', 1);
101
define('SURVEY_VISIBLE_PUBLIC', 2);
102
103
// CONSTANTS defining all tools, using the english version
104
/* When you add a new tool you must add it into function api_get_tools_lists() too */
105
define('TOOL_DOCUMENT', 'document');
106
define('TOOL_LP_FINAL_ITEM', 'final_item');
107
define('TOOL_READOUT_TEXT', 'readout_text');
108
define('TOOL_THUMBNAIL', 'thumbnail');
109
define('TOOL_HOTPOTATOES', 'hotpotatoes');
110
define('TOOL_CALENDAR_EVENT', 'calendar_event');
111
define('TOOL_LINK', 'link');
112
define('TOOL_LINK_CATEGORY', 'link_category');
113
define('TOOL_COURSE_DESCRIPTION', 'course_description');
114
define('TOOL_SEARCH', 'search');
115
define('TOOL_LEARNPATH', 'learnpath');
116
define('TOOL_LEARNPATH_CATEGORY', 'learnpath_category');
117
define('TOOL_AGENDA', 'agenda');
118
define('TOOL_ANNOUNCEMENT', 'announcement');
119
define('TOOL_FORUM', 'forum');
120
define('TOOL_FORUM_CATEGORY', 'forum_category');
121
define('TOOL_FORUM_THREAD', 'forum_thread');
122
define('TOOL_FORUM_POST', 'forum_post');
123
define('TOOL_FORUM_ATTACH', 'forum_attachment');
124
define('TOOL_FORUM_THREAD_QUALIFY', 'forum_thread_qualify');
125
define('TOOL_THREAD', 'thread');
126
define('TOOL_POST', 'post');
127
define('TOOL_DROPBOX', 'dropbox');
128
define('TOOL_QUIZ', 'quiz');
129
define('TOOL_TEST_CATEGORY', 'test_category');
130
define('TOOL_USER', 'user');
131
define('TOOL_GROUP', 'group');
132
define('TOOL_BLOGS', 'blog_management');
133
define('TOOL_CHAT', 'chat');
134
define('TOOL_STUDENTPUBLICATION', 'student_publication');
135
define('TOOL_TRACKING', 'tracking');
136
define('TOOL_HOMEPAGE_LINK', 'homepage_link');
137
define('TOOL_COURSE_SETTING', 'course_setting');
138
define('TOOL_BACKUP', 'backup');
139
define('TOOL_COPY_COURSE_CONTENT', 'copy_course_content');
140
define('TOOL_RECYCLE_COURSE', 'recycle_course');
141
define('TOOL_COURSE_HOMEPAGE', 'course_homepage');
142
define('TOOL_COURSE_RIGHTS_OVERVIEW', 'course_rights');
143
define('TOOL_UPLOAD', 'file_upload');
144
define('TOOL_COURSE_MAINTENANCE', 'course_maintenance');
145
define('TOOL_SURVEY', 'survey');
146
//define('TOOL_WIKI', 'wiki');
147
define('TOOL_GLOSSARY', 'glossary');
148
define('TOOL_GRADEBOOK', 'gradebook');
149
define('TOOL_NOTEBOOK', 'notebook');
150
define('TOOL_ATTENDANCE', 'attendance');
151
define('TOOL_COURSE_PROGRESS', 'course_progress');
152
define('TOOL_PORTFOLIO', 'portfolio');
153
define('TOOL_PLAGIARISM', 'compilatio');
154
define('TOOL_XAPI', 'xapi');
155
156
// CONSTANTS defining Chamilo interface sections
157
define('SECTION_CAMPUS', 'mycampus');
158
define('SECTION_COURSES', 'mycourses');
159
define('SECTION_CATALOG', 'catalog');
160
define('SECTION_MYPROFILE', 'myprofile');
161
define('SECTION_MYAGENDA', 'myagenda');
162
define('SECTION_COURSE_ADMIN', 'course_admin');
163
define('SECTION_PLATFORM_ADMIN', 'platform_admin');
164
define('SECTION_MYGRADEBOOK', 'mygradebook');
165
define('SECTION_TRACKING', 'session_my_space');
166
define('SECTION_SOCIAL', 'social-network');
167
define('SECTION_DASHBOARD', 'dashboard');
168
define('SECTION_REPORTS', 'reports');
169
define('SECTION_GLOBAL', 'global');
170
define('SECTION_INCLUDE', 'include');
171
define('SECTION_CUSTOMPAGE', 'custompage');
172
173
// CONSTANT name for local authentication source
174
define('PLATFORM_AUTH_SOURCE', 'platform');
175
define('CAS_AUTH_SOURCE', 'cas');
176
define('LDAP_AUTH_SOURCE', 'extldap');
177
178
// event logs types
179
define('LOG_COURSE_DELETE', 'course_deleted');
180
define('LOG_COURSE_CREATE', 'course_created');
181
define('LOG_COURSE_SETTINGS_CHANGED', 'course_settings_changed');
182
183
// @todo replace 'soc_gr' with social_group
184
define('LOG_GROUP_PORTAL_CREATED', 'soc_gr_created');
185
define('LOG_GROUP_PORTAL_UPDATED', 'soc_gr_updated');
186
define('LOG_GROUP_PORTAL_DELETED', 'soc_gr_deleted');
187
define('LOG_GROUP_PORTAL_USER_DELETE_ALL', 'soc_gr_delete_users');
188
189
define('LOG_GROUP_PORTAL_ID', 'soc_gr_portal_id');
190
define('LOG_GROUP_PORTAL_REL_USER_ARRAY', 'soc_gr_user_array');
191
192
define('LOG_GROUP_PORTAL_USER_SUBSCRIBED', 'soc_gr_u_subs');
193
define('LOG_GROUP_PORTAL_USER_UNSUBSCRIBED', 'soc_gr_u_unsubs');
194
define('LOG_GROUP_PORTAL_USER_UPDATE_ROLE', 'soc_gr_update_role');
195
196
define('LOG_MESSAGE_DATA', 'message_data');
197
define('LOG_MESSAGE_DELETE', 'msg_deleted');
198
199
define('LOG_USER_DELETE', 'user_deleted');
200
define('LOG_USER_CREATE', 'user_created');
201
define('LOG_USER_UPDATE', 'user_updated');
202
define('LOG_USER_PASSWORD_UPDATE', 'user_password_updated');
203
define('LOG_USER_ENABLE', 'user_enable');
204
define('LOG_USER_DISABLE', 'user_disable');
205
define('LOG_USER_ANONYMIZE', 'user_anonymized');
206
define('LOG_USER_FIELD_CREATE', 'user_field_created');
207
define('LOG_USER_FIELD_DELETE', 'user_field_deleted');
208
define('LOG_SESSION_CREATE', 'session_created');
209
define('LOG_SESSION_DELETE', 'session_deleted');
210
define('LOG_SESSION_ADD_USER_COURSE', 'session_add_user_course');
211
define('LOG_SESSION_DELETE_USER_COURSE', 'session_delete_user_course');
212
define('LOG_SESSION_ADD_USER', 'session_add_user');
213
define('LOG_SESSION_DELETE_USER', 'session_delete_user');
214
define('LOG_SESSION_ADD_COURSE', 'session_add_course');
215
define('LOG_SESSION_DELETE_COURSE', 'session_delete_course');
216
define('LOG_SESSION_CATEGORY_CREATE', 'session_cat_created'); //changed in 1.9.8
217
define('LOG_SESSION_CATEGORY_DELETE', 'session_cat_deleted'); //changed in 1.9.8
218
define('LOG_CONFIGURATION_SETTINGS_CHANGE', 'settings_changed');
219
define('LOG_PLATFORM_LANGUAGE_CHANGE', 'platform_lng_changed'); //changed in 1.9.8
220
define('LOG_SUBSCRIBE_USER_TO_COURSE', 'user_subscribed');
221
define('LOG_UNSUBSCRIBE_USER_FROM_COURSE', 'user_unsubscribed');
222
define('LOG_ATTEMPTED_FORCED_LOGIN', 'attempted_forced_login');
223
define('LOG_PLUGIN_CHANGE', 'plugin_changed');
224
define('LOG_HOMEPAGE_CHANGED', 'homepage_changed');
225
define('LOG_PROMOTION_CREATE', 'promotion_created');
226
define('LOG_PROMOTION_DELETE', 'promotion_deleted');
227
define('LOG_CAREER_CREATE', 'career_created');
228
define('LOG_CAREER_DELETE', 'career_deleted');
229
define('LOG_USER_PERSONAL_DOC_DELETED', 'user_doc_deleted');
230
//define('LOG_WIKI_ACCESS', 'wiki_page_view');
231
// All results from an exercise
232
define('LOG_EXERCISE_RESULT_DELETE', 'exe_result_deleted');
233
// Logs only the one attempt
234
define('LOG_EXERCISE_ATTEMPT_DELETE', 'exe_attempt_deleted');
235
define('LOG_LP_ATTEMPT_DELETE', 'lp_attempt_deleted');
236
define('LOG_QUESTION_RESULT_DELETE', 'qst_attempt_deleted');
237
define('LOG_QUESTION_SCORE_UPDATE', 'score_attempt_updated');
238
239
define('LOG_MY_FOLDER_CREATE', 'my_folder_created');
240
define('LOG_MY_FOLDER_CHANGE', 'my_folder_changed');
241
define('LOG_MY_FOLDER_DELETE', 'my_folder_deleted');
242
define('LOG_MY_FOLDER_COPY', 'my_folder_copied');
243
define('LOG_MY_FOLDER_CUT', 'my_folder_cut');
244
define('LOG_MY_FOLDER_PASTE', 'my_folder_pasted');
245
define('LOG_MY_FOLDER_UPLOAD', 'my_folder_uploaded');
246
247
// Event logs data types (max 20 chars)
248
define('LOG_COURSE_CODE', 'course_code');
249
define('LOG_COURSE_ID', 'course_id');
250
define('LOG_USER_ID', 'user_id');
251
define('LOG_USER_OBJECT', 'user_object');
252
define('LOG_USER_FIELD_VARIABLE', 'user_field_variable');
253
define('LOG_SESSION_ID', 'session_id');
254
255
define('LOG_QUESTION_ID', 'question_id');
256
define('LOG_SESSION_CATEGORY_ID', 'session_category_id');
257
define('LOG_CONFIGURATION_SETTINGS_CATEGORY', 'settings_category');
258
define('LOG_CONFIGURATION_SETTINGS_VARIABLE', 'settings_variable');
259
define('LOG_PLATFORM_LANGUAGE', 'default_platform_language');
260
define('LOG_PLUGIN_UPLOAD', 'plugin_upload');
261
define('LOG_PLUGIN_ENABLE', 'plugin_enable');
262
define('LOG_PLUGIN_SETTINGS_CHANGE', 'plugin_settings_change');
263
define('LOG_CAREER_ID', 'career_id');
264
define('LOG_PROMOTION_ID', 'promotion_id');
265
define('LOG_GRADEBOOK_LOCKED', 'gradebook_locked');
266
define('LOG_GRADEBOOK_UNLOCKED', 'gradebook_unlocked');
267
define('LOG_GRADEBOOK_ID', 'gradebook_id');
268
//define('LOG_WIKI_PAGE_ID', 'wiki_page_id');
269
define('LOG_EXERCISE_ID', 'exercise_id');
270
define('LOG_EXERCISE_AND_USER_ID', 'exercise_and_user_id');
271
define('LOG_LP_ID', 'lp_id');
272
define('LOG_EXERCISE_ATTEMPT_QUESTION_ID', 'exercise_a_q_id');
273
define('LOG_EXERCISE_ATTEMPT', 'exe_id');
274
275
define('LOG_WORK_DIR_DELETE', 'work_dir_delete');
276
define('LOG_WORK_FILE_DELETE', 'work_file_delete');
277
define('LOG_WORK_DATA', 'work_data_array');
278
279
define('LOG_MY_FOLDER_PATH', 'path');
280
define('LOG_MY_FOLDER_NEW_PATH', 'new_path');
281
282
define('LOG_TERM_CONDITION_ACCEPTED', 'term_condition_accepted');
283
define('LOG_USER_CONFIRMED_EMAIL', 'user_confirmed_email');
284
define('LOG_USER_REMOVED_LEGAL_ACCEPT', 'user_removed_legal_accept');
285
286
define('LOG_USER_DELETE_ACCOUNT_REQUEST', 'user_delete_account_request');
287
288
define('LOG_QUESTION_CREATED', 'question_created');
289
define('LOG_QUESTION_UPDATED', 'question_updated');
290
define('LOG_QUESTION_DELETED', 'question_deleted');
291
define('LOG_QUESTION_REMOVED_FROM_QUIZ', 'question_removed_from_quiz');
292
293
define('LOG_SURVEY_ID', 'survey_id');
294
define('LOG_SURVEY_CREATED', 'survey_created');
295
define('LOG_SURVEY_DELETED', 'survey_deleted');
296
define('LOG_SURVEY_CLEAN_RESULTS', 'survey_clean_results');
297
define('USERNAME_PURIFIER', '/[^0-9A-Za-z_\.\$-]/');
298
299
//used when login_is_email setting is true
300
define('USERNAME_PURIFIER_MAIL', '/[^0-9A-Za-z_\.@]/');
301
define('USERNAME_PURIFIER_SHALLOW', '/\s/');
302
303
// This constant is a result of Windows OS detection, it has a boolean value:
304
// true whether the server runs on Windows OS, false otherwise.
305
define('IS_WINDOWS_OS', api_is_windows_os());
306
307
// Patterns for processing paths. Examples.
308
define('REPEATED_SLASHES_PURIFIER', '/\/{2,}/'); // $path = preg_replace(REPEATED_SLASHES_PURIFIER, '/', $path);
309
define('VALID_WEB_PATH', '/https?:\/\/[^\/]*(\/.*)?/i'); // $is_valid_path = preg_match(VALID_WEB_PATH, $path);
310
// $new_path = preg_replace(VALID_WEB_SERVER_BASE, $new_base, $path);
311
define('VALID_WEB_SERVER_BASE', '/https?:\/\/[^\/]*/i');
312
// Constants for api_get_path() and api_get_path_type(), etc. - registered path types.
313
// basic (leaf elements)
314
define('REL_CODE_PATH', 'REL_CODE_PATH');
315
define('REL_COURSE_PATH', 'REL_COURSE_PATH');
316
define('REL_HOME_PATH', 'REL_HOME_PATH');
317
318
// Constants for api_get_path() and api_get_path_type(), etc. - registered path types.
319
define('WEB_PATH', 'WEB_PATH');
320
define('SYS_PATH', 'SYS_PATH');
321
define('SYMFONY_SYS_PATH', 'SYMFONY_SYS_PATH');
322
323
define('REL_PATH', 'REL_PATH');
324
define('WEB_COURSE_PATH', 'WEB_COURSE_PATH');
325
define('WEB_CODE_PATH', 'WEB_CODE_PATH');
326
define('SYS_CODE_PATH', 'SYS_CODE_PATH');
327
define('SYS_LANG_PATH', 'SYS_LANG_PATH');
328
define('WEB_IMG_PATH', 'WEB_IMG_PATH');
329
define('WEB_CSS_PATH', 'WEB_CSS_PATH');
330
define('WEB_PUBLIC_PATH', 'WEB_PUBLIC_PATH');
331
define('SYS_CSS_PATH', 'SYS_CSS_PATH');
332
define('SYS_PLUGIN_PATH', 'SYS_PLUGIN_PATH');
333
define('WEB_PLUGIN_PATH', 'WEB_PLUGIN_PATH');
334
define('WEB_PLUGIN_ASSET_PATH', 'WEB_PLUGIN_ASSET_PATH');
335
define('SYS_ARCHIVE_PATH', 'SYS_ARCHIVE_PATH');
336
define('WEB_ARCHIVE_PATH', 'WEB_ARCHIVE_PATH');
337
define('LIBRARY_PATH', 'LIBRARY_PATH');
338
define('CONFIGURATION_PATH', 'CONFIGURATION_PATH');
339
define('WEB_LIBRARY_PATH', 'WEB_LIBRARY_PATH');
340
define('WEB_LIBRARY_JS_PATH', 'WEB_LIBRARY_JS_PATH');
341
define('WEB_AJAX_PATH', 'WEB_AJAX_PATH');
342
define('SYS_TEST_PATH', 'SYS_TEST_PATH');
343
define('SYS_TEMPLATE_PATH', 'SYS_TEMPLATE_PATH');
344
define('SYS_PUBLIC_PATH', 'SYS_PUBLIC_PATH');
345
define('SYS_FONTS_PATH', 'SYS_FONTS_PATH');
346
347
// Relations type with Course manager
348
define('COURSE_RELATION_TYPE_COURSE_MANAGER', 1);
349
define('SESSION_RELATION_TYPE_COURSE_MANAGER', 1);
350
351
// Relations type with Human resources manager
352
define('COURSE_RELATION_TYPE_RRHH', 1);
353
define('SESSION_RELATION_TYPE_RRHH', 1);
354
355
// User image sizes
356
define('USER_IMAGE_SIZE_ORIGINAL', 1);
357
define('USER_IMAGE_SIZE_BIG', 2);
358
define('USER_IMAGE_SIZE_MEDIUM', 3);
359
define('USER_IMAGE_SIZE_SMALL', 4);
360
361
// Gradebook link constants
362
// Please do not change existing values, they are used in the database !
363
define('GRADEBOOK_ITEM_LIMIT', 1000);
364
365
define('LINK_EXERCISE', 1);
366
define('LINK_DROPBOX', 2);
367
define('LINK_STUDENTPUBLICATION', 3);
368
define('LINK_LEARNPATH', 4);
369
define('LINK_FORUM_THREAD', 5);
370
//define('LINK_WORK',6);
371
define('LINK_ATTENDANCE', 7);
372
define('LINK_SURVEY', 8);
373
define('LINK_HOTPOTATOES', 9);
374
define('LINK_PORTFOLIO', 10);
375
376
// Score display types constants
377
define('SCORE_DIV', 1); // X / Y
378
define('SCORE_PERCENT', 2); // XX %
379
define('SCORE_DIV_PERCENT', 3); // X / Y (XX %)
380
define('SCORE_AVERAGE', 4); // XX %
381
define('SCORE_DECIMAL', 5); // 0.50  (X/Y)
382
define('SCORE_BAR', 6); // Uses the Display::bar_progress function
383
define('SCORE_SIMPLE', 7); // X
384
define('SCORE_IGNORE_SPLIT', 8); //  ??
385
define('SCORE_DIV_PERCENT_WITH_CUSTOM', 9); // X / Y (XX %) - Good!
386
define('SCORE_CUSTOM', 10); // Good!
387
define('SCORE_DIV_SIMPLE_WITH_CUSTOM', 11); // X - Good!
388
define('SCORE_DIV_SIMPLE_WITH_CUSTOM_LETTERS', 12); // X - Good!
389
define('SCORE_ONLY_SCORE', 13); // X - Good!
390
define('SCORE_NUMERIC', 14);
391
392
define('SCORE_BOTH', 1);
393
define('SCORE_ONLY_DEFAULT', 2);
394
define('SCORE_ONLY_CUSTOM', 3);
395
396
// From display.lib.php
397
398
define('MAX_LENGTH_BREADCRUMB', 100);
399
define('ICON_SIZE_ATOM', 8);
400
define('ICON_SIZE_TINY', 16);
401
define('ICON_SIZE_SMALL', 22);
402
define('ICON_SIZE_MEDIUM', 32);
403
define('ICON_SIZE_LARGE', 48);
404
define('ICON_SIZE_BIG', 64);
405
define('ICON_SIZE_HUGE', 128);
406
define('SHOW_TEXT_NEAR_ICONS', false);
407
408
// Session catalog
409
define('CATALOG_COURSES', 0);
410
define('CATALOG_SESSIONS', 1);
411
define('CATALOG_COURSES_SESSIONS', 2);
412
413
// Hook type events, pre-process and post-process.
414
// All means to be executed for both hook event types
415
define('HOOK_EVENT_TYPE_PRE', 0);
416
define('HOOK_EVENT_TYPE_POST', 1);
417
define('HOOK_EVENT_TYPE_ALL', 10);
418
419
// Group permissions
420
define('GROUP_PERMISSION_OPEN', '1');
421
define('GROUP_PERMISSION_CLOSED', '2');
422
423
// Group user permissions
424
define('GROUP_USER_PERMISSION_ADMIN', 1); // the admin of a group
425
define('GROUP_USER_PERMISSION_READER', 2); // a normal user
426
define('GROUP_USER_PERMISSION_PENDING_INVITATION', 3); // When an admin/moderator invites a user
427
define('GROUP_USER_PERMISSION_PENDING_INVITATION_SENT_BY_USER', 4); // an user joins a group
428
define('GROUP_USER_PERMISSION_MODERATOR', 5); // a moderator
429
define('GROUP_USER_PERMISSION_ANONYMOUS', 6); // an anonymous user
430
define('GROUP_USER_PERMISSION_HRM', 7); // a human resources manager
431
432
define('GROUP_IMAGE_SIZE_ORIGINAL', 1);
433
define('GROUP_IMAGE_SIZE_BIG', 2);
434
define('GROUP_IMAGE_SIZE_MEDIUM', 3);
435
define('GROUP_IMAGE_SIZE_SMALL', 4);
436
define('GROUP_TITLE_LENGTH', 50);
437
438
// Exercise
439
// @todo move into a class
440
define('ALL_ON_ONE_PAGE', 1);
441
define('ONE_PER_PAGE', 2);
442
443
define('EXERCISE_FEEDBACK_TYPE_END', 0); //Feedback 		 - show score and expected answers
444
define('EXERCISE_FEEDBACK_TYPE_DIRECT', 1); //DirectFeedback - Do not show score nor answers
445
define('EXERCISE_FEEDBACK_TYPE_EXAM', 2); // NoFeedback 	 - Show score only
446
define('EXERCISE_FEEDBACK_TYPE_POPUP', 3); // Popup BT#15827
447
448
define('RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS', 0); //show score and expected answers
449
define('RESULT_DISABLE_NO_SCORE_AND_EXPECTED_ANSWERS', 1); //Do not show score nor answers
450
define('RESULT_DISABLE_SHOW_SCORE_ONLY', 2); //Show score only
451
define('RESULT_DISABLE_SHOW_FINAL_SCORE_ONLY_WITH_CATEGORIES', 3); //Show final score only with categories
452
define('RESULT_DISABLE_SHOW_SCORE_ATTEMPT_SHOW_ANSWERS_LAST_ATTEMPT', 4);
453
define('RESULT_DISABLE_DONT_SHOW_SCORE_ONLY_IF_USER_FINISHES_ATTEMPTS_SHOW_ALWAYS_FEEDBACK', 5);
454
define('RESULT_DISABLE_RANKING', 6);
455
define('RESULT_DISABLE_SHOW_ONLY_IN_CORRECT_ANSWER', 7);
456
define('RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS_AND_RANKING', 8);
457
define('RESULT_DISABLE_RADAR', 9);
458
define('RESULT_DISABLE_SHOW_SCORE_ATTEMPT_SHOW_ANSWERS_LAST_ATTEMPT_NO_FEEDBACK', 10);
459
460
define('EXERCISE_MAX_NAME_SIZE', 80);
461
462
// Question types (edit next array as well when adding values)
463
// @todo move into a class
464
define('UNIQUE_ANSWER', 1);
465
define('MULTIPLE_ANSWER', 2);
466
define('FILL_IN_BLANKS', 3);
467
define('MATCHING', 4);
468
define('FREE_ANSWER', 5);
469
define('HOT_SPOT', 6);
470
define('HOT_SPOT_ORDER', 7);
471
define('HOT_SPOT_DELINEATION', 8);
472
define('MULTIPLE_ANSWER_COMBINATION', 9);
473
define('UNIQUE_ANSWER_NO_OPTION', 10);
474
define('MULTIPLE_ANSWER_TRUE_FALSE', 11);
475
define('MULTIPLE_ANSWER_COMBINATION_TRUE_FALSE', 12);
476
define('ORAL_EXPRESSION', 13);
477
define('GLOBAL_MULTIPLE_ANSWER', 14);
478
define('MEDIA_QUESTION', 15);
479
define('CALCULATED_ANSWER', 16);
480
define('UNIQUE_ANSWER_IMAGE', 17);
481
define('DRAGGABLE', 18);
482
define('MATCHING_DRAGGABLE', 19);
483
define('ANNOTATION', 20);
484
define('READING_COMPREHENSION', 21);
485
define('MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY', 22);
486
487
define('EXERCISE_CATEGORY_RANDOM_SHUFFLED', 1);
488
define('EXERCISE_CATEGORY_RANDOM_ORDERED', 2);
489
define('EXERCISE_CATEGORY_RANDOM_DISABLED', 0);
490
491
// Question selection type
492
define('EX_Q_SELECTION_ORDERED', 1);
493
define('EX_Q_SELECTION_RANDOM', 2);
494
define('EX_Q_SELECTION_CATEGORIES_ORDERED_QUESTIONS_ORDERED', 3);
495
define('EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_ORDERED', 4);
496
define('EX_Q_SELECTION_CATEGORIES_ORDERED_QUESTIONS_RANDOM', 5);
497
define('EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_RANDOM', 6);
498
define('EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_ORDERED_NO_GROUPED', 7);
499
define('EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_RANDOM_NO_GROUPED', 8);
500
define('EX_Q_SELECTION_CATEGORIES_ORDERED_BY_PARENT_QUESTIONS_ORDERED', 9);
501
define('EX_Q_SELECTION_CATEGORIES_ORDERED_BY_PARENT_QUESTIONS_RANDOM', 10);
502
503
// Used to save the skill_rel_item table
504
define('ITEM_TYPE_EXERCISE', 1);
505
define('ITEM_TYPE_HOTPOTATOES', 2);
506
define('ITEM_TYPE_LINK', 3);
507
define('ITEM_TYPE_LEARNPATH', 4);
508
define('ITEM_TYPE_GRADEBOOK', 5);
509
define('ITEM_TYPE_STUDENT_PUBLICATION', 6);
510
//define('ITEM_TYPE_FORUM', 7);
511
define('ITEM_TYPE_ATTENDANCE', 8);
512
define('ITEM_TYPE_SURVEY', 9);
513
define('ITEM_TYPE_FORUM_THREAD', 10);
514
define('ITEM_TYPE_PORTFOLIO', 11);
515
516
// Course description blocks.
517
define('ADD_BLOCK', 8);
518
519
// one big string with all question types, for the validator in pear/HTML/QuickForm/Rule/QuestionType
520
define(
521
    'QUESTION_TYPES',
522
    UNIQUE_ANSWER.':'.
523
    MULTIPLE_ANSWER.':'.
524
    FILL_IN_BLANKS.':'.
525
    MATCHING.':'.
526
    FREE_ANSWER.':'.
527
    HOT_SPOT.':'.
528
    HOT_SPOT_ORDER.':'.
529
    HOT_SPOT_DELINEATION.':'.
530
    MULTIPLE_ANSWER_COMBINATION.':'.
531
    UNIQUE_ANSWER_NO_OPTION.':'.
532
    MULTIPLE_ANSWER_TRUE_FALSE.':'.
533
    MULTIPLE_ANSWER_COMBINATION_TRUE_FALSE.':'.
534
    ORAL_EXPRESSION.':'.
535
    GLOBAL_MULTIPLE_ANSWER.':'.
536
    MEDIA_QUESTION.':'.
537
    CALCULATED_ANSWER.':'.
538
    UNIQUE_ANSWER_IMAGE.':'.
539
    DRAGGABLE.':'.
540
    MATCHING_DRAGGABLE.':'.
541
    MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY.':'.
542
    ANNOTATION
543
);
544
545
//Some alias used in the QTI exports
546
define('MCUA', 1);
547
define('TF', 1);
548
define('MCMA', 2);
549
define('FIB', 3);
550
551
// Message
552
define('MESSAGE_STATUS_INVITATION_PENDING', 5);
553
define('MESSAGE_STATUS_INVITATION_ACCEPTED', 6);
554
define('MESSAGE_STATUS_INVITATION_DENIED', 7);
555
define('MESSAGE_STATUS_WALL', 8);
556
557
define('MESSAGE_STATUS_WALL_DELETE', 9);
558
define('MESSAGE_STATUS_WALL_POST', 10);
559
560
define('MESSAGE_STATUS_FORUM', 12);
561
define('MESSAGE_STATUS_PROMOTED', 13);
562
563
// Images
564
define('IMAGE_WALL_SMALL_SIZE', 200);
565
define('IMAGE_WALL_MEDIUM_SIZE', 500);
566
define('IMAGE_WALL_BIG_SIZE', 2000);
567
define('IMAGE_WALL_SMALL', 'small');
568
define('IMAGE_WALL_MEDIUM', 'medium');
569
define('IMAGE_WALL_BIG', 'big');
570
571
// Social PLUGIN PLACES
572
define('SOCIAL_LEFT_PLUGIN', 1);
573
define('SOCIAL_CENTER_PLUGIN', 2);
574
define('SOCIAL_RIGHT_PLUGIN', 3);
575
define('CUT_GROUP_NAME', 50);
576
577
/**
578
 * FormValidator Filter.
579
 */
580
define('NO_HTML', 1);
581
define('STUDENT_HTML', 2);
582
define('TEACHER_HTML', 3);
583
define('STUDENT_HTML_FULLPAGE', 4);
584
define('TEACHER_HTML_FULLPAGE', 5);
585
586
// Timeline
587
define('TIMELINE_STATUS_ACTIVE', '1');
588
define('TIMELINE_STATUS_INACTIVE', '2');
589
590
// Event email template class
591
define('EVENT_EMAIL_TEMPLATE_ACTIVE', 1);
592
define('EVENT_EMAIL_TEMPLATE_INACTIVE', 0);
593
594
// Course home
595
define('SHORTCUTS_HORIZONTAL', 0);
596
define('SHORTCUTS_VERTICAL', 1);
597
598
// Course copy
599
define('FILE_SKIP', 1);
600
define('FILE_RENAME', 2);
601
define('FILE_OVERWRITE', 3);
602
define('UTF8_CONVERT', false); //false by default
603
604
define('DOCUMENT', 'file');
605
define('FOLDER', 'folder');
606
607
define('RESOURCE_ASSET', 'asset');
608
define('RESOURCE_DOCUMENT', 'document');
609
define('RESOURCE_GLOSSARY', 'glossary');
610
define('RESOURCE_EVENT', 'calendar_event');
611
define('RESOURCE_LINK', 'link');
612
define('RESOURCE_COURSEDESCRIPTION', 'course_description');
613
define('RESOURCE_LEARNPATH', 'learnpath');
614
define('RESOURCE_LEARNPATH_CATEGORY', 'learnpath_category');
615
define('RESOURCE_ANNOUNCEMENT', 'announcement');
616
define('RESOURCE_FORUM', 'forum');
617
define('RESOURCE_FORUMTOPIC', 'thread');
618
define('RESOURCE_FORUMPOST', 'post');
619
define('RESOURCE_QUIZ', 'quiz');
620
define('RESOURCE_TEST_CATEGORY', 'test_category');
621
define('RESOURCE_QUIZQUESTION', 'Exercise_Question');
622
define('RESOURCE_TOOL_INTRO', 'Tool introduction');
623
define('RESOURCE_LINKCATEGORY', 'Link_Category');
624
define('RESOURCE_FORUMCATEGORY', 'Forum_Category');
625
define('RESOURCE_SCORM', 'Scorm');
626
define('RESOURCE_SURVEY', 'survey');
627
define('RESOURCE_SURVEYQUESTION', 'survey_question');
628
define('RESOURCE_SURVEYINVITATION', 'survey_invitation');
629
//define('RESOURCE_WIKI', 'wiki');
630
define('RESOURCE_THEMATIC', 'thematic');
631
define('RESOURCE_ATTENDANCE', 'attendance');
632
define('RESOURCE_WORK', 'work');
633
define('RESOURCE_SESSION_COURSE', 'session_course');
634
define('RESOURCE_GRADEBOOK', 'gradebook');
635
define('ADD_THEMATIC_PLAN', 6);
636
637
// Max online users to show per page (whoisonline)
638
define('MAX_ONLINE_USERS', 12);
639
640
define('TOOL_AUTHORING', 'toolauthoring');
641
define('TOOL_INTERACTION', 'toolinteraction');
642
define('TOOL_COURSE_PLUGIN', 'toolcourseplugin'); //all plugins that can be enabled in courses
643
define('TOOL_ADMIN', 'tooladmin');
644
define('TOOL_ADMIN_PLATFORM', 'tooladminplatform');
645
define('TOOL_DRH', 'tool_drh');
646
define('TOOL_STUDENT_VIEW', 'toolstudentview');
647
define('TOOL_ADMIN_VISIBLE', 'tooladminvisible');
648
649
// Search settings (from main/inc/lib/search/IndexableChunk.class.php )
650
// some constants to avoid serialize string keys on serialized data array
651
define('SE_COURSE_ID', 0);
652
define('SE_TOOL_ID', 1);
653
define('SE_DATA', 2);
654
define('SE_USER', 3);
655
656
// in some cases we need top differenciate xapian documents of the same tool
657
define('SE_DOCTYPE_EXERCISE_EXERCISE', 0);
658
define('SE_DOCTYPE_EXERCISE_QUESTION', 1);
659
660
// xapian prefixes
661
define('XAPIAN_PREFIX_COURSEID', 'C');
662
define('XAPIAN_PREFIX_TOOLID', 'O');
663
664
/**
665
 * Returns a path to a certain resource within Chamilo.
666
 *
667
 * @param string $path A path which type is to be converted. Also, it may be a defined constant for a path.
668
 *
669
 * @return string the requested path or the converted path
670
 *
671
 * Notes about the current behaviour model:
672
 * 1. Windows back-slashes are converted to slashes in the result.
673
 * 2. A semi-absolute web-path is detected by its leading slash. On Linux systems, absolute system paths start with
674
 * a slash too, so an additional check about presence of leading system server base is implemented. For example, the function is
675
 * able to distinguish type difference between /var/www/chamilo/courses/ (SYS) and /chamilo/courses/ (REL).
676
 * 3. The function api_get_path() returns only these three types of paths, which in some sense are absolute. The function has
677
 * no a mechanism for processing relative web/system paths, such as: lesson01.html, ./lesson01.html, ../css/my_styles.css.
678
 * It has not been identified as needed yet.
679
 * 4. Also, resolving the meta-symbols "." and ".." within paths has not been implemented, it is to be identified as needed.
680
 *
681
 * Vchamilo changes : allow using an alternate configuration
682
 * to get vchamilo  instance paths
683
 */
684
function api_get_path($path = '', $configuration = [])
685
{
686
    global $paths;
687
688
    // get proper configuration data if exists
689
    global $_configuration;
690
691
    $emptyConfigurationParam = false;
692
    if (empty($configuration)) {
693
        $configuration = (array) $_configuration;
694
        $emptyConfigurationParam = true;
695
    }
696
697
    $root_sys = Container::getProjectDir();
698
    $root_web = '';
699
    if (isset(Container::$container)) {
700
        $root_web = Container::$container->get('router')->generate(
701
            'index',
702
            [],
703
            UrlGeneratorInterface::ABSOLUTE_URL
704
        );
705
    }
706
707
    if (isset($configuration['multiple_access_urls']) &&
708
        $configuration['multiple_access_urls']
709
    ) {
710
        // To avoid that the api_get_access_url() function fails since global.inc.php also calls the main_api.lib.php
711
        if (isset($configuration['access_url']) && !empty($configuration['access_url'])) {
712
            // We look into the DB the function api_get_access_url
713
            $urlInfo = api_get_access_url($configuration['access_url']);
714
            // Avoid default value
715
            $defaultValues = ['http://localhost/', 'https://localhost/'];
716
            if (!empty($urlInfo['url']) && !in_array($urlInfo['url'], $defaultValues)) {
717
                $root_web = 1 == $urlInfo['active'] ? $urlInfo['url'] : $configuration['root_web'];
718
            }
719
        }
720
    }
721
722
    $paths = [
723
        WEB_PATH => $root_web,
724
        SYMFONY_SYS_PATH => $root_sys,
725
        SYS_PATH => $root_sys.'public/',
726
        REL_PATH => '',
727
        CONFIGURATION_PATH => 'app/config/',
728
        LIBRARY_PATH => $root_sys.'public/main/inc/lib/',
729
730
        REL_COURSE_PATH => '',
731
        REL_CODE_PATH => '/main/',
732
733
        SYS_CODE_PATH => $root_sys.'public/main/',
734
        SYS_CSS_PATH => $root_sys.'public/build/css/',
735
        SYS_PLUGIN_PATH => $root_sys.'public/plugin/',
736
        SYS_ARCHIVE_PATH => $root_sys.'var/cache/',
737
        SYS_TEST_PATH => $root_sys.'tests/',
738
        SYS_TEMPLATE_PATH => $root_sys.'public/main/template/',
739
        SYS_PUBLIC_PATH => $root_sys.'public/',
740
        SYS_FONTS_PATH => $root_sys.'public/fonts/',
741
742
        WEB_CODE_PATH => $root_web.'main/',
743
        WEB_PLUGIN_ASSET_PATH => $root_web.'plugins/',
744
        WEB_COURSE_PATH => $root_web.'course/',
745
        WEB_IMG_PATH => $root_web.'img/',
746
        WEB_CSS_PATH => $root_web.'build/css/',
747
        WEB_AJAX_PATH => $root_web.'main/inc/ajax/',
748
        WEB_LIBRARY_PATH => $root_web.'main/inc/lib/',
749
        WEB_LIBRARY_JS_PATH => $root_web.'main/inc/lib/javascript/',
750
        WEB_PLUGIN_PATH => $root_web.'plugin/',
751
        WEB_PUBLIC_PATH => $root_web,
752
    ];
753
754
    $root_rel = '';
755
756
    global $virtualChamilo;
757
    if (!empty($virtualChamilo)) {
758
        $paths[SYS_ARCHIVE_PATH] = api_add_trailing_slash($virtualChamilo[SYS_ARCHIVE_PATH]);
759
        //$paths[SYS_UPLOAD_PATH] = api_add_trailing_slash($virtualChamilo[SYS_UPLOAD_PATH]);
760
        //$paths[$root_web][WEB_UPLOAD_PATH] = api_add_trailing_slash($virtualChamilo[WEB_UPLOAD_PATH]);
761
        $paths[WEB_ARCHIVE_PATH] = api_add_trailing_slash($virtualChamilo[WEB_ARCHIVE_PATH]);
762
        //$paths[$root_web][WEB_COURSE_PATH] = api_add_trailing_slash($virtualChamilo[WEB_COURSE_PATH]);
763
764
        // WEB_UPLOAD_PATH should be handle by apache htaccess in the vhost
765
766
        // RewriteEngine On
767
        // RewriteRule /app/upload/(.*)$ http://localhost/other/upload/my-chamilo111-net/$1 [QSA,L]
768
769
        //$paths[$root_web][WEB_UPLOAD_PATH] = api_add_trailing_slash($virtualChamilo[WEB_UPLOAD_PATH]);
770
        //$paths[$root_web][REL_PATH] = $virtualChamilo[REL_PATH];
771
        //$paths[$root_web][REL_COURSE_PATH] = $virtualChamilo[REL_COURSE_PATH];
772
    }
773
774
    $path = trim($path);
775
776
    // Retrieving a common-purpose path.
777
    if (isset($paths[$path])) {
778
        return $paths[$path];
779
    }
780
781
    return false;
782
}
783
784
/**
785
 * Adds to a given path a trailing slash if it is necessary (adds "/" character at the end of the string).
786
 *
787
 * @param string $path the input path
788
 *
789
 * @return string returns the modified path
790
 */
791
function api_add_trailing_slash($path)
792
{
793
    return '/' === substr($path, -1) ? $path : $path.'/';
794
}
795
796
/**
797
 * Removes from a given path the trailing slash if it is necessary (removes "/" character from the end of the string).
798
 *
799
 * @param string $path the input path
800
 *
801
 * @return string returns the modified path
802
 */
803
function api_remove_trailing_slash($path)
804
{
805
    return '/' === substr($path, -1) ? substr($path, 0, -1) : $path;
806
}
807
808
/**
809
 * Checks the RFC 3986 syntax of a given URL.
810
 *
811
 * @param string $url      the URL to be checked
812
 * @param bool   $absolute whether the URL is absolute (beginning with a scheme such as "http:")
813
 *
814
 * @return string|false Returns the URL if it is valid, FALSE otherwise.
815
 *                      This function is an adaptation from the function valid_url(), Drupal CMS.
816
 *
817
 * @see http://drupal.org
818
 * Note: The built-in function filter_var($urs, FILTER_VALIDATE_URL) has a bug for some versions of PHP.
819
 * @see http://bugs.php.net/51192
820
 */
821
function api_valid_url($url, $absolute = false)
822
{
823
    if ($absolute) {
824
        if (preg_match("
825
            /^                                                      # Start at the beginning of the text
826
            (?:ftp|https?|feed):\/\/                                # Look for ftp, http, https or feed schemes
827
            (?:                                                     # Userinfo (optional) which is typically
828
                (?:(?:[\w\.\-\+!$&'\(\)*\+,;=]|%[0-9a-f]{2})+:)*    # a username or a username and password
829
                (?:[\w\.\-\+%!$&'\(\)*\+,;=]|%[0-9a-f]{2})+@        # combination
830
            )?
831
            (?:
832
                (?:[a-z0-9\-\.]|%[0-9a-f]{2})+                      # A domain name or a IPv4 address
833
                |(?:\[(?:[0-9a-f]{0,4}:)*(?:[0-9a-f]{0,4})\])       # or a well formed IPv6 address
834
            )
835
            (?::[0-9]+)?                                            # Server port number (optional)
836
            (?:[\/|\?]
837
                (?:[\w#!:\.\?\+=&@$'~*,;\/\(\)\[\]\-]|%[0-9a-f]{2}) # The path and query (optional)
838
            *)?
839
            $/xi", $url)) {
840
            return $url;
841
        }
842
843
        return false;
844
    } else {
845
        return preg_match("/^(?:[\w#!:\.\?\+=&@$'~*,;\/\(\)\[\]\-]|%[0-9a-f]{2})+$/i", $url) ? $url : false;
846
    }
847
}
848
849
/**
850
 * Checks whether a given string looks roughly like an email address.
851
 *
852
 * @param string $address the e-mail address to be checked
853
 *
854
 * @return mixed returns the e-mail if it is valid, FALSE otherwise
855
 */
856
function api_valid_email($address)
857
{
858
    return filter_var($address, FILTER_VALIDATE_EMAIL);
859
}
860
861
/**
862
 * Function used to protect a course script.
863
 * The function blocks access when
864
 * - there is no $_SESSION["_course"] defined; or
865
 * - $is_allowed_in_course is set to false (this depends on the course
866
 * visibility and user status).
867
 *
868
 * This is only the first proposal, test and improve!
869
 *
870
 * @param bool Option to print headers when displaying error message. Default: false
871
 * @param bool whether session admins should be allowed or not
872
 * @param string $checkTool check if tool is available for users (user, group)
873
 *
874
 * @return bool True if the user has access to the current course or is out of a course context, false otherwise
875
 *
876
 * @todo replace global variable
877
 *
878
 * @author Roan Embrechts
879
 */
880
function api_protect_course_script($print_headers = false, $allow_session_admins = false, $checkTool = '')
881
{
882
    $course_info = api_get_course_info();
883
    if (empty($course_info)) {
884
        api_not_allowed($print_headers);
885
886
        return false;
887
    }
888
889
    if (api_is_drh()) {
890
        return true;
891
    }
892
893
    // Session admin has access to course
894
    $sessionAccess = api_get_configuration_value('session_admins_access_all_content');
895
    if ($sessionAccess) {
896
        $allow_session_admins = true;
897
    }
898
899
    if (api_is_platform_admin($allow_session_admins)) {
900
        return true;
901
    }
902
903
    $isAllowedInCourse = api_is_allowed_in_course();
904
    $is_visible = false;
905
    if (isset($course_info) && isset($course_info['visibility'])) {
906
        switch ($course_info['visibility']) {
907
            default:
908
            case Course::CLOSED:
909
                // Completely closed: the course is only accessible to the teachers. - 0
910
                if ($isAllowedInCourse && api_get_user_id() && !api_is_anonymous()) {
911
                    $is_visible = true;
912
                }
913
                break;
914
            case Course::REGISTERED:
915
                // Private - access authorized to course members only - 1
916
                if ($isAllowedInCourse && api_get_user_id() && !api_is_anonymous()) {
917
                    $is_visible = true;
918
                }
919
                break;
920
            case Course::OPEN_PLATFORM:
921
                // Open - access allowed for users registered on the platform - 2
922
                if ($isAllowedInCourse && api_get_user_id() && !api_is_anonymous()) {
923
                    $is_visible = true;
924
                }
925
                break;
926
            case Course::OPEN_WORLD:
927
                //Open - access allowed for the whole world - 3
928
                $is_visible = true;
929
                break;
930
            case Course::HIDDEN:
931
                //Completely closed: the course is only accessible to the teachers. - 0
932
                if (api_is_platform_admin()) {
933
                    $is_visible = true;
934
                }
935
                break;
936
        }
937
938
        //If password is set and user is not registered to the course then the course is not visible
939
        if (false === $isAllowedInCourse &&
940
            isset($course_info['registration_code']) &&
941
            !empty($course_info['registration_code'])
942
        ) {
943
            $is_visible = false;
944
        }
945
    }
946
947
    if (!empty($checkTool)) {
948
        if (!api_is_allowed_to_edit(true, true, true)) {
949
            $toolInfo = api_get_tool_information_by_name($checkTool);
950
            if (!empty($toolInfo) && isset($toolInfo['visibility']) && 0 == $toolInfo['visibility']) {
951
                api_not_allowed(true);
952
953
                return false;
954
            }
955
        }
956
    }
957
958
    // Check session visibility
959
    $session_id = api_get_session_id();
960
961
    if (!empty($session_id)) {
962
        // $isAllowedInCourse was set in local.inc.php
963
        if (!$isAllowedInCourse) {
964
            $is_visible = false;
965
        }
966
        // Check if course is inside session.
967
        if (!SessionManager::relation_session_course_exist($session_id, $course_info['real_id'])) {
968
            $is_visible = false;
969
        }
970
    }
971
972
    error_log((string )$is_visible);
973
974
    if (!$is_visible) {
975
        api_not_allowed($print_headers);
976
977
        return false;
978
    }
979
980
    if ($is_visible && 'true' === api_get_plugin_setting('positioning', 'tool_enable')) {
981
        $plugin = Positioning::create();
982
        $block = $plugin->get('block_course_if_initial_exercise_not_attempted');
983
        if ('true' === $block) {
984
            $currentPath = $_SERVER['PHP_SELF'];
985
            // Allowed only this course paths.
986
            $paths = [
987
                '/plugin/positioning/start.php',
988
                '/plugin/positioning/start_student.php',
989
                '/main/course_home/course_home.php',
990
                '/main/exercise/overview.php',
991
            ];
992
993
            if (!in_array($currentPath, $paths, true)) {
994
                // Check if entering an exercise.
995
                // @todo remove global $current_course_tool
996
                /*global $current_course_tool;
997
                if ('quiz' !== $current_course_tool) {
998
                    $initialData = $plugin->getInitialExercise($course_info['real_id'], $session_id);
999
                    if ($initialData && isset($initialData['exercise_id'])) {
1000
                        $results = Event::getExerciseResultsByUser(
1001
                            api_get_user_id(),
1002
                            $initialData['exercise_id'],
1003
                            $course_info['real_id'],
1004
                            $session_id
1005
                        );
1006
                        if (empty($results)) {
1007
                            api_not_allowed($print_headers);
1008
1009
                            return false;
1010
                        }
1011
                    }
1012
                }*/
1013
            }
1014
        }
1015
    }
1016
1017
    api_block_inactive_user();
1018
1019
    return true;
1020
}
1021
1022
/**
1023
 * Function used to protect an admin script.
1024
 *
1025
 * The function blocks access when the user has no platform admin rights
1026
 * with an error message printed on default output
1027
 *
1028
 * @param bool Whether to allow session admins as well
1029
 * @param bool Whether to allow HR directors as well
1030
 * @param string An optional message (already passed through get_lang)
1031
 *
1032
 * @return bool True if user is allowed, false otherwise.
1033
 *              The function also outputs an error message in case not allowed
1034
 *
1035
 * @author Roan Embrechts (original author)
1036
 */
1037
function api_protect_admin_script($allow_sessions_admins = false, $allow_drh = false, $message = null)
1038
{
1039
    if (!api_is_platform_admin($allow_sessions_admins, $allow_drh)) {
1040
        api_not_allowed(true, $message);
1041
1042
        return false;
1043
    }
1044
    api_block_inactive_user();
1045
1046
    return true;
1047
}
1048
1049
/**
1050
 * Blocks inactive users with a currently active session from accessing more pages "live".
1051
 *
1052
 * @return bool Returns true if the feature is disabled or the user account is still enabled.
1053
 *              Returns false (and shows a message) if the feature is enabled *and* the user is disabled.
1054
 */
1055
function api_block_inactive_user()
1056
{
1057
    $data = true;
1058
    if (1 != api_get_configuration_value('security_block_inactive_users_immediately')) {
1059
        return $data;
1060
    }
1061
1062
    $userId = api_get_user_id();
1063
    $homeUrl = api_get_path(WEB_PATH);
1064
    if (0 == $userId) {
1065
        return $data;
1066
    }
1067
1068
    $sql = "SELECT active FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1069
            WHERE id = $userId";
1070
1071
    $result = Database::query($sql);
1072
    if (Database::num_rows($result) > 0) {
1073
        $result_array = Database::fetch_array($result);
1074
        $data = (bool) $result_array['active'];
1075
    }
1076
    if (false == $data) {
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...
1077
        $tpl = new Template(null, true, true, false, true, false, true, 0);
1078
        $tpl->assign('hide_login_link', 1);
1079
1080
        //api_not_allowed(true, get_lang('AccountInactive'));
1081
        // we were not in a course, return to home page
1082
        $msg = Display::return_message(
1083
            get_lang('AccountInactive'),
1084
            'error',
1085
            false
1086
        );
1087
1088
        $msg .= '<p class="text-center">
1089
                 <a class="btn btn-default" href="'.$homeUrl.'">'.get_lang('BackHome').'</a></p>';
1090
1091
        $tpl->assign('content', $msg);
1092
        $tpl->display_one_col_template();
1093
        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...
1094
    }
1095
1096
    return $data;
1097
}
1098
1099
/**
1100
 * Function used to protect a teacher script.
1101
 * The function blocks access when the user has no teacher rights.
1102
 *
1103
 * @return bool True if the current user can access the script, false otherwise
1104
 *
1105
 * @author Yoselyn Castillo
1106
 */
1107
function api_protect_teacher_script()
1108
{
1109
    if (!api_is_allowed_to_edit()) {
1110
        api_not_allowed(true);
1111
1112
        return false;
1113
    }
1114
1115
    return true;
1116
}
1117
1118
/**
1119
 * Function used to prevent anonymous users from accessing a script.
1120
 *
1121
 * @param bool $printHeaders
1122
 *
1123
 * @return bool
1124
 */
1125
function api_block_anonymous_users($printHeaders = true)
1126
{
1127
    $isAuth = Container::getAuthorizationChecker()->isGranted('IS_AUTHENTICATED_FULLY');
1128
1129
    if (false === $isAuth) {
1130
        api_not_allowed($printHeaders);
1131
1132
        return false;
1133
    }
1134
1135
    api_block_inactive_user();
1136
1137
    return true;
1138
}
1139
1140
/**
1141
 * Returns a rough evaluation of the browser's name and version based on very
1142
 * simple regexp.
1143
 *
1144
 * @return array with the navigator name and version ['name' => '...', 'version' => '...']
1145
 */
1146
function api_get_navigator()
1147
{
1148
    $navigator = 'Unknown';
1149
    $version = 0;
1150
1151
    if (!isset($_SERVER['HTTP_USER_AGENT'])) {
1152
        return ['name' => 'Unknown', 'version' => '0.0.0'];
1153
    }
1154
1155
    if (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Opera')) {
1156
        $navigator = 'Opera';
1157
        [, $version] = explode('Opera', $_SERVER['HTTP_USER_AGENT']);
1158
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Edge')) {
1159
        $navigator = 'Edge';
1160
        [, $version] = explode('Edge', $_SERVER['HTTP_USER_AGENT']);
1161
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE')) {
1162
        $navigator = 'Internet Explorer';
1163
        [, $version] = explode('MSIE ', $_SERVER['HTTP_USER_AGENT']);
1164
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Chrome')) {
1165
        $navigator = 'Chrome';
1166
        [, $version] = explode('Chrome', $_SERVER['HTTP_USER_AGENT']);
1167
    } elseif (false !== stripos($_SERVER['HTTP_USER_AGENT'], 'Safari')) {
1168
        $navigator = 'Safari';
1169
        if (false !== stripos($_SERVER['HTTP_USER_AGENT'], 'Version/')) {
1170
            // If this Safari does have the "Version/" string in its user agent
1171
            // then use that as a version indicator rather than what's after
1172
            // "Safari/" which is rather a "build number" or something
1173
            [, $version] = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1174
        } else {
1175
            [, $version] = explode('Safari/', $_SERVER['HTTP_USER_AGENT']);
1176
        }
1177
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Firefox')) {
1178
        $navigator = 'Firefox';
1179
        [, $version] = explode('Firefox', $_SERVER['HTTP_USER_AGENT']);
1180
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Netscape')) {
1181
        $navigator = 'Netscape';
1182
        if (false !== stripos($_SERVER['HTTP_USER_AGENT'], 'Netscape/')) {
1183
            [, $version] = explode('Netscape', $_SERVER['HTTP_USER_AGENT']);
1184
        } else {
1185
            [, $version] = explode('Navigator', $_SERVER['HTTP_USER_AGENT']);
1186
        }
1187
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Konqueror')) {
1188
        $navigator = 'Konqueror';
1189
        [, $version] = explode('Konqueror', $_SERVER['HTTP_USER_AGENT']);
1190
    } elseif (false !== stripos($_SERVER['HTTP_USER_AGENT'], 'applewebkit')) {
1191
        $navigator = 'AppleWebKit';
1192
        [, $version] = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1193
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Gecko')) {
1194
        $navigator = 'Mozilla';
1195
        [, $version] = explode('; rv:', $_SERVER['HTTP_USER_AGENT']);
1196
    }
1197
1198
    // Now cut extra stuff around (mostly *after*) the version number
1199
    $version = preg_replace('/^([\/\s])?([\d\.]+)?.*/', '\2', $version);
1200
1201
    if (false === strpos($version, '.')) {
1202
        $version = number_format(doubleval($version), 1);
1203
    }
1204
1205
    return ['name' => $navigator, 'version' => $version];
1206
}
1207
1208
/**
1209
 * This function returns the id of the user which is stored in the $_user array.
1210
 *
1211
 * example: The function can be used to check if a user is logged in
1212
 *          if (api_get_user_id())
1213
 *
1214
 * @return int the id of the current user, 0 if is empty
1215
 */
1216
function api_get_user_id()
1217
{
1218
    $userInfo = Session::read('_user');
1219
    if ($userInfo && isset($userInfo['user_id'])) {
1220
        return (int) $userInfo['user_id'];
1221
    }
1222
1223
    return 0;
1224
}
1225
1226
/**
1227
 * Formats user information into a standard array
1228
 * This function should be only used inside api_get_user_info().
1229
 *
1230
 * @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...
1231
 * @param bool $add_password
1232
 * @param bool $loadAvatars  turn off to improve performance
1233
 *
1234
 * @return array Standard user array
1235
 */
1236
function _api_format_user($user, $add_password = false, $loadAvatars = true)
1237
{
1238
    $result = [];
1239
1240
    if (!isset($user['id'])) {
1241
        return [];
1242
    }
1243
1244
    $result['firstname'] = null;
1245
    $result['lastname'] = null;
1246
1247
    if (isset($user['firstname']) && isset($user['lastname'])) {
1248
        // with only lowercase
1249
        $result['firstname'] = $user['firstname'];
1250
        $result['lastname'] = $user['lastname'];
1251
    } elseif (isset($user['firstName']) && isset($user['lastName'])) {
1252
        // with uppercase letters
1253
        $result['firstname'] = isset($user['firstName']) ? $user['firstName'] : null;
1254
        $result['lastname'] = isset($user['lastName']) ? $user['lastName'] : null;
1255
    }
1256
1257
    if (isset($user['email'])) {
1258
        $result['mail'] = isset($user['email']) ? $user['email'] : null;
1259
        $result['email'] = isset($user['email']) ? $user['email'] : null;
1260
    } else {
1261
        $result['mail'] = isset($user['mail']) ? $user['mail'] : null;
1262
        $result['email'] = isset($user['mail']) ? $user['mail'] : null;
1263
    }
1264
1265
    $result['complete_name'] = api_get_person_name($result['firstname'], $result['lastname']);
1266
    $result['complete_name_with_username'] = $result['complete_name'];
1267
1268
    if (!empty($user['username']) && 'false' === api_get_setting('profile.hide_username_with_complete_name')) {
1269
        $result['complete_name_with_username'] = $result['complete_name'].' ('.$user['username'].')';
1270
    }
1271
1272
    $showEmail = 'true' === api_get_setting('show_email_addresses');
1273
    if (!empty($user['email'])) {
1274
        $result['complete_name_with_email_forced'] = $result['complete_name'].' ('.$user['email'].')';
1275
        if ($showEmail) {
1276
            $result['complete_name_with_email'] = $result['complete_name'].' ('.$user['email'].')';
1277
        }
1278
    } else {
1279
        $result['complete_name_with_email'] = $result['complete_name'];
1280
        $result['complete_name_with_email_forced'] = $result['complete_name'];
1281
    }
1282
1283
    // Kept for historical reasons
1284
    $result['firstName'] = $result['firstname'];
1285
    $result['lastName'] = $result['lastname'];
1286
1287
    $attributes = [
1288
        'phone',
1289
        'address',
1290
        'picture_uri',
1291
        'official_code',
1292
        'status',
1293
        'active',
1294
        'auth_source',
1295
        'username',
1296
        'theme',
1297
        'language',
1298
        'locale',
1299
        'creator_id',
1300
        'registration_date',
1301
        'hr_dept_id',
1302
        'expiration_date',
1303
        'last_login',
1304
        'user_is_online',
1305
    ];
1306
1307
    if ('true' === api_get_setting('extended_profile')) {
1308
        $attributes[] = 'competences';
1309
        $attributes[] = 'diplomas';
1310
        $attributes[] = 'teach';
1311
        $attributes[] = 'openarea';
1312
    }
1313
1314
    foreach ($attributes as $attribute) {
1315
        $result[$attribute] = $user[$attribute] ?? null;
1316
    }
1317
1318
    $user_id = (int) $user['id'];
1319
    // Maintain the user_id index for backwards compatibility
1320
    $result['user_id'] = $result['id'] = $user_id;
1321
1322
    $hasCertificates = Certificate::getCertificateByUser($user_id);
1323
    $result['has_certificates'] = 0;
1324
    if (!empty($hasCertificates)) {
1325
        $result['has_certificates'] = 1;
1326
    }
1327
1328
    $result['icon_status'] = '';
1329
    $result['icon_status_medium'] = '';
1330
    $result['is_admin'] = UserManager::is_admin($user_id);
1331
1332
    // Getting user avatar.
1333
    if ($loadAvatars) {
1334
        $result['avatar'] = '';
1335
        $result['avatar_no_query'] = '';
1336
        $result['avatar_small'] = '';
1337
        $result['avatar_medium'] = '';
1338
        $urlImg = api_get_path(WEB_IMG_PATH);
1339
        $iconStatus = '';
1340
        $iconStatusMedium = '';
1341
        $label = '';
1342
1343
        switch ($result['status']) {
1344
            case STUDENT:
1345
                if ($result['has_certificates']) {
1346
                    $iconStatus = $urlImg.'icons/svg/identifier_graduated.svg';
1347
                    $label = get_lang('Graduated');
1348
                } else {
1349
                    $iconStatus = $urlImg.'icons/svg/identifier_student.svg';
1350
                    $label = get_lang('Student');
1351
                }
1352
                break;
1353
            case COURSEMANAGER:
1354
                if ($result['is_admin']) {
1355
                    $iconStatus = $urlImg.'icons/svg/identifier_admin.svg';
1356
                    $label = get_lang('Admin');
1357
                } else {
1358
                    $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1359
                    $label = get_lang('Teacher');
1360
                }
1361
                break;
1362
            case STUDENT_BOSS:
1363
                $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1364
                $label = get_lang('StudentBoss');
1365
                break;
1366
        }
1367
1368
        if (!empty($iconStatus)) {
1369
            $iconStatusMedium = '<img src="'.$iconStatus.'" width="32px" height="32px">';
1370
            $iconStatus = '<img src="'.$iconStatus.'" width="22px" height="22px">';
1371
        }
1372
1373
        $result['icon_status'] = $iconStatus;
1374
        $result['icon_status_label'] = $label;
1375
        $result['icon_status_medium'] = $iconStatusMedium;
1376
    }
1377
1378
    if (isset($user['user_is_online'])) {
1379
        $result['user_is_online'] = true == $user['user_is_online'] ? 1 : 0;
1380
    }
1381
    if (isset($user['user_is_online_in_chat'])) {
1382
        $result['user_is_online_in_chat'] = (int) $user['user_is_online_in_chat'];
1383
    }
1384
1385
    if ($add_password) {
1386
        $result['password'] = $user['password'];
1387
    }
1388
1389
    if (isset($result['profile_completed'])) {
1390
        $result['profile_completed'] = $user['profile_completed'];
1391
    }
1392
1393
    $result['profile_url'] = api_get_path(WEB_CODE_PATH).'social/profile.php?u='.$user_id;
1394
1395
    // Send message link
1396
    $sendMessage = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&user_id='.$user_id;
1397
    $result['complete_name_with_message_link'] = Display::url(
1398
        $result['complete_name_with_username'],
1399
        $sendMessage,
1400
        ['class' => 'ajax']
1401
    );
1402
1403
    if (isset($user['extra'])) {
1404
        $result['extra'] = $user['extra'];
1405
    }
1406
1407
    return $result;
1408
}
1409
1410
/**
1411
 * Finds all the information about a user.
1412
 * If no parameter is passed you find all the information about the current user.
1413
 *
1414
 * @param int  $user_id
1415
 * @param bool $checkIfUserOnline
1416
 * @param bool $showPassword
1417
 * @param bool $loadExtraData
1418
 * @param bool $loadOnlyVisibleExtraData Get the user extra fields that are visible
1419
 * @param bool $loadAvatars              turn off to improve performance and if avatars are not needed
1420
 * @param bool $updateCache              update apc cache if exists
1421
 *
1422
 * @return mixed $user_info user_id, lastname, firstname, username, email, etc or false on error
1423
 *
1424
 * @author Patrick Cool <[email protected]>
1425
 * @author Julio Montoya
1426
 *
1427
 * @version 21 September 2004
1428
 */
1429
function api_get_user_info(
1430
    $user_id = 0,
1431
    $checkIfUserOnline = false,
1432
    $showPassword = false,
1433
    $loadExtraData = false,
1434
    $loadOnlyVisibleExtraData = false,
1435
    $loadAvatars = true,
1436
    $updateCache = false
1437
) {
1438
    // Make sure user_id is safe
1439
    $user_id = (int) $user_id;
1440
    $user = false;
1441
    if (empty($user_id)) {
1442
        $userFromSession = Session::read('_user');
1443
        if (isset($userFromSession) && !empty($userFromSession)) {
1444
            return $userFromSession;
1445
            /*
1446
            return _api_format_user(
1447
                $userFromSession,
1448
                $showPassword,
1449
                $loadAvatars
1450
            );*/
1451
        }
1452
1453
        return false;
1454
    }
1455
1456
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1457
            WHERE id = $user_id";
1458
    $result = Database::query($sql);
1459
    if (Database::num_rows($result) > 0) {
1460
        $result_array = Database::fetch_array($result);
1461
        $result_array['user_is_online_in_chat'] = 0;
1462
        if ($checkIfUserOnline) {
1463
            $use_status_in_platform = user_is_online($user_id);
1464
            $result_array['user_is_online'] = $use_status_in_platform;
1465
            $user_online_in_chat = 0;
1466
            if ($use_status_in_platform) {
1467
                $user_status = UserManager::get_extra_user_data_by_field(
1468
                    $user_id,
1469
                    'user_chat_status',
1470
                    false,
1471
                    true
1472
                );
1473
                if (1 == (int) $user_status['user_chat_status']) {
1474
                    $user_online_in_chat = 1;
1475
                }
1476
            }
1477
            $result_array['user_is_online_in_chat'] = $user_online_in_chat;
1478
        }
1479
1480
        if ($loadExtraData) {
1481
            $fieldValue = new ExtraFieldValue('user');
1482
            $result_array['extra'] = $fieldValue->getAllValuesForAnItem(
1483
                $user_id,
1484
                $loadOnlyVisibleExtraData
1485
            );
1486
        }
1487
        $user = _api_format_user($result_array, $showPassword, $loadAvatars);
1488
    }
1489
1490
    return $user;
1491
}
1492
1493
function api_get_user_info_from_entity(
1494
    User $user,
1495
    $checkIfUserOnline = false,
1496
    $showPassword = false,
1497
    $loadExtraData = false,
1498
    $loadOnlyVisibleExtraData = false,
1499
    $loadAvatars = true,
1500
    $loadCertificate = false
1501
) {
1502
    if (!$user instanceof UserInterface) {
1503
        return false;
1504
    }
1505
1506
    // Make sure user_id is safe
1507
    $user_id = (int) $user->getId();
1508
1509
    if (empty($user_id)) {
1510
        $userFromSession = Session::read('_user');
1511
1512
        if (isset($userFromSession) && !empty($userFromSession)) {
1513
            return $userFromSession;
1514
        }
1515
1516
        return false;
1517
    }
1518
1519
    $result = [];
1520
    $result['user_is_online_in_chat'] = 0;
1521
    if ($checkIfUserOnline) {
1522
        $use_status_in_platform = user_is_online($user_id);
1523
        $result['user_is_online'] = $use_status_in_platform;
1524
        $user_online_in_chat = 0;
1525
        if ($use_status_in_platform) {
1526
            $user_status = UserManager::get_extra_user_data_by_field(
1527
                $user_id,
1528
                'user_chat_status',
1529
                false,
1530
                true
1531
            );
1532
            if (1 == (int) $user_status['user_chat_status']) {
1533
                $user_online_in_chat = 1;
1534
            }
1535
        }
1536
        $result['user_is_online_in_chat'] = $user_online_in_chat;
1537
    }
1538
1539
    if ($loadExtraData) {
1540
        $fieldValue = new ExtraFieldValue('user');
1541
        $result['extra'] = $fieldValue->getAllValuesForAnItem(
1542
            $user_id,
1543
            $loadOnlyVisibleExtraData
1544
        );
1545
    }
1546
1547
    $result['username'] = $user->getUsername();
1548
    $result['status'] = $user->getStatus();
1549
    $result['firstname'] = $user->getFirstname();
1550
    $result['lastname'] = $user->getLastname();
1551
    $result['email'] = $result['mail'] = $user->getEmail();
1552
    $result['complete_name'] = api_get_person_name($result['firstname'], $result['lastname']);
1553
    $result['complete_name_with_username'] = $result['complete_name'];
1554
1555
    if (!empty($result['username']) && 'false' === api_get_setting('profile.hide_username_with_complete_name')) {
1556
        $result['complete_name_with_username'] = $result['complete_name'].' ('.$result['username'].')';
1557
    }
1558
1559
    $showEmail = 'true' === api_get_setting('show_email_addresses');
1560
    if (!empty($result['email'])) {
1561
        $result['complete_name_with_email_forced'] = $result['complete_name'].' ('.$result['email'].')';
1562
        if ($showEmail) {
1563
            $result['complete_name_with_email'] = $result['complete_name'].' ('.$result['email'].')';
1564
        }
1565
    } else {
1566
        $result['complete_name_with_email'] = $result['complete_name'];
1567
        $result['complete_name_with_email_forced'] = $result['complete_name'];
1568
    }
1569
1570
    // Kept for historical reasons
1571
    $result['firstName'] = $result['firstname'];
1572
    $result['lastName'] = $result['lastname'];
1573
1574
    $attributes = [
1575
        'picture_uri',
1576
        'last_login',
1577
        'user_is_online',
1578
    ];
1579
1580
    $result['phone'] = $user->getPhone();
1581
    $result['address'] = $user->getAddress();
1582
    $result['official_code'] = $user->getOfficialCode();
1583
    $result['active'] = $user->getActive();
1584
    $result['auth_source'] = $user->getAuthSource();
1585
    $result['language'] = $user->getLocale();
1586
    $result['creator_id'] = $user->getCreatorId();
1587
    $result['registration_date'] = $user->getRegistrationDate()->format('Y-m-d H:i:s');
1588
    $result['hr_dept_id'] = $user->getHrDeptId();
1589
    $result['expiration_date'] = '';
1590
    if ($user->getExpirationDate()) {
1591
        $result['expiration_date'] = $user->getExpirationDate()->format('Y-m-d H:i:s');
1592
    }
1593
1594
    $result['last_login'] = null;
1595
    if ($user->getLastLogin()) {
1596
        $result['last_login'] = $user->getLastLogin()->format('Y-m-d H:i:s');
1597
    }
1598
1599
    $result['competences'] = $user->getCompetences();
1600
    $result['diplomas'] = $user->getDiplomas();
1601
    $result['teach'] = $user->getTeach();
1602
    $result['openarea'] = $user->getOpenarea();
1603
    $user_id = (int) $user->getId();
1604
1605
    // Maintain the user_id index for backwards compatibility
1606
    $result['user_id'] = $result['id'] = $user_id;
1607
1608
    if ($loadCertificate) {
1609
        $hasCertificates = Certificate::getCertificateByUser($user_id);
1610
        $result['has_certificates'] = 0;
1611
        if (!empty($hasCertificates)) {
1612
            $result['has_certificates'] = 1;
1613
        }
1614
    }
1615
1616
    $result['icon_status'] = '';
1617
    $result['icon_status_medium'] = '';
1618
    $result['is_admin'] = UserManager::is_admin($user_id);
1619
1620
    // Getting user avatar.
1621
    if ($loadAvatars) {
1622
        $result['avatar'] = '';
1623
        $result['avatar_no_query'] = '';
1624
        $result['avatar_small'] = '';
1625
        $result['avatar_medium'] = '';
1626
        $urlImg = '/';
1627
        $iconStatus = '';
1628
        $iconStatusMedium = '';
1629
1630
        switch ($user->getStatus()) {
1631
            case STUDENT:
1632
                if (isset($result['has_certificates']) && $result['has_certificates']) {
1633
                    $iconStatus = $urlImg.'icons/svg/identifier_graduated.svg';
1634
                } else {
1635
                    $iconStatus = $urlImg.'icons/svg/identifier_student.svg';
1636
                }
1637
                break;
1638
            case COURSEMANAGER:
1639
                if ($result['is_admin']) {
1640
                    $iconStatus = $urlImg.'icons/svg/identifier_admin.svg';
1641
                } else {
1642
                    $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1643
                }
1644
                break;
1645
            case STUDENT_BOSS:
1646
                $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1647
                break;
1648
        }
1649
1650
        if (!empty($iconStatus)) {
1651
            $iconStatusMedium = '<img src="'.$iconStatus.'" width="32px" height="32px">';
1652
            $iconStatus = '<img src="'.$iconStatus.'" width="22px" height="22px">';
1653
        }
1654
1655
        $result['icon_status'] = $iconStatus;
1656
        $result['icon_status_medium'] = $iconStatusMedium;
1657
    }
1658
1659
    if (isset($result['user_is_online'])) {
1660
        $result['user_is_online'] = true == $result['user_is_online'] ? 1 : 0;
1661
    }
1662
    if (isset($result['user_is_online_in_chat'])) {
1663
        $result['user_is_online_in_chat'] = $result['user_is_online_in_chat'];
1664
    }
1665
1666
    $result['password'] = '';
1667
    if ($showPassword) {
1668
        $result['password'] = $user->getPassword();
1669
    }
1670
1671
    if (isset($result['profile_completed'])) {
1672
        $result['profile_completed'] = $result['profile_completed'];
1673
    }
1674
1675
    $result['profile_url'] = api_get_path(WEB_CODE_PATH).'social/profile.php?u='.$user_id;
1676
1677
    // Send message link
1678
    $sendMessage = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&user_id='.$user_id;
1679
    $result['complete_name_with_message_link'] = Display::url(
1680
        $result['complete_name_with_username'],
1681
        $sendMessage,
1682
        ['class' => 'ajax']
1683
    );
1684
1685
    if (isset($result['extra'])) {
1686
        $result['extra'] = $result['extra'];
1687
    }
1688
1689
    return $result;
1690
}
1691
1692
function api_get_lp_entity(int $id): ?CLp
1693
{
1694
    return Database::getManager()->getRepository(CLp::class)->find($id);
1695
}
1696
1697
function api_get_user_entity(int $userId = 0): ?User
1698
{
1699
    $userId = $userId ?: api_get_user_id();
1700
    $repo = Container::getUserRepository();
1701
1702
    return $repo->find($userId);
1703
}
1704
1705
function api_get_current_user(): ?User
1706
{
1707
    $isLoggedIn = Container::getAuthorizationChecker()->isGranted('IS_AUTHENTICATED_REMEMBERED');
1708
    if (false === $isLoggedIn) {
1709
        return null;
1710
    }
1711
1712
    $token = Container::getTokenStorage()->getToken();
1713
1714
    if (null !== $token) {
1715
        return $token->getUser();
1716
    }
1717
1718
    return null;
1719
}
1720
1721
/**
1722
 * Finds all the information about a user from username instead of user id.
1723
 *
1724
 * @param string $username
1725
 *
1726
 * @return mixed $user_info array user_id, lastname, firstname, username, email or false on error
1727
 *
1728
 * @author Yannick Warnier <[email protected]>
1729
 */
1730
function api_get_user_info_from_username($username)
1731
{
1732
    if (empty($username)) {
1733
        return false;
1734
    }
1735
    $username = trim($username);
1736
1737
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1738
            WHERE username='".Database::escape_string($username)."'";
1739
    $result = Database::query($sql);
1740
    if (Database::num_rows($result) > 0) {
1741
        $resultArray = Database::fetch_array($result);
1742
1743
        return _api_format_user($resultArray);
1744
    }
1745
1746
    return false;
1747
}
1748
1749
/**
1750
 * Get first user with an email.
1751
 *
1752
 * @param string $email
1753
 *
1754
 * @return array|bool
1755
 */
1756
function api_get_user_info_from_email($email = '')
1757
{
1758
    if (empty($email)) {
1759
        return false;
1760
    }
1761
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1762
            WHERE email ='".Database::escape_string($email)."' LIMIT 1";
1763
    $result = Database::query($sql);
1764
    if (Database::num_rows($result) > 0) {
1765
        $resultArray = Database::fetch_array($result);
1766
1767
        return _api_format_user($resultArray);
1768
    }
1769
1770
    return false;
1771
}
1772
1773
/**
1774
 * @return string
1775
 */
1776
function api_get_course_id()
1777
{
1778
    return Session::read('_cid', null);
1779
}
1780
1781
/**
1782
 * Returns the current course id (integer).
1783
 *
1784
 * @param string $code Optional course code
1785
 *
1786
 * @return int
1787
 */
1788
function api_get_course_int_id($code = null)
1789
{
1790
    if (!empty($code)) {
1791
        $code = Database::escape_string($code);
1792
        $row = Database::select(
1793
            'id',
1794
            Database::get_main_table(TABLE_MAIN_COURSE),
1795
            ['where' => ['code = ?' => [$code]]],
1796
            'first'
1797
        );
1798
1799
        if (is_array($row) && isset($row['id'])) {
1800
            return $row['id'];
1801
        } else {
1802
            return false;
1803
        }
1804
    }
1805
1806
    return Session::read('_real_cid', 0);
1807
}
1808
1809
/**
1810
 * Gets a course setting from the current course_setting table. Try always using integer values.
1811
 *
1812
 * @param string       $settingName The name of the setting we want from the table
1813
 * @param Course|array $courseInfo
1814
 * @param bool         $force       force checking the value in the database
1815
 *
1816
 * @return mixed The value of that setting in that table. Return -1 if not found.
1817
 */
1818
function api_get_course_setting($settingName, $courseInfo = null, $force = false)
1819
{
1820
    if (empty($courseInfo)) {
1821
        $courseInfo = api_get_course_info();
1822
    }
1823
1824
    if (empty($courseInfo) || empty($settingName)) {
1825
        return -1;
1826
    }
1827
1828
    if ($courseInfo instanceof Course) {
1829
        $courseId = $courseInfo->getId();
1830
    } else {
1831
        $courseId = isset($courseInfo['real_id']) && !empty($courseInfo['real_id']) ? $courseInfo['real_id'] : 0;
1832
    }
1833
1834
    if (empty($courseId)) {
1835
        return -1;
1836
    }
1837
1838
    static $courseSettingInfo = [];
1839
1840
    if ($force) {
1841
        $courseSettingInfo = [];
1842
    }
1843
1844
    if (!isset($courseSettingInfo[$courseId])) {
1845
        $table = Database::get_course_table(TABLE_COURSE_SETTING);
1846
        $settingName = Database::escape_string($settingName);
1847
1848
        $sql = "SELECT variable, value FROM $table
1849
                WHERE c_id = $courseId ";
1850
        $res = Database::query($sql);
1851
        if (Database::num_rows($res) > 0) {
1852
            $result = Database::store_result($res, 'ASSOC');
1853
            $courseSettingInfo[$courseId] = array_column($result, 'value', 'variable');
1854
1855
            if (isset($courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'])) {
1856
                $value = $courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'];
1857
                if (!is_null($value)) {
1858
                    $result = explode(',', $value);
1859
                    $courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'] = $result;
1860
                }
1861
            }
1862
        }
1863
    }
1864
1865
    if (isset($courseSettingInfo[$courseId]) && isset($courseSettingInfo[$courseId][$settingName])) {
1866
        return $courseSettingInfo[$courseId][$settingName];
1867
    }
1868
1869
    return -1;
1870
}
1871
1872
function api_get_course_plugin_setting($plugin, $settingName, $courseInfo = [])
1873
{
1874
    $value = api_get_course_setting($settingName, $courseInfo, true);
1875
1876
    if (-1 === $value) {
1877
        // Check global settings
1878
        $value = api_get_plugin_setting($plugin, $settingName);
1879
        if ('true' === $value) {
1880
            return 1;
1881
        }
1882
        if ('false' === $value) {
1883
            return 0;
1884
        }
1885
        if (null === $value) {
1886
            return -1;
1887
        }
1888
    }
1889
1890
    return $value;
1891
}
1892
1893
/**
1894
 * Gets an anonymous user ID.
1895
 *
1896
 * For some tools that need tracking, like the learnpath tool, it is necessary
1897
 * to have a usable user-id to enable some kind of tracking, even if not
1898
 * perfect. An anonymous ID is taken from the users table by looking for a
1899
 * status of "6" (anonymous).
1900
 *
1901
 * @return int User ID of the anonymous user, or O if no anonymous user found
1902
 */
1903
function api_get_anonymous_id()
1904
{
1905
    // Find if another anon is connected now
1906
    $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
1907
    $tableU = Database::get_main_table(TABLE_MAIN_USER);
1908
    $ip = Database::escape_string(api_get_real_ip());
1909
    $max = (int) api_get_configuration_value('max_anonymous_users');
1910
    if ($max >= 2) {
1911
        $sql = "SELECT * FROM $table as TEL
1912
                JOIN $tableU as U
1913
                ON U.id = TEL.login_user_id
1914
                WHERE TEL.user_ip = '$ip'
1915
                    AND U.status = ".ANONYMOUS."
1916
                    AND U.id != 2 ";
1917
1918
        $result = Database::query($sql);
1919
        if (empty(Database::num_rows($result))) {
1920
            $login = uniqid('anon_');
1921
            $anonList = UserManager::get_user_list(['status' => ANONYMOUS], ['registration_date ASC']);
1922
            if (count($anonList) >= $max) {
1923
                foreach ($anonList as $userToDelete) {
1924
                    UserManager::delete_user($userToDelete['user_id']);
1925
                    break;
1926
                }
1927
            }
1928
1929
            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...
1930
                $login,
1931
                'anon',
1932
                ANONYMOUS,
1933
                ' anonymous@localhost',
1934
                $login,
1935
                $login
1936
            );
1937
        } else {
1938
            $row = Database::fetch_array($result, 'ASSOC');
1939
1940
            return $row['id'];
1941
        }
1942
    }
1943
1944
    $table = Database::get_main_table(TABLE_MAIN_USER);
1945
    $sql = "SELECT id
1946
            FROM $table
1947
            WHERE status = ".ANONYMOUS." ";
1948
    $res = Database::query($sql);
1949
    if (Database::num_rows($res) > 0) {
1950
        $row = Database::fetch_array($res, 'ASSOC');
1951
1952
        return $row['id'];
1953
    }
1954
1955
    // No anonymous user was found.
1956
    return 0;
1957
}
1958
1959
/**
1960
 * @param int $courseId
1961
 * @param int $sessionId
1962
 * @param int $groupId
1963
 *
1964
 * @return string
1965
 */
1966
function api_get_cidreq_params($courseId, $sessionId = 0, $groupId = 0)
1967
{
1968
    $courseId = !empty($courseId) ? (int) $courseId : 0;
1969
    $sessionId = !empty($sessionId) ? (int) $sessionId : 0;
1970
    $groupId = !empty($groupId) ? (int) $groupId : 0;
1971
1972
    $url = 'cid='.$courseId;
1973
    $url .= '&sid='.$sessionId;
1974
    $url .= '&gid='.$groupId;
1975
1976
    return $url;
1977
}
1978
1979
/**
1980
 * Returns the current course url part including session, group, and gradebook params.
1981
 *
1982
 * @param bool   $addSessionId
1983
 * @param bool   $addGroupId
1984
 * @param string $origin
1985
 *
1986
 * @return string Course & session references to add to a URL
1987
 */
1988
function api_get_cidreq($addSessionId = true, $addGroupId = true, $origin = '')
1989
{
1990
    $courseId = api_get_course_int_id();
1991
    $url = empty($courseId) ? '' : 'cid='.$courseId;
1992
    $origin = empty($origin) ? api_get_origin() : Security::remove_XSS($origin);
1993
1994
    if ($addSessionId) {
1995
        if (!empty($url)) {
1996
            $url .= 0 == api_get_session_id() ? '&sid=0' : '&sid='.api_get_session_id();
1997
        }
1998
    }
1999
2000
    if ($addGroupId) {
2001
        if (!empty($url)) {
2002
            $url .= 0 == api_get_group_id() ? '&gid=0' : '&gid='.api_get_group_id();
2003
        }
2004
    }
2005
2006
    if (!empty($url)) {
2007
        $url .= '&gradebook='.(int) api_is_in_gradebook();
2008
        $url .= '&origin='.$origin;
0 ignored issues
show
Bug introduced by
Are you sure $origin of type array|string can be used in concatenation? ( Ignorable by Annotation )

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

2008
        $url .= '&origin='./** @scrutinizer ignore-type */ $origin;
Loading history...
2009
    }
2010
2011
    return $url;
2012
}
2013
2014
/**
2015
 * Get if we visited a gradebook page.
2016
 *
2017
 * @return bool
2018
 */
2019
function api_is_in_gradebook()
2020
{
2021
    return Session::read('in_gradebook', false);
2022
}
2023
2024
/**
2025
 * Set that we are in a page inside a gradebook.
2026
 */
2027
function api_set_in_gradebook()
2028
{
2029
    Session::write('in_gradebook', true);
2030
}
2031
2032
/**
2033
 * Remove gradebook session.
2034
 */
2035
function api_remove_in_gradebook()
2036
{
2037
    Session::erase('in_gradebook');
2038
}
2039
2040
/**
2041
 * Returns the current course info array see api_format_course_array()
2042
 * If the course_code is given, the returned array gives info about that
2043
 * particular course, if none given it gets the course info from the session.
2044
 *
2045
 * @param string $courseCode
2046
 *
2047
 * @return array
2048
 */
2049
function api_get_course_info($courseCode = null)
2050
{
2051
    if (!empty($courseCode)) {
2052
        $course = Container::getCourseRepository()->findOneByCode($courseCode);
2053
2054
        return api_format_course_array($course);
2055
    }
2056
2057
    $course = Session::read('_course');
2058
    if ('-1' == $course) {
2059
        $course = [];
2060
    }
2061
2062
    return $course;
2063
}
2064
2065
/**
2066
 * @param int $courseId
2067
 */
2068
function api_get_course_entity($courseId = 0): ?Course
2069
{
2070
    if (empty($courseId)) {
2071
        $courseId = api_get_course_int_id();
2072
    }
2073
2074
    if (empty($courseId)) {
2075
        return null;
2076
    }
2077
2078
    return Container::getCourseRepository()->find($courseId);
2079
}
2080
2081
/**
2082
 * @param int $id
2083
 */
2084
function api_get_session_entity($id = 0): ?SessionEntity
2085
{
2086
    if (empty($id)) {
2087
        $id = api_get_session_id();
2088
    }
2089
2090
    if (empty($id)) {
2091
        return null;
2092
    }
2093
2094
    return Container::getSessionRepository()->find($id);
2095
}
2096
2097
/**
2098
 * @param int $id
2099
 */
2100
function api_get_group_entity($id = 0): ?CGroup
2101
{
2102
    if (empty($id)) {
2103
        $id = api_get_group_id();
2104
    }
2105
2106
    return Container::getGroupRepository()->find($id);
2107
}
2108
2109
/**
2110
 * @param int $id
2111
 */
2112
function api_get_url_entity($id = 0): ?AccessUrl
2113
{
2114
    if (empty($id)) {
2115
        $id = api_get_current_access_url_id();
2116
    }
2117
2118
    return Container::getAccessUrlRepository()->find($id);
2119
}
2120
2121
/**
2122
 * Returns the current course info array.
2123
2124
 * Now if the course_code is given, the returned array gives info about that
2125
 * particular course, not specially the current one.
2126
 *
2127
 * @param int $id Numeric ID of the course
2128
 *
2129
 * @return array The course info as an array formatted by api_format_course_array, including category.name
2130
 */
2131
function api_get_course_info_by_id($id = 0)
2132
{
2133
    $id = (int) $id;
2134
    if (empty($id)) {
2135
        $course = Session::read('_course', []);
2136
2137
        return $course;
2138
    }
2139
2140
    $course = Container::getCourseRepository()->find($id);
2141
    if (empty($course)) {
2142
        return [];
2143
    }
2144
2145
    return api_format_course_array($course);
2146
}
2147
2148
/**
2149
 * Reformat the course array (output by api_get_course_info()) in order, mostly,
2150
 * to switch from 'code' to 'id' in the array.
2151
 *
2152
 * @return array
2153
 *
2154
 * @todo eradicate the false "id"=code field of the $_course array and use the int id
2155
 */
2156
function api_format_course_array(Course $course = null)
2157
{
2158
    if (empty($course)) {
2159
        return [];
2160
    }
2161
2162
    $courseData = [];
2163
    $courseData['id'] = $courseData['real_id'] = $course->getId();
2164
2165
    // Added
2166
    $courseData['code'] = $courseData['sysCode'] = $course->getCode();
2167
    $courseData['name'] = $courseData['title'] = $course->getTitle();
2168
    $courseData['official_code'] = $courseData['visual_code'] = $course->getVisualCode();
2169
    //$courseData['path'] = $courseData['directory'] = $course->getDirectory(); // Use as key in path.
2170
    $courseData['creation_date'] = $course->getCreationDate()->format('Y-m-d H:i:s');
2171
    $courseData['titular'] = $course->getTutorName();
2172
    $courseData['language'] = $courseData['course_language'] = $course->getCourseLanguage();
2173
    $courseData['extLink']['url'] = $courseData['department_url'] = $course->getDepartmentUrl();
2174
    $courseData['extLink']['name'] = $courseData['department_name'] = $course->getDepartmentName();
2175
2176
    $courseData['visibility'] = $course->getVisibility();
2177
    $courseData['subscribe_allowed'] = $courseData['subscribe'] = $course->getSubscribe();
2178
    $courseData['unsubscribe'] = $course->getUnsubscribe();
2179
    $courseData['activate_legal'] = $course->getActivateLegal();
2180
    $courseData['legal'] = $course->getLegal();
2181
    $courseData['show_score'] = $course->getShowScore(); //used in the work tool
2182
2183
    $coursePath = '/course/';
2184
    $webCourseHome = $coursePath.$courseData['real_id'].'/home';
2185
2186
    // Course password
2187
    $courseData['registration_code'] = $course->getRegistrationCode();
2188
    $courseData['disk_quota'] = $course->getDiskQuota();
2189
    $courseData['course_public_url'] = $webCourseHome;
2190
    $courseData['about_url'] = $coursePath.$courseData['real_id'].'/about';
2191
    $courseData['add_teachers_to_sessions_courses'] = $course->isAddTeachersToSessionsCourses();
2192
2193
    $image = Display::return_icon(
2194
        'course.png',
2195
        null,
2196
        null,
2197
        ICON_SIZE_BIG,
2198
        null,
2199
        true,
2200
        false
2201
    );
2202
2203
    $illustration = Container::getIllustrationRepository()->getIllustrationUrl($course);
2204
    if (!empty($illustration)) {
2205
        $image = $illustration;
2206
    }
2207
2208
    $courseData['course_image'] = $image.'?filter=course_picture_small';
2209
    $courseData['course_image_large'] = $image.'?filter=course_picture_medium';
2210
2211
    return $courseData;
2212
}
2213
2214
/**
2215
 * Returns a difficult to guess password.
2216
 *
2217
 * @param int $length the length of the password
2218
 *
2219
 * @return string the generated password
2220
 */
2221
function api_generate_password($length = 8)
2222
{
2223
    if ($length < 2) {
2224
        $length = 2;
2225
    }
2226
2227
    $charactersLowerCase = 'abcdefghijkmnopqrstuvwxyz';
2228
    $charactersUpperCase = 'ABCDEFGHJKLMNPQRSTUVWXYZ';
2229
    $minNumbers = 2;
2230
    $length = $length - $minNumbers;
2231
    $minLowerCase = round($length / 2);
2232
    $minUpperCase = $length - $minLowerCase;
2233
2234
    $password = '';
2235
    $passwordRequirements = api_get_configuration_value('password_requirements');
2236
2237
    $factory = new RandomLib\Factory();
2238
    $generator = $factory->getGenerator(new SecurityLib\Strength(SecurityLib\Strength::MEDIUM));
2239
2240
    if (!empty($passwordRequirements)) {
2241
        $length = $passwordRequirements['min']['length'];
2242
        $minNumbers = $passwordRequirements['min']['numeric'];
2243
        $minLowerCase = $passwordRequirements['min']['lowercase'];
2244
        $minUpperCase = $passwordRequirements['min']['uppercase'];
2245
2246
        $rest = $length - $minNumbers - $minLowerCase - $minUpperCase;
2247
        // Add the rest to fill the length requirement
2248
        if ($rest > 0) {
2249
            $password .= $generator->generateString($rest, $charactersLowerCase.$charactersUpperCase);
2250
        }
2251
    }
2252
2253
    // Min digits default 2
2254
    for ($i = 0; $i < $minNumbers; $i++) {
2255
        $password .= $generator->generateInt(2, 9);
2256
    }
2257
2258
    // Min lowercase
2259
    $password .= $generator->generateString($minLowerCase, $charactersLowerCase);
2260
2261
    // Min uppercase
2262
    $password .= $generator->generateString($minUpperCase, $charactersUpperCase);
2263
    $password = str_shuffle($password);
2264
2265
    return $password;
2266
}
2267
2268
/**
2269
 * Checks a password to see wether it is OK to use.
2270
 *
2271
 * @param string $password
2272
 *
2273
 * @return bool if the password is acceptable, false otherwise
2274
 *              Notes about what a password "OK to use" is:
2275
 *              1. The password should be at least 5 characters long.
2276
 *              2. Only English letters (uppercase or lowercase, it doesn't matter) and digits are allowed.
2277
 *              3. The password should contain at least 3 letters.
2278
 *              4. It should contain at least 2 digits.
2279
 *              Settings will change if the configuration value is set: password_requirements
2280
 */
2281
function api_check_password($password)
2282
{
2283
    $passwordRequirements = Security::getPasswordRequirements();
2284
2285
    $minLength = $passwordRequirements['min']['length'];
2286
    $minNumbers = $passwordRequirements['min']['numeric'];
2287
    // Optional
2288
    $minLowerCase = $passwordRequirements['min']['lowercase'];
2289
    $minUpperCase = $passwordRequirements['min']['uppercase'];
2290
2291
    $minLetters = $minLowerCase + $minUpperCase;
2292
    $passwordLength = api_strlen($password);
2293
2294
    $conditions = [
2295
        'min_length' => $passwordLength >= $minLength,
2296
    ];
2297
2298
    $digits = 0;
2299
    $lowerCase = 0;
2300
    $upperCase = 0;
2301
2302
    for ($i = 0; $i < $passwordLength; $i++) {
2303
        $currentCharacterCode = api_ord(api_substr($password, $i, 1));
2304
        if ($currentCharacterCode >= 65 && $currentCharacterCode <= 90) {
2305
            $upperCase++;
2306
        }
2307
2308
        if ($currentCharacterCode >= 97 && $currentCharacterCode <= 122) {
2309
            $lowerCase++;
2310
        }
2311
        if ($currentCharacterCode >= 48 && $currentCharacterCode <= 57) {
2312
            $digits++;
2313
        }
2314
    }
2315
2316
    // Min number of digits
2317
    $conditions['min_numeric'] = $digits >= $minNumbers;
2318
2319
    if (!empty($minUpperCase)) {
2320
        // Uppercase
2321
        $conditions['min_uppercase'] = $upperCase >= $minUpperCase;
2322
    }
2323
2324
    if (!empty($minLowerCase)) {
2325
        // Lowercase
2326
        $conditions['min_lowercase'] = $upperCase >= $minLowerCase;
2327
    }
2328
2329
    // Min letters
2330
    $letters = $upperCase + $lowerCase;
2331
    $conditions['min_letters'] = $letters >= $minLetters;
2332
2333
    $isPasswordOk = true;
2334
    foreach ($conditions as $condition) {
2335
        if (false === $condition) {
2336
            $isPasswordOk = false;
2337
            break;
2338
        }
2339
    }
2340
2341
    if (false === $isPasswordOk) {
2342
        $output = get_lang('The new password does not match the minimum security requirements').'<br />';
2343
        $output .= Security::getPasswordRequirementsToString($conditions);
2344
2345
        Display::addFlash(Display::return_message($output, 'warning', false));
2346
    }
2347
2348
    return $isPasswordOk;
2349
}
2350
2351
/**
2352
 * Gets the current Chamilo (not PHP/cookie) session ID.
2353
 *
2354
 * @return int O if no active session, the session ID otherwise
2355
 */
2356
function api_get_session_id()
2357
{
2358
    return (int) Session::read('sid', 0);
2359
}
2360
2361
/**
2362
 * Gets the current Chamilo (not social network) group ID.
2363
 *
2364
 * @return int O if no active session, the session ID otherwise
2365
 */
2366
function api_get_group_id()
2367
{
2368
    return Session::read('gid', 0);
2369
}
2370
2371
/**
2372
 * Gets the current or given session name.
2373
 *
2374
 * @param   int     Session ID (optional)
2375
 *
2376
 * @return string The session name, or null if not found
2377
 */
2378
function api_get_session_name($session_id = 0)
2379
{
2380
    if (empty($session_id)) {
2381
        $session_id = api_get_session_id();
2382
        if (empty($session_id)) {
2383
            return null;
2384
        }
2385
    }
2386
    $t = Database::get_main_table(TABLE_MAIN_SESSION);
2387
    $s = "SELECT name FROM $t WHERE id = ".(int) $session_id;
2388
    $r = Database::query($s);
2389
    $c = Database::num_rows($r);
2390
    if ($c > 0) {
2391
        //technically, there can be only one, but anyway we take the first
2392
        $rec = Database::fetch_array($r);
2393
2394
        return $rec['name'];
2395
    }
2396
2397
    return null;
2398
}
2399
2400
/**
2401
 * Gets the session info by id.
2402
 *
2403
 * @param int $id Session ID
2404
 *
2405
 * @return array information of the session
2406
 */
2407
function api_get_session_info($id)
2408
{
2409
    return SessionManager::fetch($id);
2410
}
2411
2412
/**
2413
 * Gets the session visibility by session id.
2414
 *
2415
 * @param int  $session_id
2416
 * @param int  $courseId
2417
 * @param bool $ignore_visibility_for_admins
2418
 *
2419
 * @return int
2420
 *             0 = session still available,
2421
 *             SESSION_VISIBLE_READ_ONLY = 1,
2422
 *             SESSION_VISIBLE = 2,
2423
 *             SESSION_INVISIBLE = 3
2424
 */
2425
function api_get_session_visibility(
2426
    $session_id,
2427
    $courseId = null,
2428
    $ignore_visibility_for_admins = true,
2429
    $userId = 0
2430
) {
2431
    if (api_is_platform_admin()) {
2432
        if ($ignore_visibility_for_admins) {
2433
            return SESSION_AVAILABLE;
2434
        }
2435
    }
2436
    $userId = empty($userId) ? api_get_user_id() : (int) $userId;
2437
2438
    $now = time();
2439
    if (empty($session_id)) {
2440
        return 0; // Means that the session is still available.
2441
    }
2442
2443
    $session_id = (int) $session_id;
2444
    $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
2445
2446
    $result = Database::query("SELECT * FROM $tbl_session WHERE id = $session_id");
2447
2448
    if (Database::num_rows($result) <= 0) {
2449
        return SESSION_INVISIBLE;
2450
    }
2451
2452
    $row = Database::fetch_array($result, 'ASSOC');
2453
    $visibility = $row['visibility'];
2454
2455
    // I don't care the session visibility.
2456
    if (empty($row['access_start_date']) && empty($row['access_end_date'])) {
2457
        // Session duration per student.
2458
        if (isset($row['duration']) && !empty($row['duration'])) {
2459
            $duration = $row['duration'] * 24 * 60 * 60;
2460
            $courseAccess = CourseManager::getFirstCourseAccessPerSessionAndUser($session_id, $userId);
2461
2462
            // If there is a session duration but there is no previous
2463
            // access by the user, then the session is still available
2464
            if (0 == count($courseAccess)) {
2465
                return SESSION_AVAILABLE;
2466
            }
2467
2468
            $currentTime = time();
2469
            $firstAccess = isset($courseAccess['login_course_date'])
2470
                ? api_strtotime($courseAccess['login_course_date'], 'UTC')
2471
                : 0;
2472
            $userDurationData = SessionManager::getUserSession($userId, $session_id);
2473
            $userDuration = isset($userDurationData['duration'])
2474
                ? (intval($userDurationData['duration']) * 24 * 60 * 60)
2475
                : 0;
2476
2477
            $totalDuration = $firstAccess + $duration + $userDuration;
2478
2479
            return $totalDuration > $currentTime ? SESSION_AVAILABLE : SESSION_VISIBLE_READ_ONLY;
2480
        }
2481
2482
        return SESSION_AVAILABLE;
2483
    }
2484
2485
    // If start date was set.
2486
    if (!empty($row['access_start_date'])) {
2487
        $visibility = $now > api_strtotime($row['access_start_date'], 'UTC') ? SESSION_AVAILABLE : SESSION_INVISIBLE;
2488
    }
2489
2490
    // If the end date was set.
2491
    if (!empty($row['access_end_date'])) {
2492
        // Only if date_start said that it was ok
2493
        if (SESSION_AVAILABLE === $visibility) {
2494
            $visibility = $now < api_strtotime($row['access_end_date'], 'UTC')
2495
                ? SESSION_AVAILABLE // Date still available
2496
                : $row['visibility']; // Session ends
2497
        }
2498
    }
2499
2500
    // If I'm a coach the visibility can change in my favor depending in the coach dates.
2501
    $isCoach = api_is_coach($session_id, $courseId);
2502
2503
    if ($isCoach) {
2504
        // Test start date.
2505
        if (!empty($row['coach_access_start_date'])) {
2506
            $start = api_strtotime($row['coach_access_start_date'], 'UTC');
2507
            $visibility = $start < $now ? SESSION_AVAILABLE : SESSION_INVISIBLE;
2508
        }
2509
2510
        // Test end date.
2511
        if (!empty($row['coach_access_end_date'])) {
2512
            if (SESSION_AVAILABLE === $visibility) {
2513
                $endDateCoach = api_strtotime($row['coach_access_end_date'], 'UTC');
2514
                $visibility = $endDateCoach >= $now ? SESSION_AVAILABLE : $row['visibility'];
2515
            }
2516
        }
2517
    }
2518
2519
    return $visibility;
2520
}
2521
2522
/**
2523
 * This function returns a (star) session icon if the session is not null and
2524
 * the user is not a student.
2525
 *
2526
 * @param int $sessionId
2527
 * @param int $statusId  User status id - if 5 (student), will return empty
2528
 *
2529
 * @return string Session icon
2530
 */
2531
function api_get_session_image($sessionId, User $user)
2532
{
2533
    $sessionId = (int) $sessionId;
2534
    $image = '';
2535
    if (!$user->hasRole('ROLE_STUDENT')) {
2536
        // Check whether is not a student
2537
        if ($sessionId > 0) {
2538
            $image = '&nbsp;&nbsp;'.Display::return_icon(
2539
                'star.png',
2540
                get_lang('Session-specific resource'),
2541
                ['align' => 'absmiddle'],
2542
                ICON_SIZE_SMALL
2543
            );
2544
        }
2545
    }
2546
2547
    return $image;
2548
}
2549
2550
/**
2551
 * This function add an additional condition according to the session of the course.
2552
 *
2553
 * @param int    $session_id        session id
2554
 * @param bool   $and               optional, true if more than one condition false if the only condition in the query
2555
 * @param bool   $with_base_content optional, true to accept content with session=0 as well,
2556
 *                                  false for strict session condition
2557
 * @param string $session_field
2558
 *
2559
 * @return string condition of the session
2560
 */
2561
function api_get_session_condition(
2562
    $session_id,
2563
    $and = true,
2564
    $with_base_content = false,
2565
    $session_field = 'session_id'
2566
) {
2567
    $session_id = (int) $session_id;
2568
2569
    if (empty($session_field)) {
2570
        $session_field = 'session_id';
2571
    }
2572
    // Condition to show resources by session
2573
    $condition_add = $and ? ' AND ' : ' WHERE ';
2574
2575
    if ($with_base_content) {
2576
        $condition_session = $condition_add." ( $session_field = $session_id OR $session_field = 0 OR $session_field IS NULL) ";
2577
    } else {
2578
        if (empty($session_id)) {
2579
            $condition_session = $condition_add." ($session_field = $session_id OR $session_field IS NULL)";
2580
        } else {
2581
            $condition_session = $condition_add." $session_field = $session_id ";
2582
        }
2583
    }
2584
2585
    return $condition_session;
2586
}
2587
2588
/**
2589
 * Returns the value of a setting from the web-adjustable admin config settings.
2590
 *
2591
 * WARNING true/false are stored as string, so when comparing you need to check e.g.
2592
 * if (api_get_setting('show_navigation_menu') == 'true') //CORRECT
2593
 * instead of
2594
 * if (api_get_setting('show_navigation_menu') == true) //INCORRECT
2595
 *
2596
 * @param string $variable The variable name
2597
 *
2598
 * @return string|array
2599
 */
2600
function api_get_setting($variable)
2601
{
2602
    $settingsManager = Container::getSettingsManager();
2603
    if (empty($settingsManager)) {
2604
        return '';
2605
    }
2606
    $variable = trim($variable);
2607
2608
    switch ($variable) {
2609
        case 'server_type':
2610
            $test = ['dev', 'test'];
2611
            $environment = Container::getEnvironment();
2612
            if (in_array($environment, $test)) {
2613
                return 'test';
2614
            }
2615
2616
            return 'prod';
2617
        case 'stylesheets':
2618
            $variable = 'platform.theme';
2619
        // deprecated settings
2620
        // no break
2621
        case 'openid_authentication':
2622
        case 'service_ppt2lp':
2623
        case 'formLogin_hide_unhide_label':
2624
            return false;
2625
            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...
2626
        case 'tool_visible_by_default_at_creation':
2627
            $values = $settingsManager->getSetting($variable);
2628
            $newResult = [];
2629
            foreach ($values as $parameter) {
2630
                $newResult[$parameter] = 'true';
2631
            }
2632
2633
            return $newResult;
2634
            break;
2635
        default:
2636
            return $settingsManager->getSetting($variable);
2637
            break;
2638
    }
2639
}
2640
2641
/**
2642
 * @param string $variable
2643
 * @param string $option
2644
 *
2645
 * @return bool
2646
 */
2647
function api_get_setting_in_list($variable, $option)
2648
{
2649
    $value = api_get_setting($variable);
2650
2651
    return in_array($option, $value);
2652
}
2653
2654
/**
2655
 * @param string $plugin
2656
 * @param string $variable
2657
 *
2658
 * @return string
2659
 */
2660
function api_get_plugin_setting($plugin, $variable)
2661
{
2662
    $variableName = $plugin.'_'.$variable;
2663
    //$result = api_get_setting($variableName);
2664
    $params = [
2665
        'category = ? AND subkey = ? AND variable = ?' => [
2666
            'Plugins',
2667
            $plugin,
2668
            $variableName,
2669
        ],
2670
    ];
2671
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2672
    $result = Database::select(
2673
        'selected_value',
2674
        $table,
2675
        ['where' => $params],
2676
        'one'
2677
    );
2678
    if ($result) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $result of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
2679
        $value = $result['selected_value'];
2680
        $serializedValue = @unserialize($result['selected_value'], []);
2681
        if (false !== $serializedValue) {
2682
            $value = $serializedValue;
2683
        }
2684
2685
        return $value;
2686
    }
2687
2688
    return null;
2689
    /// Old code
2690
2691
    $variableName = $plugin.'_'.$variable;
0 ignored issues
show
Unused Code introduced by
$variableName = $plugin . '_' . $variable is not reachable.

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

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

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

    return false;
}

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

Loading history...
2692
    $result = api_get_setting($variableName);
2693
2694
    if (isset($result[$plugin])) {
2695
        $value = $result[$plugin];
2696
2697
        $unserialized = UnserializeApi::unserialize('not_allowed_classes', $value, true);
2698
2699
        if (false !== $unserialized) {
2700
            $value = $unserialized;
2701
        }
2702
2703
        return $value;
2704
    }
2705
2706
    return null;
2707
}
2708
2709
/**
2710
 * Returns the value of a setting from the web-adjustable admin config settings.
2711
 */
2712
function api_get_settings_params($params)
2713
{
2714
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2715
2716
    return Database::select('*', $table, ['where' => $params]);
2717
}
2718
2719
/**
2720
 * @param array $params example: [id = ? => '1']
2721
 *
2722
 * @return array
2723
 */
2724
function api_get_settings_params_simple($params)
2725
{
2726
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2727
2728
    return Database::select('*', $table, ['where' => $params], 'one');
2729
}
2730
2731
/**
2732
 * Returns the value of a setting from the web-adjustable admin config settings.
2733
 */
2734
function api_delete_settings_params($params)
2735
{
2736
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2737
2738
    return Database::delete($table, $params);
2739
}
2740
2741
/**
2742
 * Returns an escaped version of $_SERVER['PHP_SELF'] to avoid XSS injection.
2743
 *
2744
 * @return string Escaped version of $_SERVER['PHP_SELF']
2745
 */
2746
function api_get_self()
2747
{
2748
    return htmlentities($_SERVER['PHP_SELF']);
2749
}
2750
2751
/**
2752
 * Checks whether current user is a platform administrator.
2753
 *
2754
 * @param bool $allowSessionAdmins Whether session admins should be considered admins or not
2755
 * @param bool $allowDrh           Whether HR directors should be considered admins or not
2756
 *
2757
 * @return bool true if the user has platform admin rights,
2758
 *              false otherwise
2759
 *
2760
 * @see usermanager::is_admin(user_id) for a user-id specific function
2761
 */
2762
function api_is_platform_admin($allowSessionAdmins = false, $allowDrh = false)
2763
{
2764
    $currentUser = api_get_current_user();
2765
2766
    if (null === $currentUser) {
2767
        return false;
2768
    }
2769
2770
    ///$isAdmin = Session::read('is_platformAdmin');
2771
    $isAdmin = $currentUser->hasRole('ROLE_ADMIN');
2772
2773
    if ($isAdmin) {
2774
        return true;
2775
    }
2776
2777
    if ($allowSessionAdmins && $currentUser->hasRole('ROLE_SESSION_MANAGER')) {
2778
        return true;
2779
    }
2780
2781
    if ($allowDrh && $currentUser->hasRole('ROLE_RRHH')) {
2782
        return true;
2783
    }
2784
2785
    return false;
2786
}
2787
2788
/**
2789
 * Checks whether the user given as user id is in the admin table.
2790
 *
2791
 * @param int $user_id If none provided, will use current user
2792
 * @param int $url     URL ID. If provided, also check if the user is active on given URL
2793
 *
2794
 * @return bool True if the user is admin, false otherwise
2795
 */
2796
function api_is_platform_admin_by_id($user_id = null, $url = null)
2797
{
2798
    $user_id = (int) $user_id;
2799
    if (empty($user_id)) {
2800
        $user_id = api_get_user_id();
2801
    }
2802
    $admin_table = Database::get_main_table(TABLE_MAIN_ADMIN);
2803
    $sql = "SELECT * FROM $admin_table WHERE user_id = $user_id";
2804
    $res = Database::query($sql);
2805
    $is_admin = 1 === Database::num_rows($res);
2806
    if (!$is_admin || !isset($url)) {
2807
        return $is_admin;
2808
    }
2809
    // We get here only if $url is set
2810
    $url = (int) $url;
2811
    $url_user_table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
2812
    $sql = "SELECT * FROM $url_user_table
2813
            WHERE access_url_id = $url AND user_id = $user_id";
2814
    $res = Database::query($sql);
2815
2816
    return 1 === Database::num_rows($res);
2817
}
2818
2819
/**
2820
 * Checks whether current user is allowed to create courses.
2821
 *
2822
 * @return bool true if the user has course creation rights,
2823
 *              false otherwise
2824
 */
2825
function api_is_allowed_to_create_course()
2826
{
2827
    if (api_is_platform_admin()) {
2828
        return true;
2829
    }
2830
2831
    // Teachers can only create courses
2832
    if (api_is_teacher()) {
2833
        if ('true' === api_get_setting('allow_users_to_create_courses')) {
2834
            return true;
2835
        } else {
2836
            return false;
2837
        }
2838
    }
2839
2840
    return Session::read('is_allowedCreateCourse');
2841
}
2842
2843
/**
2844
 * Checks whether the current user is a course administrator.
2845
 *
2846
 * @return bool True if current user is a course administrator
2847
 */
2848
function api_is_course_admin()
2849
{
2850
    if (api_is_platform_admin()) {
2851
        return true;
2852
    }
2853
2854
    $user = api_get_current_user();
2855
    if ($user) {
2856
        if (
2857
            $user->hasRole('ROLE_CURRENT_COURSE_SESSION_TEACHER') ||
2858
            $user->hasRole('ROLE_CURRENT_COURSE_TEACHER')
2859
        ) {
2860
            return true;
2861
        }
2862
    }
2863
2864
    return false;
2865
}
2866
2867
/**
2868
 * Checks whether the current user is a course coach
2869
 * Based on the presence of user in session.id_coach (session general coach).
2870
 *
2871
 * @return bool True if current user is a course coach
2872
 */
2873
function api_is_session_general_coach()
2874
{
2875
    return Session::read('is_session_general_coach');
2876
}
2877
2878
/**
2879
 * Checks whether the current user is a course tutor
2880
 * Based on the presence of user in session_rel_course_rel_user.user_id with status = 2.
2881
 *
2882
 * @return bool True if current user is a course tutor
2883
 */
2884
function api_is_course_tutor()
2885
{
2886
    return Session::read('is_courseTutor');
2887
}
2888
2889
/**
2890
 * @param int $user_id
2891
 * @param int $courseId
2892
 * @param int $session_id
2893
 *
2894
 * @return bool
2895
 */
2896
function api_is_course_session_coach($user_id, $courseId, $session_id)
2897
{
2898
    $session_table = Database::get_main_table(TABLE_MAIN_SESSION);
2899
    $session_rel_course_rel_user_table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2900
2901
    $user_id = (int) $user_id;
2902
    $session_id = (int) $session_id;
2903
    $courseId = (int) $courseId;
2904
2905
    $sql = "SELECT DISTINCT session.id
2906
            FROM $session_table
2907
            INNER JOIN $session_rel_course_rel_user_table session_rc_ru
2908
            ON session.id = session_rc_ru.session_id
2909
            WHERE
2910
                session_rc_ru.user_id = '".$user_id."'  AND
2911
                session_rc_ru.c_id = '$courseId' AND
2912
                session_rc_ru.status = 2 AND
2913
                session_rc_ru.session_id = '$session_id'";
2914
    $result = Database::query($sql);
2915
2916
    return Database::num_rows($result) > 0;
2917
}
2918
2919
/**
2920
 * Checks whether the current user is a course or session coach.
2921
 *
2922
 * @param int $session_id
2923
 * @param int $courseId
2924
 * @param bool  Check whether we are in student view and, if we are, return false
2925
 * @param int $userId
2926
 *
2927
 * @return bool True if current user is a course or session coach
2928
 */
2929
function api_is_coach($session_id = 0, $courseId = null, $check_student_view = true, $userId = 0)
2930
{
2931
    $userId = empty($userId) ? api_get_user_id() : (int) $userId;
2932
2933
    if (!empty($session_id)) {
2934
        $session_id = (int) $session_id;
2935
    } else {
2936
        $session_id = api_get_session_id();
2937
    }
2938
2939
    // The student preview was on
2940
    if ($check_student_view && api_is_student_view_active()) {
2941
        return false;
2942
    }
2943
2944
    if (!empty($courseId)) {
2945
        $courseId = (int) $courseId;
2946
    } else {
2947
        $courseId = api_get_course_int_id();
2948
    }
2949
2950
    $session_table = Database::get_main_table(TABLE_MAIN_SESSION);
2951
    $session_rel_course_rel_user_table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2952
    $sessionIsCoach = [];
2953
2954
    if (!empty($courseId)) {
2955
        $sql = "SELECT DISTINCT s.id, name, access_start_date, access_end_date
2956
                FROM $session_table s
2957
                INNER JOIN $session_rel_course_rel_user_table session_rc_ru
2958
                ON session_rc_ru.session_id = s.id AND session_rc_ru.user_id = '".$userId."'
2959
                WHERE
2960
                    session_rc_ru.c_id = '$courseId' AND
2961
                    session_rc_ru.status = 2 AND
2962
                    session_rc_ru.session_id = '$session_id'";
2963
        $result = Database::query($sql);
2964
        $sessionIsCoach = Database::store_result($result);
2965
    }
2966
2967
    if (!empty($session_id)) {
2968
        $sql = "SELECT DISTINCT id, name, access_start_date, access_end_date
2969
                FROM $session_table
2970
                WHERE session.id_coach = $userId AND id = $session_id
2971
                ORDER BY access_start_date, access_end_date, name";
2972
        $result = Database::query($sql);
2973
        if (!empty($sessionIsCoach)) {
2974
            $sessionIsCoach = array_merge(
2975
                $sessionIsCoach,
2976
                Database::store_result($result)
2977
            );
2978
        } else {
2979
            $sessionIsCoach = Database::store_result($result);
2980
        }
2981
    }
2982
2983
    return count($sessionIsCoach) > 0;
2984
}
2985
2986
function api_user_has_role(string $role, ?User $user = null): bool
2987
{
2988
    if (null === $user) {
2989
        $user = api_get_current_user();
2990
    }
2991
2992
    if (null === $user) {
2993
        return false;
2994
    }
2995
2996
    return $user->hasRole($role);
2997
}
2998
2999
function api_is_allowed_in_course(): bool
3000
{
3001
    if (api_is_platform_admin()) {
3002
        return true;
3003
    }
3004
3005
    $user = api_get_current_user();
3006
    if ($user instanceof User) {
3007
        if ($user->hasRole('ROLE_CURRENT_COURSE_SESSION_STUDENT') ||
3008
            $user->hasRole('ROLE_CURRENT_COURSE_SESSION_TEACHER') ||
3009
            $user->hasRole('ROLE_CURRENT_COURSE_STUDENT') ||
3010
            $user->hasRole('ROLE_CURRENT_COURSE_TEACHER')
3011
        ) {
3012
            return true;
3013
        }
3014
    }
3015
3016
    return false;
3017
}
3018
3019
/**
3020
 * Checks whether current user is a student boss.
3021
 */
3022
function api_is_student_boss(?User $user = null): bool
3023
{
3024
    return api_user_has_role('ROLE_STUDENT_BOSS', $user);
3025
}
3026
3027
/**
3028
 * Checks whether the current user is a session administrator.
3029
 *
3030
 * @return bool True if current user is a course administrator
3031
 */
3032
function api_is_session_admin(?User $user = null)
3033
{
3034
    return api_user_has_role('ROLE_SESSION_MANAGER', $user);
3035
}
3036
3037
/**
3038
 * Checks whether the current user is a human resources manager.
3039
 *
3040
 * @return bool True if current user is a human resources manager
3041
 */
3042
function api_is_drh()
3043
{
3044
    return api_user_has_role('ROLE_RRHH');
3045
}
3046
3047
/**
3048
 * Checks whether the current user is a student.
3049
 *
3050
 * @return bool True if current user is a human resources manager
3051
 */
3052
function api_is_student()
3053
{
3054
    return api_user_has_role('ROLE_STUDENT');
3055
}
3056
3057
/**
3058
 * Checks whether the current user has the status 'teacher'.
3059
 *
3060
 * @return bool True if current user is a human resources manager
3061
 */
3062
function api_is_teacher()
3063
{
3064
    return api_user_has_role('ROLE_TEACHER');
3065
}
3066
3067
/**
3068
 * Checks whether the current user is a invited user.
3069
 *
3070
 * @return bool
3071
 */
3072
function api_is_invitee()
3073
{
3074
    return api_user_has_role('ROLE_INVITEE');
3075
}
3076
3077
/**
3078
 * This function checks whether a session is assigned into a category.
3079
 *
3080
 * @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...
3081
 * @param string    - category name
3082
 *
3083
 * @return bool - true if is found, otherwise false
3084
 */
3085
function api_is_session_in_category($session_id, $category_name)
3086
{
3087
    $session_id = (int) $session_id;
3088
    $category_name = Database::escape_string($category_name);
3089
    $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
3090
    $tbl_session_category = Database::get_main_table(TABLE_MAIN_SESSION_CATEGORY);
3091
3092
    $sql = "SELECT 1
3093
            FROM $tbl_session
3094
            WHERE $session_id IN (
3095
                SELECT s.id FROM $tbl_session s, $tbl_session_category sc
3096
                WHERE
3097
                  s.session_category_id = sc.id AND
3098
                  sc.name LIKE '%$category_name'
3099
            )";
3100
    $rs = Database::query($sql);
3101
3102
    if (Database::num_rows($rs) > 0) {
3103
        return true;
3104
    }
3105
3106
    return false;
3107
}
3108
3109
/**
3110
 * Displays options for switching between student view and course manager view.
3111
 *
3112
 * Changes in version 1.2 (Patrick Cool)
3113
 * Student view switch now behaves as a real switch. It maintains its current state until the state
3114
 * is changed explicitly
3115
 *
3116
 * Changes in version 1.1 (Patrick Cool)
3117
 * student view now works correctly in subfolders of the document tool
3118
 * student view works correctly in the new links tool
3119
 *
3120
 * Example code for using this in your tools:
3121
 * //if ($is_courseAdmin && api_get_setting('student_view_enabled') == 'true') {
3122
 * //   display_tool_view_option($isStudentView);
3123
 * //}
3124
 * //and in later sections, use api_is_allowed_to_edit()
3125
 *
3126
 * @author Roan Embrechts
3127
 * @author Patrick Cool
3128
 * @author Julio Montoya, changes added in Chamilo
3129
 *
3130
 * @version 1.2
3131
 *
3132
 * @todo rewrite code so it is easier to understand
3133
 */
3134
function api_display_tool_view_option()
3135
{
3136
    if ('true' != api_get_setting('student_view_enabled')) {
3137
        return '';
3138
    }
3139
3140
    $sourceurl = '';
3141
    $is_framed = false;
3142
    // Exceptions apply for all multi-frames pages
3143
    if (false !== strpos($_SERVER['REQUEST_URI'], 'chat/chat_banner.php')) {
3144
        // The chat is a multiframe bit that doesn't work too well with the student_view, so do not show the link
3145
        return '';
3146
    }
3147
3148
    // Uncomment to remove student view link from document view page
3149
    if (false !== strpos($_SERVER['REQUEST_URI'], 'lp/lp_header.php')) {
3150
        if (empty($_GET['lp_id'])) {
3151
            return '';
3152
        }
3153
        $sourceurl = substr($_SERVER['REQUEST_URI'], 0, strpos($_SERVER['REQUEST_URI'], '?'));
3154
        $sourceurl = str_replace(
3155
            'lp/lp_header.php',
3156
            'lp/lp_controller.php?'.api_get_cidreq().'&action=view&lp_id='.intval($_GET['lp_id']).'&isStudentView='.('studentview' == $_SESSION['studentview'] ? 'false' : 'true'),
3157
            $sourceurl
3158
        );
3159
        //showinframes doesn't handle student view anyway...
3160
        //return '';
3161
        $is_framed = true;
3162
    }
3163
3164
    // Check whether the $_SERVER['REQUEST_URI'] contains already url parameters (thus a questionmark)
3165
    if (!$is_framed) {
3166
        if (false === strpos($_SERVER['REQUEST_URI'], '?')) {
3167
            $sourceurl = api_get_self().'?'.api_get_cidreq();
3168
        } else {
3169
            $sourceurl = $_SERVER['REQUEST_URI'];
3170
        }
3171
    }
3172
3173
    $output_string = '';
3174
    if (!empty($_SESSION['studentview'])) {
3175
        if ('studentview' == $_SESSION['studentview']) {
3176
            // We have to remove the isStudentView=true from the $sourceurl
3177
            $sourceurl = str_replace('&isStudentView=true', '', $sourceurl);
3178
            $sourceurl = str_replace('&isStudentView=false', '', $sourceurl);
3179
            $output_string .= '<a class="btn btn-primary btn-sm" href="'.$sourceurl.'&isStudentView=false" target="_self">'.
3180
                Display::returnFontAwesomeIcon('eye').' '.get_lang('Switch to teacher view').'</a>';
3181
        } elseif ('teacherview' == $_SESSION['studentview']) {
3182
            // Switching to teacherview
3183
            $sourceurl = str_replace('&isStudentView=true', '', $sourceurl);
3184
            $sourceurl = str_replace('&isStudentView=false', '', $sourceurl);
3185
            $output_string .= '<a class="btn btn-default btn-sm" href="'.$sourceurl.'&isStudentView=true" target="_self">'.
3186
                Display::returnFontAwesomeIcon('eye').' '.get_lang('Switch to student view').'</a>';
3187
        }
3188
    } else {
3189
        $output_string .= '<a class="btn btn-default btn-sm" href="'.$sourceurl.'&isStudentView=true" target="_self">'.
3190
            Display::returnFontAwesomeIcon('eye').' '.get_lang('Switch to student view').'</a>';
3191
    }
3192
    $output_string = Security::remove_XSS($output_string);
3193
    $html = Display::tag('div', $output_string, ['class' => 'view-options']);
3194
3195
    return $html;
3196
}
3197
3198
/**
3199
 * Function that removes the need to directly use is_courseAdmin global in
3200
 * tool scripts. It returns true or false depending on the user's rights in
3201
 * this particular course.
3202
 * Optionally checking for tutor and coach roles here allows us to use the
3203
 * student_view feature altogether with these roles as well.
3204
 *
3205
 * @param bool  Whether to check if the user has the tutor role
3206
 * @param bool  Whether to check if the user has the coach role
3207
 * @param bool  Whether to check if the user has the session coach role
3208
 * @param bool  check the student view or not
3209
 *
3210
 * @author Roan Embrechts
3211
 * @author Patrick Cool
3212
 * @author Julio Montoya
3213
 *
3214
 * @version 1.1, February 2004
3215
 *
3216
 * @return bool true: the user has the rights to edit, false: he does not
3217
 */
3218
function api_is_allowed_to_edit(
3219
    $tutor = false,
3220
    $coach = false,
3221
    $session_coach = false,
3222
    $check_student_view = true
3223
) {
3224
    $allowSessionAdminEdit = true === api_get_setting('session.session_admins_edit_courses_content');
3225
    // Admins can edit anything.
3226
    if (api_is_platform_admin($allowSessionAdminEdit)) {
3227
        //The student preview was on
3228
        if ($check_student_view && api_is_student_view_active()) {
3229
            return false;
3230
        }
3231
3232
        return true;
3233
    }
3234
3235
    $sessionId = api_get_session_id();
3236
3237
    if ($sessionId && api_get_configuration_value('session_courses_read_only_mode')) {
3238
        $efv = new ExtraFieldValue('course');
3239
        $lockExrafieldField = $efv->get_values_by_handler_and_field_variable(
3240
            api_get_course_int_id(),
3241
            'session_courses_read_only_mode'
3242
        );
3243
3244
        if (!empty($lockExrafieldField['value'])) {
3245
            return false;
3246
        }
3247
    }
3248
3249
    $is_allowed_coach_to_edit = api_is_coach(null, null, $check_student_view);
3250
    $session_visibility = api_get_session_visibility($sessionId);
3251
    $is_courseAdmin = api_is_course_admin();
3252
3253
    if (!$is_courseAdmin && $tutor) {
3254
        // If we also want to check if the user is a tutor...
3255
        $is_courseAdmin = $is_courseAdmin || api_is_course_tutor();
3256
    }
3257
3258
    if (!$is_courseAdmin && $coach) {
3259
        // If we also want to check if the user is a coach...';
3260
        // Check if session visibility is read only for coaches.
3261
        if (SESSION_VISIBLE_READ_ONLY == $session_visibility) {
3262
            $is_allowed_coach_to_edit = false;
3263
        }
3264
3265
        if ('true' === api_get_setting('allow_coach_to_edit_course_session')) {
3266
            // Check if coach is allowed to edit a course.
3267
            $is_courseAdmin = $is_courseAdmin || $is_allowed_coach_to_edit;
3268
        }
3269
    }
3270
3271
    if (!$is_courseAdmin && $session_coach) {
3272
        $is_courseAdmin = $is_courseAdmin || $is_allowed_coach_to_edit;
3273
    }
3274
3275
    // Check if the student_view is enabled, and if so, if it is activated.
3276
    if ('true' === api_get_setting('student_view_enabled')) {
3277
        $studentView = api_is_student_view_active();
3278
        if (!empty($sessionId)) {
3279
            // Check if session visibility is read only for coaches.
3280
            if (SESSION_VISIBLE_READ_ONLY == $session_visibility) {
3281
                $is_allowed_coach_to_edit = false;
3282
            }
3283
3284
            $is_allowed = false;
3285
            if ('true' === api_get_setting('allow_coach_to_edit_course_session')) {
3286
                // Check if coach is allowed to edit a course.
3287
                $is_allowed = $is_allowed_coach_to_edit;
3288
            }
3289
            if ($check_student_view) {
3290
                $is_allowed = $is_allowed && false === $studentView;
3291
            }
3292
        } else {
3293
            $is_allowed = $is_courseAdmin;
3294
            if ($check_student_view) {
3295
                $is_allowed = $is_courseAdmin && false === $studentView;
3296
            }
3297
        }
3298
3299
        return $is_allowed;
3300
    } else {
3301
        return $is_courseAdmin;
3302
    }
3303
}
3304
3305
/**
3306
 * Returns true if user is a course coach of at least one course in session.
3307
 *
3308
 * @param int $sessionId
3309
 *
3310
 * @return bool
3311
 */
3312
function api_is_coach_of_course_in_session($sessionId)
3313
{
3314
    if (api_is_platform_admin()) {
3315
        return true;
3316
    }
3317
3318
    $userId = api_get_user_id();
3319
    $courseList = UserManager::get_courses_list_by_session(
3320
        $userId,
3321
        $sessionId
3322
    );
3323
3324
    // Session visibility.
3325
    $visibility = api_get_session_visibility(
3326
        $sessionId,
3327
        null,
3328
        false
3329
    );
3330
3331
    if (SESSION_VISIBLE != $visibility && !empty($courseList)) {
3332
        // Course Coach session visibility.
3333
        $blockedCourseCount = 0;
3334
        $closedVisibilityList = [
3335
            COURSE_VISIBILITY_CLOSED,
3336
            COURSE_VISIBILITY_HIDDEN,
3337
        ];
3338
3339
        foreach ($courseList as $course) {
3340
            // Checking session visibility
3341
            $sessionCourseVisibility = api_get_session_visibility(
3342
                $sessionId,
3343
                $course['real_id']
3344
            );
3345
3346
            $courseIsVisible = !in_array(
3347
                $course['visibility'],
3348
                $closedVisibilityList
3349
            );
3350
            if (false === $courseIsVisible || SESSION_INVISIBLE == $sessionCourseVisibility) {
3351
                $blockedCourseCount++;
3352
            }
3353
        }
3354
3355
        // If all courses are blocked then no show in the list.
3356
        if ($blockedCourseCount === count($courseList)) {
3357
            $visibility = SESSION_INVISIBLE;
3358
        } else {
3359
            $visibility = SESSION_VISIBLE;
3360
        }
3361
    }
3362
3363
    switch ($visibility) {
3364
        case SESSION_VISIBLE_READ_ONLY:
3365
        case SESSION_VISIBLE:
3366
        case SESSION_AVAILABLE:
3367
            return true;
3368
            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...
3369
        case SESSION_INVISIBLE:
3370
            return false;
3371
    }
3372
3373
    return false;
3374
}
3375
3376
/**
3377
 * Checks if a student can edit contents in a session depending
3378
 * on the session visibility.
3379
 *
3380
 * @param bool $tutor Whether to check if the user has the tutor role
3381
 * @param bool $coach Whether to check if the user has the coach role
3382
 *
3383
 * @return bool true: the user has the rights to edit, false: he does not
3384
 */
3385
function api_is_allowed_to_session_edit($tutor = false, $coach = false)
3386
{
3387
    if (api_is_allowed_to_edit($tutor, $coach)) {
3388
        // If I'm a teacher, I will return true in order to not affect the normal behaviour of Chamilo tools.
3389
        return true;
3390
    } else {
3391
        $sessionId = api_get_session_id();
3392
3393
        if (0 == $sessionId) {
3394
            // I'm not in a session so i will return true to not affect the normal behaviour of Chamilo tools.
3395
            return true;
3396
        } else {
3397
            // I'm in a session and I'm a student
3398
            // Get the session visibility
3399
            $session_visibility = api_get_session_visibility($sessionId);
3400
            // if 5 the session is still available
3401
            switch ($session_visibility) {
3402
                case SESSION_VISIBLE_READ_ONLY: // 1
3403
                    return false;
3404
                case SESSION_VISIBLE:           // 2
3405
                    return true;
3406
                case SESSION_INVISIBLE:         // 3
3407
                    return false;
3408
                case SESSION_AVAILABLE:         //5
3409
                    return true;
3410
            }
3411
        }
3412
    }
3413
3414
    return false;
3415
}
3416
3417
/**
3418
 * Current user is anon?
3419
 *
3420
 * @return bool true if this user is anonymous, false otherwise
3421
 */
3422
function api_is_anonymous()
3423
{
3424
    return !Container::getAuthorizationChecker()->isGranted('IS_AUTHENTICATED_FULLY');
3425
}
3426
3427
/**
3428
 * Displays message "You are not allowed here..." and exits the entire script.
3429
 *
3430
 * @param bool   $print_headers Whether or not to print headers (default = false -> does not print them)
3431
 * @param string $message
3432
 * @param int    $responseCode
3433
 */
3434
function api_not_allowed(
3435
    $print_headers = false,
3436
    $message = null,
3437
    $responseCode = 0
3438
) {
3439
    throw new Exception('You are not allowed');
3440
}
3441
3442
/**
3443
 * @param string $languageIsoCode
3444
 *
3445
 * @return string
3446
 */
3447
function languageToCountryIsoCode($languageIsoCode)
3448
{
3449
    $allow = api_get_configuration_value('language_flags_by_country');
3450
3451
    // @todo save in DB
3452
    switch ($languageIsoCode) {
3453
        case 'ar':
3454
            $country = 'ae';
3455
            break;
3456
        case 'bs':
3457
            $country = 'ba';
3458
            break;
3459
        case 'ca':
3460
            $country = 'es';
3461
            if ($allow) {
3462
                $country = 'catalan';
3463
            }
3464
            break;
3465
        case 'cs':
3466
            $country = 'cz';
3467
            break;
3468
        case 'da':
3469
            $country = 'dk';
3470
            break;
3471
        case 'el':
3472
            $country = 'ae';
3473
            break;
3474
        case 'en':
3475
            $country = 'gb';
3476
            break;
3477
        case 'eu': // Euskera
3478
            $country = 'es';
3479
            if ($allow) {
3480
                $country = 'basque';
3481
            }
3482
            break;
3483
        case 'gl': // galego
3484
            $country = 'es';
3485
            if ($allow) {
3486
                $country = 'galician';
3487
            }
3488
            break;
3489
        case 'he':
3490
            $country = 'il';
3491
            break;
3492
        case 'ja':
3493
            $country = 'jp';
3494
            break;
3495
        case 'ka':
3496
            $country = 'ge';
3497
            break;
3498
        case 'ko':
3499
            $country = 'kr';
3500
            break;
3501
        case 'ms':
3502
            $country = 'my';
3503
            break;
3504
        case 'pt-BR':
3505
            $country = 'br';
3506
            break;
3507
        case 'qu':
3508
            $country = 'pe';
3509
            break;
3510
        case 'sl':
3511
            $country = 'si';
3512
            break;
3513
        case 'sv':
3514
            $country = 'se';
3515
            break;
3516
        case 'uk': // Ukraine
3517
            $country = 'ua';
3518
            break;
3519
        case 'zh-TW':
3520
        case 'zh':
3521
            $country = 'cn';
3522
            break;
3523
        default:
3524
            $country = $languageIsoCode;
3525
            break;
3526
    }
3527
    $country = strtolower($country);
3528
3529
    return $country;
3530
}
3531
3532
/**
3533
 * Returns a list of all the languages that are made available by the admin.
3534
 *
3535
 * @return array An array with all languages. Structure of the array is
3536
 *               array['name'] = An array with the name of every language
3537
 *               array['folder'] = An array with the corresponding names of the language-folders in the filesystem
3538
 */
3539
function api_get_languages()
3540
{
3541
    $table = Database::get_main_table(TABLE_MAIN_LANGUAGE);
3542
    $sql = "SELECT * FROM $table WHERE available='1'
3543
            ORDER BY original_name ASC";
3544
    $result = Database::query($sql);
3545
    $languages = [];
3546
    while ($row = Database::fetch_array($result, 'ASSOC')) {
3547
        $languages[$row['isocode']] = $row['original_name'];
3548
    }
3549
3550
    return $languages;
3551
}
3552
3553
/**
3554
 * Returns the id (the database id) of a language.
3555
 *
3556
 * @param   string  language name (the corresponding name of the language-folder in the filesystem)
3557
 *
3558
 * @return int id of the language
3559
 */
3560
function api_get_language_id($language)
3561
{
3562
    $tbl_language = Database::get_main_table(TABLE_MAIN_LANGUAGE);
3563
    if (empty($language)) {
3564
        return null;
3565
    }
3566
    $language = Database::escape_string($language);
3567
    $sql = "SELECT id FROM $tbl_language
3568
            WHERE english_name = '$language' LIMIT 1";
3569
    $result = Database::query($sql);
3570
    $row = Database::fetch_array($result);
3571
3572
    return $row['id'];
3573
}
3574
3575
/**
3576
 * Get the language information by its id.
3577
 *
3578
 * @param int $languageId
3579
 *
3580
 * @throws Exception
3581
 *
3582
 * @return array
3583
 */
3584
function api_get_language_info($languageId)
3585
{
3586
    if (empty($languageId)) {
3587
        return [];
3588
    }
3589
3590
    $language = Database::getManager()->find(Language::class, $languageId);
3591
3592
    if (!$language) {
3593
        return [];
3594
    }
3595
3596
    return [
3597
        'id' => $language->getId(),
3598
        'original_name' => $language->getOriginalName(),
3599
        'english_name' => $language->getEnglishName(),
3600
        'isocode' => $language->getIsocode(),
3601
        'available' => $language->getAvailable(),
3602
        'parent_id' => $language->getParent() ? $language->getParent()->getId() : null,
3603
    ];
3604
}
3605
3606
/**
3607
 * @param string $code
3608
 *
3609
 * @return Language
3610
 */
3611
function api_get_language_from_iso($code)
3612
{
3613
    $em = Database::getManager();
3614
3615
    return $em->getRepository(Language::class)->findOneBy(['isocode' => $code]);
3616
}
3617
3618
/**
3619
 * Returns the name of the visual (CSS) theme to be applied on the current page.
3620
 * The returned name depends on the platform, course or user -wide settings.
3621
 *
3622
 * @return string The visual theme's name, it is the name of a folder inside web/css/themes
3623
 */
3624
function api_get_visual_theme()
3625
{
3626
    static $visual_theme;
3627
    if (!isset($visual_theme)) {
3628
        // Get style directly from DB
3629
        /*$styleFromDatabase = api_get_settings_params_simple(
3630
            [
3631
                'variable = ? AND access_url = ?' => [
3632
                    'stylesheets',
3633
                    api_get_current_access_url_id(),
3634
                ],
3635
            ]
3636
        );
3637
3638
        if ($styleFromDatabase) {
3639
            $platform_theme = $styleFromDatabase['selected_value'];
3640
        } else {
3641
            $platform_theme = api_get_setting('stylesheets');
3642
        }*/
3643
        $platform_theme = api_get_setting('stylesheets');
3644
3645
        // Platform's theme.
3646
        $visual_theme = $platform_theme;
3647
        if ('true' == api_get_setting('user_selected_theme')) {
3648
            $user_info = api_get_user_info();
3649
            if (isset($user_info['theme'])) {
3650
                $user_theme = $user_info['theme'];
3651
3652
                if (!empty($user_theme)) {
3653
                    $visual_theme = $user_theme;
3654
                    // User's theme.
3655
                }
3656
            }
3657
        }
3658
3659
        $course_id = api_get_course_id();
3660
        if (!empty($course_id)) {
3661
            if ('true' == api_get_setting('allow_course_theme')) {
3662
                $course_theme = api_get_course_setting('course_theme', $course_id);
3663
3664
                if (!empty($course_theme) && -1 != $course_theme) {
3665
                    if (!empty($course_theme)) {
3666
                        // Course's theme.
3667
                        $visual_theme = $course_theme;
3668
                    }
3669
                }
3670
3671
                $allow_lp_theme = api_get_course_setting('allow_learning_path_theme');
3672
                if (1 == $allow_lp_theme) {
3673
                    /*global $lp_theme_css, $lp_theme_config;
3674
                    // These variables come from the file lp_controller.php.
3675
                    if (!$lp_theme_config) {
3676
                        if (!empty($lp_theme_css)) {
3677
                            // LP's theme.
3678
                            $visual_theme = $lp_theme_css;
3679
                        }
3680
                    }*/
3681
                }
3682
            }
3683
        }
3684
3685
        if (empty($visual_theme)) {
3686
            $visual_theme = 'chamilo';
3687
        }
3688
3689
        /*global $lp_theme_log;
3690
        if ($lp_theme_log) {
3691
            $visual_theme = $platform_theme;
3692
        }*/
3693
    }
3694
3695
    return $visual_theme;
3696
}
3697
3698
/**
3699
 * Returns a list of CSS themes currently available in the CSS folder
3700
 * The folder must have a default.css file.
3701
 *
3702
 * @param bool $getOnlyThemeFromVirtualInstance Used by the vchamilo plugin
3703
 *
3704
 * @return array list of themes directories from the css folder
3705
 *               Note: Directory names (names of themes) in the file system should contain ASCII-characters only
3706
 */
3707
function api_get_themes($getOnlyThemeFromVirtualInstance = false)
3708
{
3709
    // This configuration value is set by the vchamilo plugin
3710
    $virtualTheme = api_get_configuration_value('virtual_css_theme_folder');
3711
3712
    $readCssFolder = function ($dir) use ($virtualTheme) {
3713
        $finder = new Finder();
3714
        $themes = $finder->directories()->in($dir)->depth(0)->sortByName();
3715
        $list = [];
3716
        /** @var Symfony\Component\Finder\SplFileInfo $theme */
3717
        foreach ($themes as $theme) {
3718
            $folder = $theme->getFilename();
3719
            // A theme folder is consider if there's a default.css file
3720
            if (!file_exists($theme->getPathname().'/default.css')) {
3721
                continue;
3722
            }
3723
            $name = ucwords(str_replace('_', ' ', $folder));
3724
            if ($folder == $virtualTheme) {
3725
                continue;
3726
            }
3727
            $list[$folder] = $name;
3728
        }
3729
3730
        return $list;
3731
    };
3732
3733
    $dir = api_get_path(SYS_CSS_PATH).'themes/';
3734
    $list = $readCssFolder($dir);
3735
3736
    if (!empty($virtualTheme)) {
3737
        $newList = $readCssFolder($dir.'/'.$virtualTheme);
3738
        if ($getOnlyThemeFromVirtualInstance) {
3739
            return $newList;
3740
        }
3741
        $list = $list + $newList;
3742
        asort($list);
3743
    }
3744
3745
    return $list;
3746
}
3747
3748
/**
3749
 * Find the largest sort value in a given user_course_category
3750
 * This function is used when we are moving a course to a different category
3751
 * and also when a user subscribes to courses (the new course is added at the end of the main category.
3752
 *
3753
 * @param int $courseCategoryId the id of the user_course_category
3754
 * @param int $userId
3755
 *
3756
 * @return int the value of the highest sort of the user_course_category
3757
 */
3758
function api_max_sort_value($courseCategoryId, $userId)
3759
{
3760
    $user = api_get_user_entity($userId);
3761
    $userCourseCategory = Database::getManager()->getRepository(UserCourseCategory::class)->find($courseCategoryId);
3762
3763
    return null === $user ? 0 : $user->getMaxSortValue($userCourseCategory);
3764
}
3765
3766
/**
3767
 * Transforms a number of seconds in hh:mm:ss format.
3768
 *
3769
 * @author Julian Prud'homme
3770
 *
3771
 * @param int    $seconds      number of seconds
3772
 * @param string $space
3773
 * @param bool   $showSeconds
3774
 * @param bool   $roundMinutes
3775
 *
3776
 * @return string the formatted time
3777
 */
3778
function api_time_to_hms($seconds, $space = ':', $showSeconds = true, $roundMinutes = false)
3779
{
3780
    // $seconds = -1 means that we have wrong data in the db.
3781
    if (-1 == $seconds) {
3782
        return
3783
            get_lang('Unknown').
3784
            Display::return_icon(
3785
                'info2.gif',
3786
                get_lang('The datas about this user were registered when the calculation of time spent on the platform wasn\'t possible.'),
3787
                ['align' => 'absmiddle', 'hspace' => '3px']
3788
            );
3789
    }
3790
3791
    // How many hours ?
3792
    $hours = floor($seconds / 3600);
3793
3794
    // How many minutes ?
3795
    $min = floor(($seconds - ($hours * 3600)) / 60);
3796
3797
    if ($roundMinutes) {
3798
        if ($min >= 45) {
3799
            $min = 45;
3800
        }
3801
3802
        if ($min >= 30 && $min <= 44) {
3803
            $min = 30;
3804
        }
3805
3806
        if ($min >= 15 && $min <= 29) {
3807
            $min = 15;
3808
        }
3809
3810
        if ($min >= 0 && $min <= 14) {
3811
            $min = 0;
3812
        }
3813
    }
3814
3815
    // How many seconds
3816
    $sec = floor($seconds - ($hours * 3600) - ($min * 60));
3817
3818
    if ($hours < 10) {
3819
        $hours = "0$hours";
3820
    }
3821
3822
    if ($sec < 10) {
3823
        $sec = "0$sec";
3824
    }
3825
3826
    if ($min < 10) {
3827
        $min = "0$min";
3828
    }
3829
3830
    $seconds = '';
3831
    if ($showSeconds) {
3832
        $seconds = $space.$sec;
3833
    }
3834
3835
    return $hours.$space.$min.$seconds;
3836
}
3837
3838
/**
3839
 * Returns the permissions to be assigned to every newly created directory by the web-server.
3840
 * The return value is based on the platform administrator's setting
3841
 * "Administration > Configuration settings > Security > Permissions for new directories".
3842
 *
3843
 * @return int returns the permissions in the format "Owner-Group-Others, Read-Write-Execute", as an integer value
3844
 */
3845
function api_get_permissions_for_new_directories()
3846
{
3847
    static $permissions;
3848
    if (!isset($permissions)) {
3849
        $permissions = trim(api_get_setting('permissions_for_new_directories'));
3850
        // The default value 0777 is according to that in the platform administration panel after fresh system installation.
3851
        $permissions = octdec(!empty($permissions) ? $permissions : '0777');
3852
    }
3853
3854
    return $permissions;
3855
}
3856
3857
/**
3858
 * Returns the permissions to be assigned to every newly created directory by the web-server.
3859
 * The return value is based on the platform administrator's setting
3860
 * "Administration > Configuration settings > Security > Permissions for new files".
3861
 *
3862
 * @return int returns the permissions in the format
3863
 *             "Owner-Group-Others, Read-Write-Execute", as an integer value
3864
 */
3865
function api_get_permissions_for_new_files()
3866
{
3867
    static $permissions;
3868
    if (!isset($permissions)) {
3869
        $permissions = trim(api_get_setting('permissions_for_new_files'));
3870
        // The default value 0666 is according to that in the platform
3871
        // administration panel after fresh system installation.
3872
        $permissions = octdec(!empty($permissions) ? $permissions : '0666');
3873
    }
3874
3875
    return $permissions;
3876
}
3877
3878
/**
3879
 * Deletes a file, or a folder and its contents.
3880
 *
3881
 * @author      Aidan Lister <[email protected]>
3882
 *
3883
 * @version     1.0.3
3884
 *
3885
 * @param string $dirname Directory to delete
3886
 * @param       bool     Deletes only the content or not
3887
 * @param bool $strict if one folder/file fails stop the loop
3888
 *
3889
 * @return bool Returns TRUE on success, FALSE on failure
3890
 *
3891
 * @see http://aidanlister.com/2004/04/recursively-deleting-a-folder-in-php/
3892
 *
3893
 * @author      Yannick Warnier, adaptation for the Chamilo LMS, April, 2008
3894
 * @author      Ivan Tcholakov, a sanity check about Directory class creation has been added, September, 2009
3895
 */
3896
function rmdirr($dirname, $delete_only_content_in_folder = false, $strict = false)
3897
{
3898
    $res = true;
3899
    // A sanity check.
3900
    if (!file_exists($dirname)) {
3901
        return false;
3902
    }
3903
    $php_errormsg = '';
3904
    // Simple delete for a file.
3905
    if (is_file($dirname) || is_link($dirname)) {
3906
        $res = unlink($dirname);
3907
        if (false === $res) {
3908
            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);
3909
        }
3910
3911
        return $res;
3912
    }
3913
3914
    // Loop through the folder.
3915
    $dir = dir($dirname);
3916
    // A sanity check.
3917
    $is_object_dir = is_object($dir);
3918
    if ($is_object_dir) {
3919
        while (false !== $entry = $dir->read()) {
3920
            // Skip pointers.
3921
            if ('.' == $entry || '..' == $entry) {
3922
                continue;
3923
            }
3924
3925
            // Recurse.
3926
            if ($strict) {
3927
                $result = rmdirr("$dirname/$entry");
3928
                if (false == $result) {
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...
3929
                    $res = false;
3930
                    break;
3931
                }
3932
            } else {
3933
                rmdirr("$dirname/$entry");
3934
            }
3935
        }
3936
    }
3937
3938
    // Clean up.
3939
    if ($is_object_dir) {
3940
        $dir->close();
3941
    }
3942
3943
    if (false == $delete_only_content_in_folder) {
3944
        $res = rmdir($dirname);
3945
        if (false === $res) {
3946
            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);
3947
        }
3948
    }
3949
3950
    return $res;
3951
}
3952
3953
// TODO: This function is to be simplified. File access modes to be implemented.
3954
/**
3955
 * function adapted from a php.net comment
3956
 * copy recursively a folder.
3957
 *
3958
 * @param the source folder
3959
 * @param the dest folder
3960
 * @param an array of excluded file_name (without extension)
3961
 * @param copied_files the returned array of copied files
3962
 * @param string $source
3963
 * @param string $dest
3964
 */
3965
function copyr($source, $dest, $exclude = [], $copied_files = [])
3966
{
3967
    if (empty($dest)) {
3968
        return false;
3969
    }
3970
    // Simple copy for a file
3971
    if (is_file($source)) {
3972
        $path_info = pathinfo($source);
3973
        if (!in_array($path_info['filename'], $exclude)) {
3974
            copy($source, $dest);
3975
        }
3976
3977
        return true;
3978
    } elseif (!is_dir($source)) {
3979
        //then source is not a dir nor a file, return
3980
        return false;
3981
    }
3982
3983
    // Make destination directory.
3984
    if (!is_dir($dest)) {
3985
        mkdir($dest, api_get_permissions_for_new_directories());
3986
    }
3987
3988
    // Loop through the folder.
3989
    $dir = dir($source);
3990
    while (false !== $entry = $dir->read()) {
3991
        // Skip pointers
3992
        if ('.' == $entry || '..' == $entry) {
3993
            continue;
3994
        }
3995
3996
        // Deep copy directories.
3997
        if ($dest !== "$source/$entry") {
3998
            $files = copyr("$source/$entry", "$dest/$entry", $exclude, $copied_files);
3999
        }
4000
    }
4001
    // Clean up.
4002
    $dir->close();
4003
4004
    return true;
4005
}
4006
4007
/**
4008
 * @todo: Using DIRECTORY_SEPARATOR is not recommended, this is an obsolete approach.
4009
 * Documentation header to be added here.
4010
 *
4011
 * @param string $pathname
4012
 * @param string $base_path_document
4013
 * @param int    $session_id
4014
 *
4015
 * @return mixed True if directory already exists, false if a file already exists at
4016
 *               the destination and null if everything goes according to plan
4017
 */
4018
function copy_folder_course_session(
4019
    $pathname,
4020
    $base_path_document,
4021
    $session_id,
4022
    $course_info,
4023
    $document,
4024
    $source_course_id
4025
) {
4026
    $table = Database::get_course_table(TABLE_DOCUMENT);
4027
    $session_id = intval($session_id);
4028
    $source_course_id = intval($source_course_id);
4029
4030
    // Check whether directory already exists.
4031
    if (is_dir($pathname) || empty($pathname)) {
4032
        return true;
4033
    }
4034
4035
    // Ensure that a file with the same name does not already exist.
4036
    if (is_file($pathname)) {
4037
        trigger_error('copy_folder_course_session(): File exists', E_USER_WARNING);
4038
4039
        return false;
4040
    }
4041
4042
    $course_id = $course_info['real_id'];
4043
    $folders = explode(DIRECTORY_SEPARATOR, str_replace($base_path_document.DIRECTORY_SEPARATOR, '', $pathname));
4044
    $new_pathname = $base_path_document;
4045
    $path = '';
4046
4047
    foreach ($folders as $folder) {
4048
        $new_pathname .= DIRECTORY_SEPARATOR.$folder;
4049
        $path .= DIRECTORY_SEPARATOR.$folder;
4050
4051
        if (!file_exists($new_pathname)) {
4052
            $path = Database::escape_string($path);
4053
4054
            $sql = "SELECT * FROM $table
4055
                    WHERE
4056
                        c_id = $source_course_id AND
4057
                        path = '$path' AND
4058
                        filetype = 'folder' AND
4059
                        session_id = '$session_id'";
4060
            $rs1 = Database::query($sql);
4061
            $num_rows = Database::num_rows($rs1);
4062
4063
            if (0 == $num_rows) {
4064
                mkdir($new_pathname, api_get_permissions_for_new_directories());
4065
4066
                // Insert new folder with destination session_id.
4067
                $params = [
4068
                    'c_id' => $course_id,
4069
                    'path' => $path,
4070
                    'comment' => $document->comment,
4071
                    'title' => basename($new_pathname),
4072
                    'filetype' => 'folder',
4073
                    'size' => '0',
4074
                    'session_id' => $session_id,
4075
                ];
4076
                Database::insert($table, $params);
4077
            }
4078
        }
4079
    } // en foreach
4080
}
4081
4082
// TODO: chmodr() is a better name. Some corrections are needed. Documentation header to be added here.
4083
/**
4084
 * @param string $path
4085
 */
4086
function api_chmod_R($path, $filemode)
4087
{
4088
    if (!is_dir($path)) {
4089
        return chmod($path, $filemode);
4090
    }
4091
4092
    $handler = opendir($path);
4093
    while ($file = readdir($handler)) {
4094
        if ('.' != $file && '..' != $file) {
4095
            $fullpath = "$path/$file";
4096
            if (!is_dir($fullpath)) {
4097
                if (!chmod($fullpath, $filemode)) {
4098
                    return false;
4099
                }
4100
            } else {
4101
                if (!api_chmod_R($fullpath, $filemode)) {
4102
                    return false;
4103
                }
4104
            }
4105
        }
4106
    }
4107
4108
    closedir($handler);
4109
4110
    return chmod($path, $filemode);
4111
}
4112
4113
// TODO: Where the following function has been copy/pased from? There is no information about author and license. Style, coding conventions...
4114
/**
4115
 * Parse info file format. (e.g: file.info).
4116
 *
4117
 * Files should use an ini-like format to specify values.
4118
 * White-space generally doesn't matter, except inside values.
4119
 * e.g.
4120
 *
4121
 * @verbatim
4122
 *   key = value
4123
 *   key = "value"
4124
 *   key = 'value'
4125
 *   key = "multi-line
4126
 *
4127
 *   value"
4128
 *   key = 'multi-line
4129
 *
4130
 *   value'
4131
 *   key
4132
 *   =
4133
 *   'value'
4134
 * @endverbatim
4135
 *
4136
 * Arrays are created using a GET-like syntax:
4137
 *
4138
 * @verbatim
4139
 *   key[] = "numeric array"
4140
 *   key[index] = "associative array"
4141
 *   key[index][] = "nested numeric array"
4142
 *   key[index][index] = "nested associative array"
4143
 * @endverbatim
4144
 *
4145
 * PHP constants are substituted in, but only when used as the entire value:
4146
 *
4147
 * Comments should start with a semi-colon at the beginning of a line.
4148
 *
4149
 * This function is NOT for placing arbitrary module-specific settings. Use
4150
 * variable_get() and variable_set() for that.
4151
 *
4152
 * Information stored in the module.info file:
4153
 * - name: The real name of the module for display purposes.
4154
 * - description: A brief description of the module.
4155
 * - dependencies: An array of shortnames of other modules this module depends on.
4156
 * - package: The name of the package of modules this module belongs to.
4157
 *
4158
 * Example of .info file:
4159
 * <code>
4160
 * @verbatim
4161
 *   name = Forum
4162
 *   description = Enables threaded discussions about general topics.
4163
 *   dependencies[] = taxonomy
4164
 *   dependencies[] = comment
4165
 *   package = Core - optional
4166
 *   version = VERSION
4167
 * @endverbatim
4168
 * </code>
4169
 *
4170
 * @param string $filename
4171
 *                         The file we are parsing. Accepts file with relative or absolute path.
4172
 *
4173
 * @return
4174
 *   The info array
4175
 */
4176
function api_parse_info_file($filename)
4177
{
4178
    $info = [];
4179
4180
    if (!file_exists($filename)) {
4181
        return $info;
4182
    }
4183
4184
    $data = file_get_contents($filename);
4185
    if (preg_match_all('
4186
        @^\s*                           # Start at the beginning of a line, ignoring leading whitespace
4187
        ((?:
4188
          [^=;\[\]]|                    # Key names cannot contain equal signs, semi-colons or square brackets,
4189
          \[[^\[\]]*\]                  # unless they are balanced and not nested
4190
        )+?)
4191
        \s*=\s*                         # Key/value pairs are separated by equal signs (ignoring white-space)
4192
        (?:
4193
          ("(?:[^"]|(?<=\\\\)")*")|     # Double-quoted string, which may contain slash-escaped quotes/slashes
4194
          (\'(?:[^\']|(?<=\\\\)\')*\')| # Single-quoted string, which may contain slash-escaped quotes/slashes
4195
          ([^\r\n]*?)                   # Non-quoted string
4196
        )\s*$                           # Stop at the next end of a line, ignoring trailing whitespace
4197
        @msx', $data, $matches, PREG_SET_ORDER)) {
4198
        $key = $value1 = $value2 = $value3 = '';
4199
        foreach ($matches as $match) {
4200
            // Fetch the key and value string.
4201
            $i = 0;
4202
            foreach (['key', 'value1', 'value2', 'value3'] as $var) {
4203
                $$var = isset($match[++$i]) ? $match[$i] : '';
4204
            }
4205
            $value = stripslashes(substr($value1, 1, -1)).stripslashes(substr($value2, 1, -1)).$value3;
4206
4207
            // Parse array syntax.
4208
            $keys = preg_split('/\]?\[/', rtrim($key, ']'));
4209
            $last = array_pop($keys);
4210
            $parent = &$info;
4211
4212
            // Create nested arrays.
4213
            foreach ($keys as $key) {
4214
                if ('' == $key) {
4215
                    $key = count($parent);
4216
                }
4217
                if (!isset($parent[$key]) || !is_array($parent[$key])) {
4218
                    $parent[$key] = [];
4219
                }
4220
                $parent = &$parent[$key];
4221
            }
4222
4223
            // Handle PHP constants.
4224
            if (defined($value)) {
4225
                $value = constant($value);
4226
            }
4227
4228
            // Insert actual value.
4229
            if ('' == $last) {
4230
                $last = count($parent);
4231
            }
4232
            $parent[$last] = $value;
4233
        }
4234
    }
4235
4236
    return $info;
4237
}
4238
4239
/**
4240
 * Gets Chamilo version from the configuration files.
4241
 *
4242
 * @return string A string of type "1.8.4", or an empty string if the version could not be found
4243
 */
4244
function api_get_version()
4245
{
4246
    return (string) api_get_configuration_value('system_version');
4247
}
4248
4249
/**
4250
 * Gets the software name (the name/brand of the Chamilo-based customized system).
4251
 *
4252
 * @return string
4253
 */
4254
function api_get_software_name()
4255
{
4256
    $name = api_get_configuration_value('software_name');
4257
    if (!empty($name)) {
4258
        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...
4259
    } else {
4260
        return 'Chamilo';
4261
    }
4262
}
4263
4264
function api_get_status_list()
4265
{
4266
    $list = [];
4267
    // Table of status
4268
    $list[COURSEMANAGER] = 'teacher'; // 1
4269
    $list[SESSIONADMIN] = 'session_admin'; // 3
4270
    $list[DRH] = 'drh'; // 4
4271
    $list[STUDENT] = 'user'; // 5
4272
    $list[ANONYMOUS] = 'anonymous'; // 6
4273
    $list[INVITEE] = 'invited'; // 20
4274
4275
    return $list;
4276
}
4277
4278
/**
4279
 * Checks whether status given in parameter exists in the platform.
4280
 *
4281
 * @param mixed the status (can be either int either string)
4282
 *
4283
 * @return bool if the status exists, else returns false
4284
 */
4285
function api_status_exists($status_asked)
4286
{
4287
    $list = api_get_status_list();
4288
4289
    return in_array($status_asked, $list) ? true : isset($list[$status_asked]);
4290
}
4291
4292
/**
4293
 * Checks whether status given in parameter exists in the platform. The function
4294
 * returns the status ID or false if it does not exist, but given the fact there
4295
 * is no "0" status, the return value can be checked against
4296
 * if(api_status_key()) to know if it exists.
4297
 *
4298
 * @param   mixed   The status (can be either int or string)
4299
 *
4300
 * @return mixed Status ID if exists, false otherwise
4301
 */
4302
function api_status_key($status)
4303
{
4304
    $list = api_get_status_list();
4305
4306
    return isset($list[$status]) ? $status : array_search($status, $list);
4307
}
4308
4309
/**
4310
 * Gets the status langvars list.
4311
 *
4312
 * @return string[] the list of status with their translations
4313
 */
4314
function api_get_status_langvars()
4315
{
4316
    return [
4317
        COURSEMANAGER => get_lang('Teacher'),
4318
        SESSIONADMIN => get_lang('SessionsAdmin'),
4319
        DRH => get_lang('Human Resources Manager'),
4320
        STUDENT => get_lang('Learner'),
4321
        ANONYMOUS => get_lang('Anonymous'),
4322
        STUDENT_BOSS => get_lang('RoleStudentBoss'),
4323
        INVITEE => get_lang('Invited'),
4324
    ];
4325
}
4326
4327
/**
4328
 * The function that retrieves all the possible settings for a certain config setting.
4329
 *
4330
 * @author Patrick Cool <[email protected]>, Ghent University
4331
 */
4332
function api_get_settings_options($var)
4333
{
4334
    $table_settings_options = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
4335
    $var = Database::escape_string($var);
4336
    $sql = "SELECT * FROM $table_settings_options
4337
            WHERE variable = '$var'
4338
            ORDER BY id";
4339
    $result = Database::query($sql);
4340
    $settings_options_array = [];
4341
    while ($row = Database::fetch_array($result, 'ASSOC')) {
4342
        $settings_options_array[] = $row;
4343
    }
4344
4345
    return $settings_options_array;
4346
}
4347
4348
/**
4349
 * @param array $params
4350
 */
4351
function api_set_setting_option($params)
4352
{
4353
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
4354
    if (empty($params['id'])) {
4355
        Database::insert($table, $params);
4356
    } else {
4357
        Database::update($table, $params, ['id = ? ' => $params['id']]);
4358
    }
4359
}
4360
4361
/**
4362
 * @param array $params
4363
 */
4364
function api_set_setting_simple($params)
4365
{
4366
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
4367
    $url_id = api_get_current_access_url_id();
4368
4369
    if (empty($params['id'])) {
4370
        $params['access_url'] = $url_id;
4371
        Database::insert($table, $params);
4372
    } else {
4373
        Database::update($table, $params, ['id = ? ' => [$params['id']]]);
4374
    }
4375
}
4376
4377
/**
4378
 * @param int $id
4379
 */
4380
function api_delete_setting_option($id)
4381
{
4382
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
4383
    if (!empty($id)) {
4384
        Database::delete($table, ['id = ? ' => $id]);
4385
    }
4386
}
4387
4388
/**
4389
 * Sets a platform configuration setting to a given value.
4390
 *
4391
 * @param string    The variable we want to update
4392
 * @param string    The value we want to record
4393
 * @param string    The sub-variable if any (in most cases, this will remain null)
4394
 * @param string    The category if any (in most cases, this will remain null)
4395
 * @param int       The access_url for which this parameter is valid
4396
 * @param string $cat
4397
 *
4398
 * @return bool|null
4399
 */
4400
function api_set_setting($var, $value, $subvar = null, $cat = null, $access_url = 1)
4401
{
4402
    if (empty($var)) {
4403
        return false;
4404
    }
4405
    $t_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
4406
    $var = Database::escape_string($var);
4407
    $value = Database::escape_string($value);
4408
    $access_url = (int) $access_url;
4409
    if (empty($access_url)) {
4410
        $access_url = 1;
4411
    }
4412
    $select = "SELECT id FROM $t_settings WHERE variable = '$var' ";
4413
    if (!empty($subvar)) {
4414
        $subvar = Database::escape_string($subvar);
4415
        $select .= " AND subkey = '$subvar'";
4416
    }
4417
    if (!empty($cat)) {
4418
        $cat = Database::escape_string($cat);
4419
        $select .= " AND category = '$cat'";
4420
    }
4421
    if ($access_url > 1) {
4422
        $select .= " AND access_url = $access_url";
4423
    } else {
4424
        $select .= " AND access_url = 1 ";
4425
    }
4426
4427
    $res = Database::query($select);
4428
    if (Database::num_rows($res) > 0) {
4429
        // Found item for this access_url.
4430
        $row = Database::fetch_array($res);
4431
        $sql = "UPDATE $t_settings SET selected_value = '$value'
4432
                WHERE id = ".$row['id'];
4433
        Database::query($sql);
4434
    } else {
4435
        // Item not found for this access_url, we have to check if it exist with access_url = 1
4436
        $select = "SELECT * FROM $t_settings
4437
                   WHERE variable = '$var' AND access_url = 1 ";
4438
        // Just in case
4439
        if (1 == $access_url) {
4440
            if (!empty($subvar)) {
4441
                $select .= " AND subkey = '$subvar'";
4442
            }
4443
            if (!empty($cat)) {
4444
                $select .= " AND category = '$cat'";
4445
            }
4446
            $res = Database::query($select);
4447
            if (Database::num_rows($res) > 0) {
4448
                // We have a setting for access_url 1, but none for the current one, so create one.
4449
                $row = Database::fetch_array($res);
4450
                $insert = "INSERT INTO $t_settings (variable, subkey, type,category, selected_value, title, comment, scope, subkeytext, access_url)
4451
                        VALUES
4452
                        ('".$row['variable']."',".(!empty($row['subkey']) ? "'".$row['subkey']."'" : "NULL").",".
4453
                    "'".$row['type']."','".$row['category']."',".
4454
                    "'$value','".$row['title']."',".
4455
                    "".(!empty($row['comment']) ? "'".$row['comment']."'" : "NULL").",".(!empty($row['scope']) ? "'".$row['scope']."'" : "NULL").",".
4456
                    "".(!empty($row['subkeytext']) ? "'".$row['subkeytext']."'" : "NULL").",$access_url)";
4457
                Database::query($insert);
4458
            } else {
4459
                // Such a setting does not exist.
4460
                //error_log(__FILE__.':'.__LINE__.': Attempting to update setting '.$var.' ('.$subvar.') which does not exist at all', 0);
4461
            }
4462
        } else {
4463
            // Other access url.
4464
            if (!empty($subvar)) {
4465
                $select .= " AND subkey = '$subvar'";
4466
            }
4467
            if (!empty($cat)) {
4468
                $select .= " AND category = '$cat'";
4469
            }
4470
            $res = Database::query($select);
4471
4472
            if (Database::num_rows($res) > 0) {
4473
                // We have a setting for access_url 1, but none for the current one, so create one.
4474
                $row = Database::fetch_array($res);
4475
                if (1 == $row['access_url_changeable']) {
4476
                    $insert = "INSERT INTO $t_settings (variable,subkey, type,category, selected_value,title, comment,scope, subkeytext,access_url, access_url_changeable) VALUES
4477
                            ('".$row['variable']."',".
4478
                        (!empty($row['subkey']) ? "'".$row['subkey']."'" : "NULL").",".
4479
                        "'".$row['type']."','".$row['category']."',".
4480
                        "'$value','".$row['title']."',".
4481
                        "".(!empty($row['comment']) ? "'".$row['comment']."'" : "NULL").",".
4482
                        (!empty($row['scope']) ? "'".$row['scope']."'" : "NULL").",".
4483
                        "".(!empty($row['subkeytext']) ? "'".$row['subkeytext']."'" : "NULL").",$access_url,".$row['access_url_changeable'].")";
4484
                    Database::query($insert);
4485
                }
4486
            } else { // Such a setting does not exist.
4487
                //error_log(__FILE__.':'.__LINE__.': Attempting to update setting '.$var.' ('.$subvar.') which does not exist at all. The access_url is: '.$access_url.' ',0);
4488
            }
4489
        }
4490
    }
4491
}
4492
4493
/**
4494
 * Sets a whole category of settings to one specific value.
4495
 *
4496
 * @param string    Category
4497
 * @param string    Value
4498
 * @param int       Access URL. Optional. Defaults to 1
4499
 * @param array     Optional array of filters on field type
4500
 * @param string $category
4501
 * @param string $value
4502
 *
4503
 * @return bool
4504
 */
4505
function api_set_settings_category($category, $value = null, $access_url = 1, $fieldtype = [])
4506
{
4507
    if (empty($category)) {
4508
        return false;
4509
    }
4510
    $category = Database::escape_string($category);
4511
    $t_s = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
4512
    $access_url = (int) $access_url;
4513
    if (empty($access_url)) {
4514
        $access_url = 1;
4515
    }
4516
    if (isset($value)) {
4517
        $value = Database::escape_string($value);
4518
        $sql = "UPDATE $t_s SET selected_value = '$value'
4519
                WHERE category = '$category' AND access_url = $access_url";
4520
        if (is_array($fieldtype) && count($fieldtype) > 0) {
4521
            $sql .= " AND ( ";
4522
            $i = 0;
4523
            foreach ($fieldtype as $type) {
4524
                if ($i > 0) {
4525
                    $sql .= ' OR ';
4526
                }
4527
                $type = Database::escape_string($type);
4528
                $sql .= " type='".$type."' ";
4529
                $i++;
4530
            }
4531
            $sql .= ")";
4532
        }
4533
        $res = Database::query($sql);
4534
4535
        return false !== $res;
4536
    } else {
4537
        $sql = "UPDATE $t_s SET selected_value = NULL
4538
                WHERE category = '$category' AND access_url = $access_url";
4539
        if (is_array($fieldtype) && count($fieldtype) > 0) {
4540
            $sql .= " AND ( ";
4541
            $i = 0;
4542
            foreach ($fieldtype as $type) {
4543
                if ($i > 0) {
4544
                    $sql .= ' OR ';
4545
                }
4546
                $type = Database::escape_string($type);
4547
                $sql .= " type='".$type."' ";
4548
                $i++;
4549
            }
4550
            $sql .= ")";
4551
        }
4552
        $res = Database::query($sql);
4553
4554
        return false !== $res;
4555
    }
4556
}
4557
4558
/**
4559
 * Gets all available access urls in an array (as in the database).
4560
 *
4561
 * @return array An array of database records
4562
 */
4563
function api_get_access_urls($from = 0, $to = 1000000, $order = 'url', $direction = 'ASC')
4564
{
4565
    $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
4566
    $from = (int) $from;
4567
    $to = (int) $to;
4568
    $order = Database::escape_string($order);
4569
    $direction = Database::escape_string($direction);
4570
    $direction = !in_array(strtolower(trim($direction)), ['asc', 'desc']) ? 'asc' : $direction;
4571
    $sql = "SELECT id, url, description, active, created_by, tms
4572
            FROM $table
4573
            ORDER BY `$order` $direction
4574
            LIMIT $to OFFSET $from";
4575
    $res = Database::query($sql);
4576
4577
    return Database::store_result($res);
4578
}
4579
4580
/**
4581
 * Gets the access url info in an array.
4582
 *
4583
 * @param int  $id            Id of the access url
4584
 * @param bool $returnDefault Set to false if you want the real URL if URL 1 is still 'http://localhost/'
4585
 *
4586
 * @return array All the info (url, description, active, created_by, tms)
4587
 *               from the access_url table
4588
 *
4589
 * @author Julio Montoya
4590
 */
4591
function api_get_access_url($id, $returnDefault = true)
4592
{
4593
    static $staticResult;
4594
    $id = (int) $id;
4595
4596
    if (isset($staticResult[$id])) {
4597
        $result = $staticResult[$id];
4598
    } else {
4599
        // Calling the Database:: library dont work this is handmade.
4600
        $table_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
4601
        $sql = "SELECT url, description, active, created_by, tms
4602
                FROM $table_access_url WHERE id = '$id' ";
4603
        $res = Database::query($sql);
4604
        $result = @Database::fetch_array($res);
4605
        $staticResult[$id] = $result;
4606
    }
4607
4608
    // If the result url is 'http://localhost/' (the default) and the root_web
4609
    // (=current url) is different, and the $id is = 1 (which might mean
4610
    // api_get_current_access_url_id() returned 1 by default), then return the
4611
    // root_web setting instead of the current URL
4612
    // This is provided as an option to avoid breaking the storage of URL-specific
4613
    // homepages in home/localhost/
4614
    if (1 === $id && false === $returnDefault) {
4615
        $currentUrl = api_get_current_access_url_id();
4616
        // only do this if we are on the main URL (=1), otherwise we could get
4617
        // information on another URL instead of the one asked as parameter
4618
        if (1 === $currentUrl) {
4619
            $rootWeb = api_get_path(WEB_PATH);
4620
            $default = AccessUrl::DEFAULT_ACCESS_URL;
4621
            if ($result['url'] === $default && $rootWeb != $default) {
4622
                $result['url'] = $rootWeb;
4623
            }
4624
        }
4625
    }
4626
4627
    return $result;
4628
}
4629
4630
/**
4631
 * Gets all the current settings for a specific access url.
4632
 *
4633
 * @param string    The category, if any, that we want to get
4634
 * @param string    Whether we want a simple list (display a category) or
4635
 * a grouped list (group by variable as in settings.php default). Values: 'list' or 'group'
4636
 * @param int       Access URL's ID. Optional. Uses 1 by default, which is the unique URL
4637
 *
4638
 * @return array Array of database results for the current settings of the current access URL
4639
 */
4640
function &api_get_settings($cat = null, $ordering = 'list', $access_url = 1, $url_changeable = 0)
4641
{
4642
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
4643
    $access_url = (int) $access_url;
4644
    $where_condition = '';
4645
    if (1 == $url_changeable) {
4646
        $where_condition = " AND access_url_changeable= '1' ";
4647
    }
4648
    if (empty($access_url) || -1 == $access_url) {
4649
        $access_url = 1;
4650
    }
4651
    $sql = "SELECT * FROM $table
4652
            WHERE access_url = $access_url  $where_condition ";
4653
4654
    if (!empty($cat)) {
4655
        $cat = Database::escape_string($cat);
4656
        $sql .= " AND category='$cat' ";
4657
    }
4658
    if ('group' == $ordering) {
4659
        $sql .= " ORDER BY id ASC";
4660
    } else {
4661
        $sql .= " ORDER BY 1,2 ASC";
4662
    }
4663
    $result = Database::query($sql);
4664
    if (null === $result) {
4665
        return [];
4666
    }
4667
    $result = Database::store_result($result, 'ASSOC');
4668
4669
    return $result;
4670
}
4671
4672
/**
4673
 * @param string $value       The value we want to record
4674
 * @param string $variable    The variable name we want to insert
4675
 * @param string $subKey      The subkey for the variable we want to insert
4676
 * @param string $type        The type for the variable we want to insert
4677
 * @param string $category    The category for the variable we want to insert
4678
 * @param string $title       The title
4679
 * @param string $comment     The comment
4680
 * @param string $scope       The scope
4681
 * @param string $subKeyText  The subkey text
4682
 * @param int    $accessUrlId The access_url for which this parameter is valid
4683
 * @param int    $visibility  The changeability of this setting for non-master urls
4684
 *
4685
 * @return int The setting ID
4686
 */
4687
function api_add_setting(
4688
    $value,
4689
    $variable,
4690
    $subKey = '',
4691
    $type = 'textfield',
4692
    $category = '',
4693
    $title = '',
4694
    $comment = '',
4695
    $scope = '',
4696
    $subKeyText = '',
4697
    $accessUrlId = 1,
4698
    $visibility = 0
4699
) {
4700
    $em = Database::getManager();
4701
4702
    $settingRepo = $em->getRepository(SettingsCurrent::class);
4703
    $accessUrlId = (int) $accessUrlId ?: 1;
4704
4705
    if (is_array($value)) {
4706
        $value = serialize($value);
4707
    } else {
4708
        $value = trim($value);
4709
    }
4710
4711
    $criteria = ['variable' => $variable, 'url' => $accessUrlId];
4712
4713
    if (!empty($subKey)) {
4714
        $criteria['subkey'] = $subKey;
4715
    }
4716
4717
    // Check if this variable doesn't exist already
4718
    /** @var SettingsCurrent $setting */
4719
    $setting = $settingRepo->findOneBy($criteria);
4720
4721
    if ($setting) {
0 ignored issues
show
introduced by
$setting is of type Chamilo\CoreBundle\Entity\SettingsCurrent, thus it always evaluated to true.
Loading history...
4722
        $setting->setSelectedValue($value);
4723
4724
        $em->persist($setting);
4725
        $em->flush();
4726
4727
        return $setting->getId();
4728
    }
4729
4730
    // Item not found for this access_url, we have to check if the whole thing is missing
4731
    // (in which case we ignore the insert) or if there *is* a record but just for access_url = 1
4732
    $setting = new SettingsCurrent();
4733
    $url = api_get_url_entity();
4734
4735
    $setting
4736
        ->setVariable($variable)
4737
        ->setSelectedValue($value)
4738
        ->setType($type)
4739
        ->setCategory($category)
4740
        ->setSubkey($subKey)
4741
        ->setTitle($title)
4742
        ->setComment($comment)
4743
        ->setScope($scope)
4744
        ->setSubkeytext($subKeyText)
4745
        ->setUrl(api_get_url_entity())
4746
        ->setAccessUrlChangeable($visibility);
4747
4748
    $em->persist($setting);
4749
    $em->flush();
4750
4751
    return $setting->getId();
4752
}
4753
4754
/**
4755
 * Checks wether a user can or can't view the contents of a course.
4756
 *
4757
 * @deprecated use CourseManager::is_user_subscribed_in_course
4758
 *
4759
 * @param int $userid User id or NULL to get it from $_SESSION
4760
 * @param int $cid    course id to check whether the user is allowed
4761
 *
4762
 * @return bool
4763
 */
4764
function api_is_course_visible_for_user($userid = null, $cid = null)
4765
{
4766
    if (null === $userid) {
4767
        $userid = api_get_user_id();
4768
    }
4769
    if (empty($userid) || strval(intval($userid)) != $userid) {
4770
        if (api_is_anonymous()) {
4771
            $userid = api_get_anonymous_id();
4772
        } else {
4773
            return false;
4774
        }
4775
    }
4776
    $cid = Database::escape_string($cid);
4777
4778
    $courseInfo = api_get_course_info($cid);
4779
    $courseId = $courseInfo['real_id'];
4780
    $is_platformAdmin = api_is_platform_admin();
4781
4782
    $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
4783
    $course_cat_table = Database::get_main_table(TABLE_MAIN_CATEGORY);
4784
4785
    $sql = "SELECT
4786
                $course_cat_table.code AS category_code,
4787
                $course_table.visibility,
4788
                $course_table.code,
4789
                $course_cat_table.code
4790
            FROM $course_table
4791
            LEFT JOIN $course_cat_table
4792
                ON $course_table.category_id = $course_cat_table.id
4793
            WHERE
4794
                $course_table.code = '$cid'
4795
            LIMIT 1";
4796
4797
    $result = Database::query($sql);
4798
4799
    if (Database::num_rows($result) > 0) {
4800
        $visibility = Database::fetch_array($result);
4801
        $visibility = $visibility['visibility'];
4802
    } else {
4803
        $visibility = 0;
4804
    }
4805
    // Shortcut permissions in case the visibility is "open to the world".
4806
    if (COURSE_VISIBILITY_OPEN_WORLD === $visibility) {
4807
        return true;
4808
    }
4809
4810
    $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4811
4812
    $sql = "SELECT
4813
                is_tutor, status
4814
            FROM $tbl_course_user
4815
            WHERE
4816
                user_id  = '$userid' AND
4817
                relation_type <> '".COURSE_RELATION_TYPE_RRHH."' AND
4818
                c_id = $courseId
4819
            LIMIT 1";
4820
4821
    $result = Database::query($sql);
4822
4823
    if (Database::num_rows($result) > 0) {
4824
        // This user has got a recorded state for this course.
4825
        $cuData = Database::fetch_array($result);
4826
        $is_courseMember = true;
4827
        $is_courseAdmin = (1 == $cuData['status']);
4828
    }
4829
4830
    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...
4831
        // This user has no status related to this course.
4832
        // Is it the session coach or the session admin?
4833
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
4834
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
4835
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4836
4837
        $sql = "SELECT
4838
                    session.id_coach, session_admin_id, session.id
4839
                FROM
4840
                    $tbl_session as session
4841
                INNER JOIN $tbl_session_course
4842
                    ON session_rel_course.session_id = session.id
4843
                    AND session_rel_course.c_id = '$courseId'
4844
                LIMIT 1";
4845
4846
        $result = Database::query($sql);
4847
        $row = Database::store_result($result);
4848
4849
        if ($row[0]['id_coach'] == $userid) {
4850
            $is_courseMember = true;
4851
            $is_courseAdmin = false;
4852
        } elseif ($row[0]['session_admin_id'] == $userid) {
4853
            $is_courseMember = false;
4854
            $is_courseAdmin = false;
4855
        } else {
4856
            // Check if the current user is the course coach.
4857
            $sql = "SELECT 1
4858
                    FROM $tbl_session_course
4859
                    WHERE session_rel_course.c_id = '$courseId'
4860
                    AND session_rel_course.id_coach = '$userid'
4861
                    LIMIT 1";
4862
4863
            $result = Database::query($sql);
4864
4865
            //if ($row = Database::fetch_array($result)) {
4866
            if (Database::num_rows($result) > 0) {
4867
                $is_courseMember = true;
4868
                $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
4869
4870
                $sql = "SELECT status FROM $tbl_user
4871
                        WHERE id = $userid
4872
                        LIMIT 1";
4873
4874
                $result = Database::query($sql);
4875
4876
                if (1 == Database::result($result, 0, 0)) {
4877
                    $is_courseAdmin = true;
4878
                } else {
4879
                    $is_courseAdmin = false;
4880
                }
4881
            } else {
4882
                // Check if the user is a student is this session.
4883
                $sql = "SELECT  id
4884
                        FROM $tbl_session_course_user
4885
                        WHERE
4886
                            user_id  = '$userid' AND
4887
                            c_id = '$courseId'
4888
                        LIMIT 1";
4889
4890
                if (Database::num_rows($result) > 0) {
4891
                    // This user haa got a recorded state for this course.
4892
                    while ($row = Database::fetch_array($result)) {
4893
                        $is_courseMember = true;
4894
                        $is_courseAdmin = false;
4895
                    }
4896
                }
4897
            }
4898
        }
4899
    }
4900
4901
    switch ($visibility) {
4902
        case Course::OPEN_WORLD:
4903
            return true;
4904
        case Course::OPEN_PLATFORM:
4905
            return isset($userid);
4906
        case Course::REGISTERED:
4907
        case Course::CLOSED:
4908
            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...
4909
        case Course::HIDDEN:
4910
            return $is_platformAdmin;
4911
    }
4912
4913
    return false;
4914
}
4915
4916
/**
4917
 * Returns whether an element (forum, message, survey ...) belongs to a session or not.
4918
 *
4919
 * @param string the tool of the element
4920
 * @param int the element id in database
4921
 * @param int the session_id to compare with element session id
4922
 *
4923
 * @return bool true if the element is in the session, false else
4924
 */
4925
function api_is_element_in_the_session($tool, $element_id, $session_id = null)
4926
{
4927
    if (is_null($session_id)) {
4928
        $session_id = api_get_session_id();
4929
    }
4930
4931
    $element_id = (int) $element_id;
4932
4933
    if (empty($element_id)) {
4934
        return false;
4935
    }
4936
4937
    // Get information to build query depending of the tool.
4938
    switch ($tool) {
4939
        case TOOL_SURVEY:
4940
            $table_tool = Database::get_course_table(TABLE_SURVEY);
4941
            $key_field = 'survey_id';
4942
            break;
4943
        case TOOL_ANNOUNCEMENT:
4944
            $table_tool = Database::get_course_table(TABLE_ANNOUNCEMENT);
4945
            $key_field = 'id';
4946
            break;
4947
        case TOOL_AGENDA:
4948
            $table_tool = Database::get_course_table(TABLE_AGENDA);
4949
            $key_field = 'id';
4950
            break;
4951
        case TOOL_GROUP:
4952
            $table_tool = Database::get_course_table(TABLE_GROUP);
4953
            $key_field = 'id';
4954
            break;
4955
        default:
4956
            return false;
4957
    }
4958
    $course_id = api_get_course_int_id();
4959
4960
    $sql = "SELECT session_id FROM $table_tool
4961
            WHERE c_id = $course_id AND $key_field =  ".$element_id;
4962
    $rs = Database::query($sql);
4963
    if ($element_session_id = Database::result($rs, 0, 0)) {
4964
        if ($element_session_id == intval($session_id)) {
4965
            // The element belongs to the session.
4966
            return true;
4967
        }
4968
    }
4969
4970
    return false;
4971
}
4972
4973
/**
4974
 * Replaces "forbidden" characters in a filename string.
4975
 *
4976
 * @param string $filename
4977
 * @param bool   $treat_spaces_as_hyphens
4978
 *
4979
 * @return string
4980
 */
4981
function api_replace_dangerous_char($filename, $treat_spaces_as_hyphens = true)
4982
{
4983
    // Some non-properly encoded file names can cause the whole file to be
4984
    // skipped when uploaded. Avoid this by detecting the encoding and
4985
    // converting to UTF-8, setting the source as ASCII (a reasonably
4986
    // limited characters set) if nothing could be found (BT#
4987
    $encoding = api_detect_encoding($filename);
4988
    if (empty($encoding)) {
4989
        $encoding = 'ASCII';
4990
        if (!api_is_valid_ascii($filename)) {
4991
            // try iconv and try non standard ASCII a.k.a CP437
4992
            // see BT#15022
4993
            if (function_exists('iconv')) {
4994
                $result = iconv('CP437', 'UTF-8', $filename);
4995
                if (api_is_valid_utf8($result)) {
4996
                    $filename = $result;
4997
                    $encoding = 'UTF-8';
4998
                }
4999
            }
5000
        }
5001
    }
5002
5003
    $filename = api_to_system_encoding($filename, $encoding);
5004
5005
    $url = URLify::filter(
5006
        $filename,
5007
        250,
5008
        '',
5009
        true,
5010
        false,
5011
        false,
5012
        false,
5013
        $treat_spaces_as_hyphens
5014
    );
5015
5016
    // Replace multiple dots at the end.
5017
    $regex = "/\.+$/";
5018
5019
    return preg_replace($regex, '', $url);
5020
}
5021
5022
/**
5023
 * Fixes the $_SERVER['REQUEST_URI'] that is empty in IIS6.
5024
 *
5025
 * @author Ivan Tcholakov, 28-JUN-2006.
5026
 */
5027
function api_request_uri()
5028
{
5029
    if (!empty($_SERVER['REQUEST_URI'])) {
5030
        return $_SERVER['REQUEST_URI'];
5031
    }
5032
    $uri = $_SERVER['SCRIPT_NAME'];
5033
    if (!empty($_SERVER['QUERY_STRING'])) {
5034
        $uri .= '?'.$_SERVER['QUERY_STRING'];
5035
    }
5036
    $_SERVER['REQUEST_URI'] = $uri;
5037
5038
    return $uri;
5039
}
5040
5041
/** Gets the current access_url id of the Chamilo Platform.
5042
 * @author Julio Montoya <[email protected]>
5043
 *
5044
 * @return int access_url_id of the current Chamilo Installation
5045
 */
5046
function api_get_current_access_url_id()
5047
{
5048
    if (false === api_get_multiple_access_url()) {
5049
        return 1;
5050
    }
5051
5052
    static $id;
5053
    if (!empty($id)) {
5054
        return $id;
5055
    }
5056
5057
    $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5058
    $path = Database::escape_string(api_get_path(WEB_PATH));
5059
    $sql = "SELECT id FROM $table WHERE url = '".$path."'";
5060
    $result = Database::query($sql);
5061
    if (Database::num_rows($result) > 0) {
5062
        $id = Database::result($result, 0, 0);
5063
        if (false === $id) {
5064
            return -1;
5065
        }
5066
5067
        return (int) $id;
5068
    }
5069
5070
    $id = 1;
5071
5072
    //if the url in WEB_PATH was not found, it can only mean that there is
5073
    // either a configuration problem or the first URL has not been defined yet
5074
    // (by default it is http://localhost/). Thus the more sensible thing we can
5075
    // do is return 1 (the main URL) as the user cannot hack this value anyway
5076
    return 1;
5077
}
5078
5079
/**
5080
 * Gets the registered urls from a given user id.
5081
 *
5082
 * @author Julio Montoya <[email protected]>
5083
 *
5084
 * @param int $user_id
5085
 *
5086
 * @return array
5087
 */
5088
function api_get_access_url_from_user($user_id)
5089
{
5090
    $user_id = (int) $user_id;
5091
    $table_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
5092
    $table_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5093
    $sql = "SELECT access_url_id
5094
            FROM $table_url_rel_user url_rel_user
5095
            INNER JOIN $table_url u
5096
            ON (url_rel_user.access_url_id = u.id)
5097
            WHERE user_id = ".$user_id;
5098
    $result = Database::query($sql);
5099
    $list = [];
5100
    while ($row = Database::fetch_array($result, 'ASSOC')) {
5101
        $list[] = $row['access_url_id'];
5102
    }
5103
5104
    return $list;
5105
}
5106
5107
/**
5108
 * Checks whether the curent user is in a group or not.
5109
 *
5110
 * @param string        The group id - optional (takes it from session if not given)
5111
 * @param string        The course code - optional (no additional check by course if course code is not given)
5112
 *
5113
 * @return bool
5114
 *
5115
 * @author Ivan Tcholakov
5116
 */
5117
function api_is_in_group($groupIdParam = null, $courseCodeParam = null)
5118
{
5119
    if (!empty($courseCodeParam)) {
5120
        $courseCode = api_get_course_id();
5121
        if (!empty($courseCode)) {
5122
            if ($courseCodeParam != $courseCode) {
5123
                return false;
5124
            }
5125
        } else {
5126
            return false;
5127
        }
5128
    }
5129
5130
    $groupId = api_get_group_id();
5131
5132
    if (isset($groupId) && '' != $groupId) {
5133
        if (!empty($groupIdParam)) {
5134
            return $groupIdParam == $groupId;
5135
        } else {
5136
            return true;
5137
        }
5138
    }
5139
5140
    return false;
5141
}
5142
5143
/**
5144
 * Checks whether a secret key is valid.
5145
 *
5146
 * @param string $original_key_secret - secret key from (webservice) client
5147
 * @param string $security_key        - security key from Chamilo
5148
 *
5149
 * @return bool - true if secret key is valid, false otherwise
5150
 */
5151
function api_is_valid_secret_key($original_key_secret, $security_key)
5152
{
5153
    if (empty($original_key_secret) || empty($security_key)) {
5154
        return false;
5155
    }
5156
5157
    return (string) $original_key_secret === sha1($security_key);
5158
}
5159
5160
/**
5161
 * Checks whether the server's operating system is Windows (TM).
5162
 *
5163
 * @return bool - true if the operating system is Windows, false otherwise
5164
 */
5165
function api_is_windows_os()
5166
{
5167
    if (function_exists('php_uname')) {
5168
        // php_uname() exists as of PHP 4.0.2, according to the documentation.
5169
        // We expect that this function will always work for Chamilo 1.8.x.
5170
        $os = php_uname();
5171
    }
5172
    // The following methods are not needed, but let them stay, just in case.
5173
    elseif (isset($_ENV['OS'])) {
5174
        // Sometimes $_ENV['OS'] may not be present (bugs?)
5175
        $os = $_ENV['OS'];
5176
    } elseif (defined('PHP_OS')) {
5177
        // PHP_OS means on which OS PHP was compiled, this is why
5178
        // using PHP_OS is the last choice for detection.
5179
        $os = PHP_OS;
5180
    } else {
5181
        return false;
5182
    }
5183
5184
    return 'win' == strtolower(substr((string) $os, 0, 3));
5185
}
5186
5187
/**
5188
 * This function informs whether the sent request is XMLHttpRequest.
5189
 */
5190
function api_is_xml_http_request()
5191
{
5192
    return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && 'xmlhttprequest' == strtolower($_SERVER['HTTP_X_REQUESTED_WITH']);
5193
}
5194
5195
/**
5196
 * Returns a list of Chamilo's tools or
5197
 * checks whether a given identificator is a valid Chamilo's tool.
5198
 *
5199
 * @author Isaac flores paz
5200
 *
5201
 * @param string The tool name to filter
5202
 *
5203
 * @return mixed Filtered string or array
5204
 */
5205
function api_get_tools_lists($my_tool = null)
5206
{
5207
    $tools_list = [
5208
        TOOL_DOCUMENT,
5209
        TOOL_THUMBNAIL,
5210
        TOOL_HOTPOTATOES,
5211
        TOOL_CALENDAR_EVENT,
5212
        TOOL_LINK,
5213
        TOOL_COURSE_DESCRIPTION,
5214
        TOOL_SEARCH,
5215
        TOOL_LEARNPATH,
5216
        TOOL_ANNOUNCEMENT,
5217
        TOOL_FORUM,
5218
        TOOL_THREAD,
5219
        TOOL_POST,
5220
        TOOL_DROPBOX,
5221
        TOOL_QUIZ,
5222
        TOOL_USER,
5223
        TOOL_GROUP,
5224
        TOOL_BLOGS,
5225
        TOOL_CHAT,
5226
        TOOL_STUDENTPUBLICATION,
5227
        TOOL_TRACKING,
5228
        TOOL_HOMEPAGE_LINK,
5229
        TOOL_COURSE_SETTING,
5230
        TOOL_BACKUP,
5231
        TOOL_COPY_COURSE_CONTENT,
5232
        TOOL_RECYCLE_COURSE,
5233
        TOOL_COURSE_HOMEPAGE,
5234
        TOOL_COURSE_RIGHTS_OVERVIEW,
5235
        TOOL_UPLOAD,
5236
        TOOL_COURSE_MAINTENANCE,
5237
        TOOL_SURVEY,
5238
        //TOOL_WIKI,
5239
        TOOL_GLOSSARY,
5240
        TOOL_GRADEBOOK,
5241
        TOOL_NOTEBOOK,
5242
        TOOL_ATTENDANCE,
5243
        TOOL_COURSE_PROGRESS,
5244
    ];
5245
    if (empty($my_tool)) {
5246
        return $tools_list;
5247
    }
5248
5249
    return in_array($my_tool, $tools_list) ? $my_tool : '';
5250
}
5251
5252
/**
5253
 * Checks whether we already approved the last version term and condition.
5254
 *
5255
 * @param int user id
5256
 *
5257
 * @return bool true if we pass false otherwise
5258
 */
5259
function api_check_term_condition($userId)
5260
{
5261
    if ('true' === api_get_setting('allow_terms_conditions')) {
5262
        // Check if exists terms and conditions
5263
        if (0 == LegalManager::count()) {
5264
            return true;
5265
        }
5266
5267
        $extraFieldValue = new ExtraFieldValue('user');
5268
        $data = $extraFieldValue->get_values_by_handler_and_field_variable(
5269
            $userId,
5270
            'legal_accept'
5271
        );
5272
5273
        if (!empty($data) && isset($data['value']) && !empty($data['value'])) {
5274
            $result = $data['value'];
5275
            $user_conditions = explode(':', $result);
5276
            $version = $user_conditions[0];
5277
            $langId = $user_conditions[1];
5278
            $realVersion = LegalManager::get_last_version($langId);
5279
5280
            return $version >= $realVersion;
5281
        }
5282
5283
        return false;
5284
    }
5285
5286
    return false;
5287
}
5288
5289
/**
5290
 * Gets all information of a tool into course.
5291
 *
5292
 * @param int The tool id
5293
 *
5294
 * @return array
5295
 */
5296
function api_get_tool_information_by_name($name)
5297
{
5298
    $t_tool = Database::get_course_table(TABLE_TOOL_LIST);
5299
    $course_id = api_get_course_int_id();
5300
5301
    $sql = "SELECT id FROM tool
5302
            WHERE name = '".Database::escape_string($name)."' ";
5303
    $rs = Database::query($sql);
5304
    $data = Database::fetch_array($rs);
5305
    if ($data) {
5306
        $tool = $data['id'];
5307
        $sql = "SELECT * FROM $t_tool
5308
                WHERE c_id = $course_id  AND tool_id = '".$tool."' ";
5309
        $rs = Database::query($sql);
5310
5311
        return Database::fetch_array($rs, 'ASSOC');
5312
    }
5313
5314
    return [];
5315
}
5316
5317
/**
5318
 * Function used to protect a "global" admin script.
5319
 * The function blocks access when the user has no global platform admin rights.
5320
 * Global admins are the admins that are registered in the main.admin table
5321
 * AND the users who have access to the "principal" portal.
5322
 * That means that there is a record in the main.access_url_rel_user table
5323
 * with his user id and the access_url_id=1.
5324
 *
5325
 * @author Julio Montoya
5326
 *
5327
 * @param int $user_id
5328
 *
5329
 * @return bool
5330
 */
5331
function api_is_global_platform_admin($user_id = null)
5332
{
5333
    $user_id = (int) $user_id;
5334
    if (empty($user_id)) {
5335
        $user_id = api_get_user_id();
5336
    }
5337
    if (api_is_platform_admin_by_id($user_id)) {
5338
        $urlList = api_get_access_url_from_user($user_id);
5339
        // The admin is registered in the first "main" site with access_url_id = 1
5340
        if (in_array(1, $urlList)) {
5341
            return true;
5342
        }
5343
    }
5344
5345
    return false;
5346
}
5347
5348
/**
5349
 * @param int  $admin_id_to_check
5350
 * @param int  $userId
5351
 * @param bool $allow_session_admin
5352
 *
5353
 * @return bool
5354
 */
5355
function api_global_admin_can_edit_admin(
5356
    $admin_id_to_check,
5357
    $userId = 0,
5358
    $allow_session_admin = false
5359
) {
5360
    if (empty($userId)) {
5361
        $userId = api_get_user_id();
5362
    }
5363
5364
    $iam_a_global_admin = api_is_global_platform_admin($userId);
5365
    $user_is_global_admin = api_is_global_platform_admin($admin_id_to_check);
5366
5367
    if ($iam_a_global_admin) {
5368
        // Global admin can edit everything
5369
        return true;
5370
    }
5371
5372
    // If i'm a simple admin
5373
    $is_platform_admin = api_is_platform_admin_by_id($userId);
5374
5375
    if ($allow_session_admin && !$is_platform_admin) {
5376
        $user = api_get_user_entity($userId);
5377
        $is_platform_admin = $user->hasRole('ROLE_SESSION_MANAGER');
5378
    }
5379
5380
    if ($is_platform_admin) {
5381
        if ($user_is_global_admin) {
5382
            return false;
5383
        } else {
5384
            return true;
5385
        }
5386
    }
5387
5388
    return false;
5389
}
5390
5391
/**
5392
 * @param int  $admin_id_to_check
5393
 * @param int  $userId
5394
 * @param bool $allow_session_admin
5395
 *
5396
 * @return bool|null
5397
 */
5398
function api_protect_super_admin($admin_id_to_check, $userId = null, $allow_session_admin = false)
5399
{
5400
    if (api_global_admin_can_edit_admin($admin_id_to_check, $userId, $allow_session_admin)) {
5401
        return true;
5402
    } else {
5403
        api_not_allowed();
5404
    }
5405
}
5406
5407
/**
5408
 * Function used to protect a global admin script.
5409
 * The function blocks access when the user has no global platform admin rights.
5410
 * See also the api_is_global_platform_admin() function wich defines who's a "global" admin.
5411
 *
5412
 * @author Julio Montoya
5413
 */
5414
function api_protect_global_admin_script()
5415
{
5416
    if (!api_is_global_platform_admin()) {
5417
        api_not_allowed();
5418
5419
        return false;
5420
    }
5421
5422
    return true;
5423
}
5424
5425
/**
5426
 * Check browser support for specific file types or features
5427
 * This function checks if the user's browser supports a file format or given
5428
 * feature, or returns the current browser and major version when
5429
 * $format=check_browser. Only a limited number of formats and features are
5430
 * checked by this method. Make sure you check its definition first.
5431
 *
5432
 * @param string $format Can be a file format (extension like svg, webm, ...) or a feature (like autocapitalize, ...)
5433
 *
5434
 * @deprecated
5435
 *
5436
 * @return bool or return text array if $format=check_browser
5437
 *
5438
 * @author Juan Carlos Raña Trabado
5439
 */
5440
function api_browser_support($format = '')
5441
{
5442
    return true;
5443
5444
    $browser = new Browser();
0 ignored issues
show
Unused Code introduced by
$browser = new Browser() is not reachable.

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

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

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

    return false;
}

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

Loading history...
5445
    $current_browser = $browser->getBrowser();
5446
    $a_versiontemp = explode('.', $browser->getVersion());
5447
    $current_majorver = $a_versiontemp[0];
5448
5449
    static $result;
5450
5451
    if (isset($result[$format])) {
5452
        return $result[$format];
5453
    }
5454
5455
    // Native svg support
5456
    if ('svg' == $format) {
5457
        if (('Internet Explorer' == $current_browser && $current_majorver >= 9) ||
5458
            ('Firefox' == $current_browser && $current_majorver > 1) ||
5459
            ('Safari' == $current_browser && $current_majorver >= 4) ||
5460
            ('Chrome' == $current_browser && $current_majorver >= 1) ||
5461
            ('Opera' == $current_browser && $current_majorver >= 9)
5462
        ) {
5463
            $result[$format] = true;
5464
5465
            return true;
5466
        } else {
5467
            $result[$format] = false;
5468
5469
            return false;
5470
        }
5471
    } elseif ('pdf' == $format) {
5472
        // native pdf support
5473
        if ('Chrome' == $current_browser && $current_majorver >= 6) {
5474
            $result[$format] = true;
5475
5476
            return true;
5477
        } else {
5478
            $result[$format] = false;
5479
5480
            return false;
5481
        }
5482
    } elseif ('tif' == $format || 'tiff' == $format) {
5483
        //native tif support
5484
        if ('Safari' == $current_browser && $current_majorver >= 5) {
5485
            $result[$format] = true;
5486
5487
            return true;
5488
        } else {
5489
            $result[$format] = false;
5490
5491
            return false;
5492
        }
5493
    } elseif ('ogg' == $format || 'ogx' == $format || 'ogv' == $format || 'oga' == $format) {
5494
        //native ogg, ogv,oga support
5495
        if (('Firefox' == $current_browser && $current_majorver >= 3) ||
5496
            ('Chrome' == $current_browser && $current_majorver >= 3) ||
5497
            ('Opera' == $current_browser && $current_majorver >= 9)) {
5498
            $result[$format] = true;
5499
5500
            return true;
5501
        } else {
5502
            $result[$format] = false;
5503
5504
            return false;
5505
        }
5506
    } elseif ('mpg' == $format || 'mpeg' == $format) {
5507
        //native mpg support
5508
        if (('Safari' == $current_browser && $current_majorver >= 5)) {
5509
            $result[$format] = true;
5510
5511
            return true;
5512
        } else {
5513
            $result[$format] = false;
5514
5515
            return false;
5516
        }
5517
    } elseif ('mp4' == $format) {
5518
        //native mp4 support (TODO: Android, iPhone)
5519
        if ('Android' == $current_browser || 'iPhone' == $current_browser) {
5520
            $result[$format] = true;
5521
5522
            return true;
5523
        } else {
5524
            $result[$format] = false;
5525
5526
            return false;
5527
        }
5528
    } elseif ('mov' == $format) {
5529
        //native mov support( TODO:check iPhone)
5530
        if ('Safari' == $current_browser && $current_majorver >= 5 || 'iPhone' == $current_browser) {
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: ('Safari' == $current_br...ne' == $current_browser, Probably Intended Meaning: 'Safari' == $current_bro...e' == $current_browser)
Loading history...
5531
            $result[$format] = true;
5532
5533
            return true;
5534
        } else {
5535
            $result[$format] = false;
5536
5537
            return false;
5538
        }
5539
    } elseif ('avi' == $format) {
5540
        //native avi support
5541
        if ('Safari' == $current_browser && $current_majorver >= 5) {
5542
            $result[$format] = true;
5543
5544
            return true;
5545
        } else {
5546
            $result[$format] = false;
5547
5548
            return false;
5549
        }
5550
    } elseif ('wmv' == $format) {
5551
        //native wmv support
5552
        if ('Firefox' == $current_browser && $current_majorver >= 4) {
5553
            $result[$format] = true;
5554
5555
            return true;
5556
        } else {
5557
            $result[$format] = false;
5558
5559
            return false;
5560
        }
5561
    } elseif ('webm' == $format) {
5562
        //native webm support (TODO:check IE9, Chrome9, Android)
5563
        if (('Firefox' == $current_browser && $current_majorver >= 4) ||
5564
            ('Opera' == $current_browser && $current_majorver >= 9) ||
5565
            ('Internet Explorer' == $current_browser && $current_majorver >= 9) ||
5566
            ('Chrome' == $current_browser && $current_majorver >= 9) ||
5567
            'Android' == $current_browser
5568
        ) {
5569
            $result[$format] = true;
5570
5571
            return true;
5572
        } else {
5573
            $result[$format] = false;
5574
5575
            return false;
5576
        }
5577
    } elseif ('wav' == $format) {
5578
        //native wav support (only some codecs !)
5579
        if (('Firefox' == $current_browser && $current_majorver >= 4) ||
5580
            ('Safari' == $current_browser && $current_majorver >= 5) ||
5581
            ('Opera' == $current_browser && $current_majorver >= 9) ||
5582
            ('Internet Explorer' == $current_browser && $current_majorver >= 9) ||
5583
            ('Chrome' == $current_browser && $current_majorver > 9) ||
5584
            'Android' == $current_browser ||
5585
            'iPhone' == $current_browser
5586
        ) {
5587
            $result[$format] = true;
5588
5589
            return true;
5590
        } else {
5591
            $result[$format] = false;
5592
5593
            return false;
5594
        }
5595
    } elseif ('mid' == $format || 'kar' == $format) {
5596
        //native midi support (TODO:check Android)
5597
        if ('Opera' == $current_browser && $current_majorver >= 9 || 'Android' == $current_browser) {
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: ('Opera' == $current_bro...id' == $current_browser, Probably Intended Meaning: 'Opera' == $current_brow...d' == $current_browser)
Loading history...
5598
            $result[$format] = true;
5599
5600
            return true;
5601
        } else {
5602
            $result[$format] = false;
5603
5604
            return false;
5605
        }
5606
    } elseif ('wma' == $format) {
5607
        //native wma support
5608
        if ('Firefox' == $current_browser && $current_majorver >= 4) {
5609
            $result[$format] = true;
5610
5611
            return true;
5612
        } else {
5613
            $result[$format] = false;
5614
5615
            return false;
5616
        }
5617
    } elseif ('au' == $format) {
5618
        //native au support
5619
        if ('Safari' == $current_browser && $current_majorver >= 5) {
5620
            $result[$format] = true;
5621
5622
            return true;
5623
        } else {
5624
            $result[$format] = false;
5625
5626
            return false;
5627
        }
5628
    } elseif ('mp3' == $format) {
5629
        //native mp3 support (TODO:check Android, iPhone)
5630
        if (('Safari' == $current_browser && $current_majorver >= 5) ||
5631
            ('Chrome' == $current_browser && $current_majorver >= 6) ||
5632
            ('Internet Explorer' == $current_browser && $current_majorver >= 9) ||
5633
            'Android' == $current_browser ||
5634
            'iPhone' == $current_browser ||
5635
            'Firefox' == $current_browser
5636
        ) {
5637
            $result[$format] = true;
5638
5639
            return true;
5640
        } else {
5641
            $result[$format] = false;
5642
5643
            return false;
5644
        }
5645
    } elseif ('autocapitalize' == $format) {
5646
        // Help avoiding showing the autocapitalize option if the browser doesn't
5647
        // support it: this attribute is against the HTML5 standard
5648
        if ('Safari' == $current_browser || 'iPhone' == $current_browser) {
5649
            return true;
5650
        } else {
5651
            return false;
5652
        }
5653
    } elseif ("check_browser" == $format) {
5654
        $array_check_browser = [$current_browser, $current_majorver];
5655
5656
        return $array_check_browser;
5657
    } else {
5658
        $result[$format] = false;
5659
5660
        return false;
5661
    }
5662
}
5663
5664
/**
5665
 * This function checks if exist path and file browscap.ini
5666
 * In order for this to work, your browscap configuration setting in php.ini
5667
 * must point to the correct location of the browscap.ini file on your system
5668
 * http://php.net/manual/en/function.get-browser.php.
5669
 *
5670
 * @return bool
5671
 *
5672
 * @author Juan Carlos Raña Trabado
5673
 */
5674
function api_check_browscap()
5675
{
5676
    $setting = ini_get('browscap');
5677
    if ($setting) {
5678
        $browser = get_browser($_SERVER['HTTP_USER_AGENT'], true);
5679
        if (strpos($setting, 'browscap.ini') && !empty($browser)) {
5680
            return true;
5681
        }
5682
    }
5683
5684
    return false;
5685
}
5686
5687
/**
5688
 * Returns the <script> HTML tag.
5689
 */
5690
function api_get_js($file)
5691
{
5692
    return '<script src="'.api_get_path(WEB_LIBRARY_PATH).'javascript/'.$file.'"></script>'."\n";
5693
}
5694
5695
function api_get_build_js($file)
5696
{
5697
    return '<script src="'.api_get_path(WEB_PUBLIC_PATH).'build/'.$file.'"></script>'."\n";
5698
}
5699
5700
function api_get_build_css($file, $media = 'screen')
5701
{
5702
    return '<link
5703
        href="'.api_get_path(WEB_PUBLIC_PATH).'build/'.$file.'" rel="stylesheet" media="'.$media.'" type="text/css" />'."\n";
5704
}
5705
5706
/**
5707
 * Returns the <script> HTML tag.
5708
 *
5709
 * @return string
5710
 */
5711
function api_get_asset($file)
5712
{
5713
    return '<script src="'.api_get_path(WEB_PUBLIC_PATH).'build/libs/'.$file.'"></script>'."\n";
5714
}
5715
5716
/**
5717
 * Returns the <script> HTML tag.
5718
 *
5719
 * @param string $file
5720
 * @param string $media
5721
 *
5722
 * @return string
5723
 */
5724
function api_get_css_asset($file, $media = 'screen')
5725
{
5726
    return '<link
5727
        href="'.api_get_path(WEB_PUBLIC_PATH).'build/libs/'.$file.'"
5728
        rel="stylesheet" media="'.$media.'" type="text/css" />'."\n";
5729
}
5730
5731
/**
5732
 * Returns the <link> HTML tag.
5733
 *
5734
 * @param string $file
5735
 * @param string $media
5736
 */
5737
function api_get_css($file, $media = 'screen')
5738
{
5739
    return '<link href="'.$file.'" rel="stylesheet" media="'.$media.'" type="text/css" />'."\n";
5740
}
5741
5742
function api_get_bootstrap_and_font_awesome($returnOnlyPath = false, $returnFileLocation = false)
5743
{
5744
    $url = api_get_path(WEB_PUBLIC_PATH).'build/css/bootstrap.css';
5745
5746
    if ($returnOnlyPath) {
5747
        if ($returnFileLocation) {
5748
            return api_get_path(SYS_PUBLIC_PATH).'build/css/bootstrap.css';
5749
        }
5750
5751
        return $url;
5752
    }
5753
5754
    return '<link href="'.$url.'" rel="stylesheet" type="text/css" />'."\n";
5755
}
5756
5757
/**
5758
 * Returns the js header to include the jquery library.
5759
 */
5760
function api_get_jquery_js()
5761
{
5762
    return api_get_asset('jquery/jquery.min.js');
5763
}
5764
5765
/**
5766
 * Returns the jquery path.
5767
 *
5768
 * @return string
5769
 */
5770
function api_get_jquery_web_path()
5771
{
5772
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery/jquery.min.js';
5773
}
5774
5775
/**
5776
 * @return string
5777
 */
5778
function api_get_jquery_ui_js_web_path()
5779
{
5780
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery-ui/jquery-ui.min.js';
5781
}
5782
5783
/**
5784
 * @return string
5785
 */
5786
function api_get_jquery_ui_css_web_path()
5787
{
5788
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery-ui/themes/smoothness/jquery-ui.min.css';
5789
}
5790
5791
/**
5792
 * Returns the jquery-ui library js headers.
5793
 *
5794
 * @return string html tags
5795
 */
5796
function api_get_jquery_ui_js()
5797
{
5798
    $libraries = [];
5799
5800
    return api_get_jquery_libraries_js($libraries);
5801
}
5802
5803
function api_get_jqgrid_js()
5804
{
5805
    return api_get_build_css('free-jqgrid.css').PHP_EOL
5806
        .api_get_build_js('free-jqgrid.js');
5807
}
5808
5809
/**
5810
 * Returns the jquery library js and css headers.
5811
 *
5812
 * @param   array   list of jquery libraries supported jquery-ui
5813
 * @param   bool    add the jquery library
5814
 *
5815
 * @return string html tags
5816
 */
5817
function api_get_jquery_libraries_js($libraries)
5818
{
5819
    $js = '';
5820
5821
    //Document multiple upload funcionality
5822
    if (in_array('jquery-uploadzs', $libraries)) {
5823
        $js .= api_get_asset('blueimp-load-image/js/load-image.all.min.js');
5824
        $js .= api_get_asset('blueimp-canvas-to-blob/js/canvas-to-blob.min.js');
5825
        $js .= api_get_asset('jquery-file-upload/js/jquery.iframe-transport.js');
5826
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload.js');
5827
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-process.js');
5828
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-image.js');
5829
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-audio.js');
5830
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-video.js');
5831
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-validate.js');
5832
5833
        $js .= api_get_css(api_get_path(WEB_PUBLIC_PATH).'assets/jquery-file-upload/css/jquery.fileupload.css');
5834
        $js .= api_get_css(api_get_path(WEB_PUBLIC_PATH).'assets/jquery-file-upload/css/jquery.fileupload-ui.css');
5835
    }
5836
5837
    // jquery datepicker
5838
    if (in_array('datepicker', $libraries)) {
5839
        $languaje = 'en-GB';
5840
        $platform_isocode = strtolower(api_get_language_isocode());
5841
5842
        $datapicker_langs = [
5843
            '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',
5844
        ];
5845
        if (in_array($platform_isocode, $datapicker_langs)) {
5846
            $languaje = $platform_isocode;
5847
        }
5848
5849
        $js .= api_get_js('jquery-ui/jquery-ui-i18n.min.js');
5850
        $script = '<script>
5851
        $(function(){
5852
            $.datepicker.setDefaults($.datepicker.regional["'.$languaje.'"]);
5853
            $.datepicker.regional["local"] = $.datepicker.regional["'.$languaje.'"];
5854
        });
5855
        </script>
5856
        ';
5857
        $js .= $script;
5858
    }
5859
5860
    return $js;
5861
}
5862
5863
/**
5864
 * Returns the URL to the course or session, removing the complexity of the URL
5865
 * building piece by piece.
5866
 *
5867
 * This function relies on api_get_course_info()
5868
 *
5869
 * @param int $courseId  The course code - optional (takes it from context if not given)
5870
 * @param int $sessionId The session ID  - optional (takes it from context if not given)
5871
 * @param int $groupId   The group ID - optional (takes it from context if not given)
5872
 *
5873
 * @return string The URL to a course, a session, or empty string if nothing works
5874
 *                e.g. https://localhost/courses/ABC/index.php?session_id=3&gidReq=1
5875
 *
5876
 * @author  Julio Montoya
5877
 */
5878
function api_get_course_url($courseId = null, $sessionId = null, $groupId = null)
5879
{
5880
    $url = '';
5881
    // If courseCode not set, get context or []
5882
    if (empty($courseId)) {
5883
        $courseId = api_get_course_int_id();
5884
    }
5885
5886
    // If sessionId not set, get context or 0
5887
    if (empty($sessionId)) {
5888
        $sessionId = api_get_session_id();
5889
    }
5890
5891
    // If groupId not set, get context or 0
5892
    if (empty($groupId)) {
5893
        $groupId = api_get_group_id();
5894
    }
5895
5896
    // Build the URL
5897
    if (!empty($courseId)) {
5898
        $webCourseHome = '/course/'.$courseId.'/home';
5899
        // directory not empty, so we do have a course
5900
        $url = $webCourseHome.'?sid='.$sessionId.'&gid='.$groupId;
5901
    } else {
5902
        if (!empty($sessionId) && 'true' !== api_get_setting('session.remove_session_url')) {
5903
            // if the course was unset and the session was set, send directly to the session
5904
            $url = api_get_path(WEB_CODE_PATH).'session/index.php?session_id='.$sessionId;
5905
        }
5906
    }
5907
5908
    // if not valid combination was found, return an empty string
5909
    return $url;
5910
}
5911
5912
/**
5913
 * Check if the current portal has the $_configuration['multiple_access_urls'] parameter on.
5914
 */
5915
function api_get_multiple_access_url(): bool
5916
{
5917
    global $_configuration;
5918
    if (isset($_configuration['multiple_access_urls']) && $_configuration['multiple_access_urls']) {
5919
        return true;
5920
    }
5921
5922
    return false;
5923
}
5924
5925
function api_is_multiple_url_enabled(): bool
5926
{
5927
    return api_get_multiple_access_url();
5928
}
5929
5930
/**
5931
 * Returns a md5 unique id.
5932
 *
5933
 * @todo add more parameters
5934
 */
5935
function api_get_unique_id()
5936
{
5937
    return md5(time().uniqid().api_get_user_id().api_get_course_id().api_get_session_id());
5938
}
5939
5940
/**
5941
 * @param int Course id
5942
 * @param int tool id: TOOL_QUIZ, TOOL_FORUM, TOOL_STUDENTPUBLICATION, TOOL_LEARNPATH
5943
 * @param int the item id (tool id, exercise id, lp id)
5944
 *
5945
 * @return bool
5946
 */
5947
function api_resource_is_locked_by_gradebook($item_id, $link_type, $course_code = null)
5948
{
5949
    if (api_is_platform_admin()) {
5950
        return false;
5951
    }
5952
    if ('true' === api_get_setting('gradebook_locking_enabled')) {
5953
        if (empty($course_code)) {
5954
            $course_code = api_get_course_id();
5955
        }
5956
        $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_LINK);
5957
        $item_id = (int) $item_id;
5958
        $link_type = (int) $link_type;
5959
        $course_code = Database::escape_string($course_code);
5960
        $sql = "SELECT locked FROM $table
5961
                WHERE locked = 1 AND ref_id = $item_id AND type = $link_type AND course_code = '$course_code' ";
5962
        $result = Database::query($sql);
5963
        if (Database::num_rows($result)) {
5964
            return true;
5965
        }
5966
    }
5967
5968
    return false;
5969
}
5970
5971
/**
5972
 * Blocks a page if the item was added in a gradebook.
5973
 *
5974
 * @param int       exercise id, work id, thread id,
5975
 * @param int       LINK_EXERCISE, LINK_STUDENTPUBLICATION, LINK_LEARNPATH LINK_FORUM_THREAD, LINK_ATTENDANCE
5976
 * see gradebook/lib/be/linkfactory
5977
 * @param string    course code
5978
 *
5979
 * @return false|null
5980
 */
5981
function api_block_course_item_locked_by_gradebook($item_id, $link_type, $course_code = null)
5982
{
5983
    if (api_is_platform_admin()) {
5984
        return false;
5985
    }
5986
5987
    if (api_resource_is_locked_by_gradebook($item_id, $link_type, $course_code)) {
5988
        $message = Display::return_message(
5989
            get_lang(
5990
                'This option is not available because this activity is contained by an assessment, which is currently locked. To unlock the assessment, ask your platform administrator.'
5991
            ),
5992
            'warning'
5993
        );
5994
        api_not_allowed(true, $message);
5995
    }
5996
}
5997
5998
/**
5999
 * Checks the PHP version installed is enough to run Chamilo.
6000
 *
6001
 * @param string Include path (used to load the error page)
6002
 */
6003
function api_check_php_version()
6004
{
6005
    if (!function_exists('version_compare') ||
6006
        version_compare(PHP_VERSION, REQUIRED_PHP_VERSION, '<')
6007
    ) {
6008
        throw new Exception('Wrong PHP version');
6009
    }
6010
}
6011
6012
/**
6013
 * Checks whether the Archive directory is present and writeable. If not,
6014
 * prints a warning message.
6015
 */
6016
function api_check_archive_dir()
6017
{
6018
    if (is_dir(api_get_path(SYS_ARCHIVE_PATH)) && !is_writable(api_get_path(SYS_ARCHIVE_PATH))) {
6019
        $message = Display::return_message(
6020
            get_lang(
6021
                'The var/cache/ directory, used by this tool, is not writeable. Please contact your platform administrator.'
6022
            ),
6023
            'warning'
6024
        );
6025
        api_not_allowed(true, $message);
6026
    }
6027
}
6028
6029
/**
6030
 * Returns an array of global configuration settings which should be ignored
6031
 * when printing the configuration settings screens.
6032
 *
6033
 * @return array Array of strings, each identifying one of the excluded settings
6034
 */
6035
function api_get_locked_settings()
6036
{
6037
    return [
6038
        'permanently_remove_deleted_files',
6039
        'account_valid_duration',
6040
        'service_ppt2lp',
6041
        'wcag_anysurfer_public_pages',
6042
        'upload_extensions_list_type',
6043
        'upload_extensions_blacklist',
6044
        'upload_extensions_whitelist',
6045
        'upload_extensions_skip',
6046
        'upload_extensions_replace_by',
6047
        'hide_dltt_markup',
6048
        'split_users_upload_directory',
6049
        'permissions_for_new_directories',
6050
        'permissions_for_new_files',
6051
        'platform_charset',
6052
        'ldap_description',
6053
        'cas_activate',
6054
        'cas_server',
6055
        'cas_server_uri',
6056
        'cas_port',
6057
        'cas_protocol',
6058
        'cas_add_user_activate',
6059
        'update_user_info_cas_with_ldap',
6060
        'languagePriority1',
6061
        'languagePriority2',
6062
        'languagePriority3',
6063
        'languagePriority4',
6064
        'login_is_email',
6065
        'chamilo_database_version',
6066
    ];
6067
}
6068
6069
/**
6070
 * Guess the real ip for register in the database, even in reverse proxy cases.
6071
 * To be recognized, the IP has to be found in either $_SERVER['REMOTE_ADDR'] or
6072
 * in $_SERVER['HTTP_X_FORWARDED_FOR'], which is in common use with rproxies.
6073
 * Note: the result of this function is not SQL-safe. Please escape it before
6074
 * inserting in a database.
6075
 *
6076
 * @return string the user's real ip (unsafe - escape it before inserting to db)
6077
 *
6078
 * @author Jorge Frisancho Jibaja <[email protected]>, USIL - Some changes to allow the use of real IP using reverse proxy
6079
 *
6080
 * @version CEV CHANGE 24APR2012
6081
 */
6082
function api_get_real_ip()
6083
{
6084
    $ip = trim($_SERVER['REMOTE_ADDR']);
6085
    if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
6086
        if (preg_match('/,/', $_SERVER['HTTP_X_FORWARDED_FOR'])) {
6087
            @list($ip1, $ip2) = @explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
6088
        } else {
6089
            $ip1 = $_SERVER['HTTP_X_FORWARDED_FOR'];
6090
        }
6091
        $ip = trim($ip1);
6092
    }
6093
6094
    return $ip;
6095
}
6096
6097
/**
6098
 * Checks whether an IP is included inside an IP range.
6099
 *
6100
 * @param string IP address
6101
 * @param string IP range
6102
 * @param string $ip
6103
 *
6104
 * @return bool True if IP is in the range, false otherwise
6105
 *
6106
 * @author claudiu at cnixs dot com  on http://www.php.net/manual/fr/ref.network.php#55230
6107
 * @author Yannick Warnier for improvements and managment of multiple ranges
6108
 *
6109
 * @todo check for IPv6 support
6110
 */
6111
function api_check_ip_in_range($ip, $range)
6112
{
6113
    if (empty($ip) or empty($range)) {
6114
        return false;
6115
    }
6116
    $ip_ip = ip2long($ip);
6117
    // divide range param into array of elements
6118
    if (false !== strpos($range, ',')) {
6119
        $ranges = explode(',', $range);
6120
    } else {
6121
        $ranges = [$range];
6122
    }
6123
    foreach ($ranges as $range) {
0 ignored issues
show
introduced by
$range is overwriting one of the parameters of this function.
Loading history...
6124
        $range = trim($range);
6125
        if (empty($range)) {
6126
            continue;
6127
        }
6128
        if (false === strpos($range, '/')) {
6129
            if (0 === strcmp($ip, $range)) {
6130
                return true; // there is a direct IP match, return OK
6131
            }
6132
            continue; //otherwise, get to the next range
6133
        }
6134
        // the range contains a "/", so analyse completely
6135
        [$net, $mask] = explode("/", $range);
6136
6137
        $ip_net = ip2long($net);
6138
        // mask binary magic
6139
        $ip_mask = ~((1 << (32 - $mask)) - 1);
6140
6141
        $ip_ip_net = $ip_ip & $ip_mask;
6142
        if ($ip_ip_net == $ip_net) {
6143
            return true;
6144
        }
6145
    }
6146
6147
    return false;
6148
}
6149
6150
function api_check_user_access_to_legal($courseInfo)
6151
{
6152
    if (empty($courseInfo)) {
6153
        return false;
6154
    }
6155
6156
    $visibility = (int) $courseInfo['visibility'];
6157
    $visibilityList = [COURSE_VISIBILITY_OPEN_WORLD, COURSE_VISIBILITY_OPEN_PLATFORM];
6158
6159
    return
6160
        in_array($visibility, $visibilityList) ||
6161
        api_is_drh() ||
6162
        (COURSE_VISIBILITY_REGISTERED === $visibility && 1 === (int) $courseInfo['subscribe']);
6163
}
6164
6165
/**
6166
 * Checks if the global chat is enabled or not.
6167
 *
6168
 * @return bool
6169
 */
6170
function api_is_global_chat_enabled()
6171
{
6172
    return
6173
        !api_is_anonymous() &&
6174
        'true' === api_get_setting('allow_global_chat') &&
6175
        'true' === api_get_setting('allow_social_tool');
6176
}
6177
6178
/**
6179
 * @param int   $item_id
6180
 * @param int   $tool_id
6181
 * @param int   $group_id   id
6182
 * @param array $courseInfo
6183
 * @param int   $sessionId
6184
 * @param int   $userId
6185
 *
6186
 * @deprecated
6187
 */
6188
function api_set_default_visibility(
6189
    $item_id,
6190
    $tool_id,
6191
    $group_id = 0,
6192
    $courseInfo = [],
6193
    $sessionId = 0,
6194
    $userId = 0
6195
) {
6196
    $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
6197
    $courseId = $courseInfo['real_id'];
6198
    $courseCode = $courseInfo['code'];
6199
    $sessionId = empty($sessionId) ? api_get_session_id() : $sessionId;
6200
    $userId = empty($userId) ? api_get_user_id() : $userId;
6201
6202
    // if group is null force group_id = 0, this force is needed to create a LP folder with group = 0
6203
    if (is_null($group_id)) {
6204
        $group_id = 0;
6205
    } else {
6206
        $group_id = empty($group_id) ? api_get_group_id() : $group_id;
6207
    }
6208
6209
    $groupInfo = [];
6210
    if (!empty($group_id)) {
6211
        $groupInfo = GroupManager::get_group_properties($group_id);
6212
    }
6213
    $original_tool_id = $tool_id;
6214
6215
    switch ($tool_id) {
6216
        case TOOL_LINK:
6217
        case TOOL_LINK_CATEGORY:
6218
            $tool_id = 'links';
6219
            break;
6220
        case TOOL_DOCUMENT:
6221
            $tool_id = 'documents';
6222
            break;
6223
        case TOOL_LEARNPATH:
6224
            $tool_id = 'learning';
6225
            break;
6226
        case TOOL_ANNOUNCEMENT:
6227
            $tool_id = 'announcements';
6228
            break;
6229
        case TOOL_FORUM:
6230
        case TOOL_FORUM_CATEGORY:
6231
        case TOOL_FORUM_THREAD:
6232
            $tool_id = 'forums';
6233
            break;
6234
        case TOOL_QUIZ:
6235
            $tool_id = 'quiz';
6236
            break;
6237
    }
6238
    $setting = api_get_setting('tool_visible_by_default_at_creation');
6239
6240
    if (isset($setting[$tool_id])) {
6241
        $visibility = 'invisible';
6242
        if ('true' === $setting[$tool_id]) {
6243
            $visibility = 'visible';
6244
        }
6245
6246
        // Read the portal and course default visibility
6247
        if ('documents' === $tool_id) {
6248
            $visibility = DocumentManager::getDocumentDefaultVisibility($courseInfo);
6249
        }
6250
6251
        // Fixes default visibility for tests
6252
        switch ($original_tool_id) {
6253
            case TOOL_QUIZ:
6254
                if (empty($sessionId)) {
6255
                    $objExerciseTmp = new Exercise($courseId);
6256
                    $objExerciseTmp->read($item_id);
6257
                    if ('visible' === $visibility) {
6258
                        $objExerciseTmp->enable();
6259
                        $objExerciseTmp->save();
6260
                    } else {
6261
                        $objExerciseTmp->disable();
6262
                        $objExerciseTmp->save();
6263
                    }
6264
                }
6265
                break;
6266
        }
6267
    }
6268
}
6269
6270
function api_get_roles()
6271
{
6272
    $hierarchy = Container::$container->getParameter('security.role_hierarchy.roles');
0 ignored issues
show
Bug introduced by
The method getParameter() does not exist on null. ( Ignorable by Annotation )

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

6272
    /** @scrutinizer ignore-call */ 
6273
    $hierarchy = Container::$container->getParameter('security.role_hierarchy.roles');

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...
6273
    $roles = [];
6274
    array_walk_recursive($hierarchy, function ($role) use (&$roles) {
6275
        $roles[$role] = $role;
6276
    });
6277
6278
    return $roles;
6279
}
6280
6281
/**
6282
 * @param string $file
6283
 *
6284
 * @return string
6285
 */
6286
function api_get_js_simple($file)
6287
{
6288
    return '<script type="text/javascript" src="'.$file.'"></script>'."\n";
6289
}
6290
6291
/**
6292
 * Modify default memory_limit and max_execution_time limits
6293
 * Needed when processing long tasks.
6294
 */
6295
function api_set_more_memory_and_time_limits()
6296
{
6297
    if (function_exists('ini_set')) {
6298
        api_set_memory_limit('256M');
6299
        ini_set('max_execution_time', 1800);
6300
    }
6301
}
6302
6303
/**
6304
 * Tries to set memory limit, if authorized and new limit is higher than current.
6305
 *
6306
 * @param string $mem New memory limit
6307
 *
6308
 * @return bool True on success, false on failure or current is higher than suggested
6309
 * @assert (null) === false
6310
 * @assert (-1) === false
6311
 * @assert (0) === true
6312
 * @assert ('1G') === true
6313
 */
6314
function api_set_memory_limit($mem)
6315
{
6316
    //if ini_set() not available, this function is useless
6317
    if (!function_exists('ini_set') || is_null($mem) || -1 == $mem) {
6318
        return false;
6319
    }
6320
6321
    $memory_limit = ini_get('memory_limit');
6322
    if (api_get_bytes_memory_limit($mem) > api_get_bytes_memory_limit($memory_limit)) {
6323
        ini_set('memory_limit', $mem);
6324
6325
        return true;
6326
    }
6327
6328
    return false;
6329
}
6330
6331
/**
6332
 * Gets memory limit in bytes.
6333
 *
6334
 * @param string The memory size (128M, 1G, 1000K, etc)
6335
 *
6336
 * @return int
6337
 * @assert (null) === false
6338
 * @assert ('1t')  === 1099511627776
6339
 * @assert ('1g')  === 1073741824
6340
 * @assert ('1m')  === 1048576
6341
 * @assert ('100k') === 102400
6342
 */
6343
function api_get_bytes_memory_limit($mem)
6344
{
6345
    $size = strtolower(substr($mem, -1));
6346
6347
    switch ($size) {
6348
        case 't':
6349
            $mem = (int) substr($mem, -1) * 1024 * 1024 * 1024 * 1024;
6350
            break;
6351
        case 'g':
6352
            $mem = (int) substr($mem, 0, -1) * 1024 * 1024 * 1024;
6353
            break;
6354
        case 'm':
6355
            $mem = (int) substr($mem, 0, -1) * 1024 * 1024;
6356
            break;
6357
        case 'k':
6358
            $mem = (int) substr($mem, 0, -1) * 1024;
6359
            break;
6360
        default:
6361
            // we assume it's integer only
6362
            $mem = (int) $mem;
6363
            break;
6364
    }
6365
6366
    return $mem;
6367
}
6368
6369
/**
6370
 * Finds all the information about a user from username instead of user id.
6371
 *
6372
 * @param string $officialCode
6373
 *
6374
 * @return array $user_info user_id, lastname, firstname, username, email, ...
6375
 *
6376
 * @author Yannick Warnier <[email protected]>
6377
 */
6378
function api_get_user_info_from_official_code($officialCode)
6379
{
6380
    if (empty($officialCode)) {
6381
        return false;
6382
    }
6383
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
6384
            WHERE official_code ='".Database::escape_string($officialCode)."'";
6385
    $result = Database::query($sql);
6386
    if (Database::num_rows($result) > 0) {
6387
        $result_array = Database::fetch_array($result);
6388
6389
        return _api_format_user($result_array);
6390
    }
6391
6392
    return false;
6393
}
6394
6395
/**
6396
 * @param string $usernameInputId
6397
 * @param string $passwordInputId
6398
 *
6399
 * @return string|null
6400
 */
6401
function api_get_password_checker_js($usernameInputId, $passwordInputId)
6402
{
6403
    $checkPass = api_get_setting('allow_strength_pass_checker');
6404
    $useStrengthPassChecker = 'true' === $checkPass;
6405
6406
    if (false === $useStrengthPassChecker) {
6407
        return null;
6408
    }
6409
6410
    $translations = [
6411
        'wordLength' => get_lang('The password is too short'),
6412
        'wordNotEmail' => get_lang('Your password cannot be the same as your email'),
6413
        'wordSimilarToUsername' => get_lang('Your password cannot contain your username'),
6414
        'wordTwoCharacterClasses' => get_lang('Use different character classes'),
6415
        'wordRepetitions' => get_lang('Too many repetitions'),
6416
        'wordSequences' => get_lang('Your password contains sequences'),
6417
        'errorList' => get_lang('errors found'),
6418
        'veryWeak' => get_lang('Very weak'),
6419
        'weak' => get_lang('Weak'),
6420
        'normal' => get_lang('Normal'),
6421
        'medium' => get_lang('Medium'),
6422
        'strong' => get_lang('Strong'),
6423
        'veryStrong' => get_lang('Very strong'),
6424
    ];
6425
6426
    $js = api_get_asset('pwstrength-bootstrap/dist/pwstrength-bootstrap.js');
6427
    $js .= "<script>
6428
    var errorMessages = {
6429
        password_to_short : \"".get_lang('The password is too short')."\",
6430
        same_as_username : \"".get_lang('Your password cannot be the same as your username')."\"
6431
    };
6432
6433
    $(function() {
6434
        var lang = ".json_encode($translations).";
6435
        var options = {
6436
            onLoad : function () {
6437
                //$('#messages').text('Start typing password');
6438
            },
6439
            onKeyUp: function (evt) {
6440
                $(evt.target).pwstrength('outputErrorList');
6441
            },
6442
            errorMessages : errorMessages,
6443
            viewports: {
6444
                progress: '#password_progress',
6445
                verdict: '#password-verdict',
6446
                errors: '#password-errors'
6447
            },
6448
            usernameField: '$usernameInputId'
6449
        };
6450
        options.i18n = {
6451
            t: function (key) {
6452
                var result = lang[key];
6453
                return result === key ? '' : result; // This assumes you return the
6454
            }
6455
        };
6456
        $('".$passwordInputId."').pwstrength(options);
6457
    });
6458
    </script>";
6459
6460
    return $js;
6461
}
6462
6463
/**
6464
 * create an user extra field called 'captcha_blocked_until_date'.
6465
 *
6466
 * @param string $username
6467
 *
6468
 * @return bool
6469
 */
6470
function api_block_account_captcha($username)
6471
{
6472
    $userInfo = api_get_user_info_from_username($username);
6473
    if (empty($userInfo)) {
6474
        return false;
6475
    }
6476
    $minutesToBlock = api_get_setting('captcha_time_to_block');
6477
    $time = time() + $minutesToBlock * 60;
6478
    UserManager::update_extra_field_value(
6479
        $userInfo['user_id'],
6480
        'captcha_blocked_until_date',
6481
        api_get_utc_datetime($time)
6482
    );
6483
6484
    return true;
6485
}
6486
6487
/**
6488
 * @param string $username
6489
 *
6490
 * @return bool
6491
 */
6492
function api_clean_account_captcha($username)
6493
{
6494
    $userInfo = api_get_user_info_from_username($username);
6495
    if (empty($userInfo)) {
6496
        return false;
6497
    }
6498
    Session::erase('loginFailedCount');
6499
    UserManager::update_extra_field_value(
6500
        $userInfo['user_id'],
6501
        'captcha_blocked_until_date',
6502
        null
6503
    );
6504
6505
    return true;
6506
}
6507
6508
/**
6509
 * @param string $username
6510
 *
6511
 * @return bool
6512
 */
6513
function api_get_user_blocked_by_captcha($username)
6514
{
6515
    $userInfo = api_get_user_info_from_username($username);
6516
    if (empty($userInfo)) {
6517
        return false;
6518
    }
6519
    $data = UserManager::get_extra_user_data_by_field(
6520
        $userInfo['user_id'],
6521
        'captcha_blocked_until_date'
6522
    );
6523
    if (isset($data) && isset($data['captcha_blocked_until_date'])) {
6524
        return $data['captcha_blocked_until_date'];
6525
    }
6526
6527
    return false;
6528
}
6529
6530
/**
6531
 * If true, the drh can access all content (courses, users) inside a session.
6532
 *
6533
 * @return bool
6534
 */
6535
function api_drh_can_access_all_session_content()
6536
{
6537
    return 'true' === api_get_setting('drh_can_access_all_session_content');
6538
}
6539
6540
/**
6541
 * Checks if user can login as another user.
6542
 *
6543
 * @param int $loginAsUserId the user id to log in
6544
 * @param int $userId        my user id
6545
 *
6546
 * @return bool
6547
 */
6548
function api_can_login_as($loginAsUserId, $userId = null)
6549
{
6550
    $loginAsUserId = (int) $loginAsUserId;
6551
6552
    if (empty($loginAsUserId)) {
6553
        return false;
6554
    }
6555
6556
    if (empty($userId)) {
6557
        $userId = api_get_user_id();
6558
    }
6559
6560
    if ($loginAsUserId == $userId) {
6561
        return false;
6562
    }
6563
6564
    // Check if the user to login is an admin
6565
    if (api_is_platform_admin_by_id($loginAsUserId)) {
6566
        // Only super admins can login to admin accounts
6567
        if (!api_global_admin_can_edit_admin($loginAsUserId)) {
6568
            return false;
6569
        }
6570
    }
6571
6572
    $userInfo = api_get_user_info($loginAsUserId);
6573
6574
    $isDrh = function () use ($loginAsUserId) {
6575
        if (api_is_drh()) {
6576
            if (api_drh_can_access_all_session_content()) {
6577
                $users = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus(
6578
                    'drh_all',
6579
                    api_get_user_id()
6580
                );
6581
                $userList = [];
6582
                if (is_array($users)) {
6583
                    foreach ($users as $user) {
6584
                        $userList[] = $user['id'];
6585
                    }
6586
                }
6587
                if (in_array($loginAsUserId, $userList)) {
6588
                    return true;
6589
                }
6590
            } else {
6591
                if (api_is_drh() &&
6592
                    UserManager::is_user_followed_by_drh($loginAsUserId, api_get_user_id())
6593
                ) {
6594
                    return true;
6595
                }
6596
            }
6597
        }
6598
6599
        return false;
6600
    };
6601
6602
    $loginAsStatusForSessionAdmins = [STUDENT];
6603
6604
    if (api_get_setting('session.allow_session_admin_login_as_teacher')) {
6605
        $loginAsStatusForSessionAdmins[] = COURSEMANAGER;
6606
    }
6607
6608
    return api_is_platform_admin() ||
6609
        (api_is_session_admin() && in_array($userInfo['status'], $loginAsStatusForSessionAdmins)) ||
6610
        $isDrh();
6611
}
6612
6613
/**
6614
 * Return true on https install.
6615
 *
6616
 * @return bool
6617
 */
6618
function api_is_https()
6619
{
6620
    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...
6621
        'https' == $_SERVER['HTTP_X_FORWARDED_PROTO'] || !empty(api_get_configuration_value('force_https_forwarded_proto'))
6622
    ) {
6623
        $isSecured = true;
6624
    } else {
6625
        if (!empty($_SERVER['HTTPS']) && 'off' != $_SERVER['HTTPS']) {
6626
            $isSecured = true;
6627
        } else {
6628
            $isSecured = false;
6629
            // last chance
6630
            if (!empty($_SERVER['SERVER_PORT']) && 443 == $_SERVER['SERVER_PORT']) {
6631
                $isSecured = true;
6632
            }
6633
        }
6634
    }
6635
6636
    return $isSecured;
6637
}
6638
6639
/**
6640
 * Return protocol (http or https).
6641
 *
6642
 * @return string
6643
 */
6644
function api_get_protocol()
6645
{
6646
    return api_is_https() ? 'https' : 'http';
6647
}
6648
6649
/**
6650
 * Get origin.
6651
 *
6652
 * @param string
6653
 *
6654
 * @return string
6655
 */
6656
function api_get_origin()
6657
{
6658
    return isset($_REQUEST['origin']) ? urlencode(Security::remove_XSS(urlencode($_REQUEST['origin']))) : '';
6659
}
6660
6661
/**
6662
 * Warns an user that the portal reach certain limit.
6663
 *
6664
 * @param string $limitName
6665
 */
6666
function api_warn_hosting_contact($limitName)
6667
{
6668
    $hostingParams = api_get_configuration_value(1);
6669
    $email = null;
6670
6671
    if (!empty($hostingParams)) {
6672
        if (isset($hostingParams['hosting_contact_mail'])) {
6673
            $email = $hostingParams['hosting_contact_mail'];
6674
        }
6675
    }
6676
6677
    if (!empty($email)) {
6678
        $subject = get_lang('Hosting warning reached');
6679
        $body = get_lang('Portal name').': '.api_get_path(WEB_PATH)." \n ";
6680
        $body .= get_lang('Portal\'s limit type').': '.$limitName." \n ";
6681
        if (isset($hostingParams[$limitName])) {
6682
            $body .= get_lang('Value').': '.$hostingParams[$limitName];
6683
        }
6684
        api_mail_html(null, $email, $subject, $body);
6685
    }
6686
}
6687
6688
/**
6689
 * Gets value of a variable from config/configuration.php
6690
 * Variables that are not set in the configuration.php file but set elsewhere:
6691
 * - virtual_css_theme_folder (vchamilo plugin)
6692
 * - access_url (global.inc.php)
6693
 * - apc/apc_prefix (global.inc.php).
6694
 *
6695
 * @param string $variable
6696
 *
6697
 * @return bool|mixed
6698
 */
6699
function api_get_configuration_value($variable)
6700
{
6701
    global $_configuration;
6702
    // Check the current url id, id = 1 by default
6703
    $urlId = isset($_configuration['access_url']) ? (int) $_configuration['access_url'] : 1;
6704
6705
    $variable = trim($variable);
6706
6707
    // Check if variable exists
6708
    if (isset($_configuration[$variable])) {
6709
        if (is_array($_configuration[$variable])) {
6710
            // Check if it exists for the sub portal
6711
            if (array_key_exists($urlId, $_configuration[$variable])) {
6712
                return $_configuration[$variable][$urlId];
6713
            } else {
6714
                // Try to found element with id = 1 (master portal)
6715
                if (array_key_exists(1, $_configuration[$variable])) {
6716
                    return $_configuration[$variable][1];
6717
                }
6718
            }
6719
        }
6720
6721
        return $_configuration[$variable];
6722
    }
6723
6724
    return false;
6725
}
6726
6727
/**
6728
 * Retreives and returns a value in a hierarchical configuration array
6729
 * api_get_configuration_sub_value('a/b/c') returns api_get_configuration_value('a')['b']['c'].
6730
 *
6731
 * @param string $path      the successive array keys, separated by the separator
6732
 * @param mixed  $default   value to be returned if not found, null by default
6733
 * @param string $separator '/' by default
6734
 * @param array  $array     the active configuration array by default
6735
 *
6736
 * @return mixed the found value or $default
6737
 */
6738
function api_get_configuration_sub_value($path, $default = null, $separator = '/', $array = null)
6739
{
6740
    $pos = strpos($path, $separator);
6741
    if (false === $pos) {
6742
        if (is_null($array)) {
6743
            return api_get_configuration_value($path);
6744
        }
6745
        if (is_array($array) && array_key_exists($path, $array)) {
6746
            return $array[$path];
6747
        }
6748
6749
        return $default;
6750
    }
6751
    $key = substr($path, 0, $pos);
6752
    if (is_null($array)) {
6753
        $newArray = api_get_configuration_value($key);
6754
    } elseif (is_array($array) && array_key_exists($key, $array)) {
6755
        $newArray = $array[$key];
6756
    } else {
6757
        return $default;
6758
    }
6759
    if (is_array($newArray)) {
6760
        $newPath = substr($path, $pos + 1);
6761
6762
        return api_get_configuration_sub_value($newPath, $default, $separator, $newArray);
6763
    }
6764
6765
    return $default;
6766
}
6767
6768
/**
6769
 * Retrieves and returns a value in a hierarchical configuration array
6770
 * api_array_sub_value($array, 'a/b/c') returns $array['a']['b']['c'].
6771
 *
6772
 * @param array  $array     the recursive array that contains the value to be returned (or not)
6773
 * @param string $path      the successive array keys, separated by the separator
6774
 * @param mixed  $default   the value to be returned if not found
6775
 * @param string $separator the separator substring
6776
 *
6777
 * @return mixed the found value or $default
6778
 */
6779
function api_array_sub_value($array, $path, $default = null, $separator = '/')
6780
{
6781
    $pos = strpos($path, $separator);
6782
    if (false === $pos) {
6783
        if (is_array($array) && array_key_exists($path, $array)) {
6784
            return $array[$path];
6785
        }
6786
6787
        return $default;
6788
    }
6789
    $key = substr($path, 0, $pos);
6790
    if (is_array($array) && array_key_exists($key, $array)) {
6791
        $newArray = $array[$key];
6792
    } else {
6793
        return $default;
6794
    }
6795
    if (is_array($newArray)) {
6796
        $newPath = substr($path, $pos + 1);
6797
6798
        return api_array_sub_value($newArray, $newPath, $default);
6799
    }
6800
6801
    return $default;
6802
}
6803
6804
/**
6805
 * Returns supported image extensions in the portal.
6806
 *
6807
 * @param bool $supportVectors Whether vector images should also be accepted or not
6808
 *
6809
 * @return array Supported image extensions in the portal
6810
 */
6811
function api_get_supported_image_extensions($supportVectors = true)
6812
{
6813
    // jpg can also be called jpeg, jpe, jfif and jif. See https://en.wikipedia.org/wiki/JPEG#JPEG_filename_extensions
6814
    $supportedImageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'jpe', 'jfif', 'jif'];
6815
    if ($supportVectors) {
6816
        array_push($supportedImageExtensions, 'svg');
6817
    }
6818
    if (version_compare(PHP_VERSION, '5.5.0', '>=')) {
6819
        array_push($supportedImageExtensions, 'webp');
6820
    }
6821
6822
    return $supportedImageExtensions;
6823
}
6824
6825
/**
6826
 * This setting changes the registration status for the campus.
6827
 *
6828
 * @author Patrick Cool <[email protected]>, Ghent University
6829
 *
6830
 * @version August 2006
6831
 *
6832
 * @param bool $listCampus Whether we authorize
6833
 *
6834
 * @todo the $_settings should be reloaded here. => write api function for this and use this in global.inc.php also.
6835
 */
6836
function api_register_campus($listCampus = true)
6837
{
6838
    $tbl_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
6839
6840
    $sql = "UPDATE $tbl_settings SET selected_value='true' WHERE variable='registered'";
6841
    Database::query($sql);
6842
6843
    if (!$listCampus) {
6844
        $sql = "UPDATE $tbl_settings SET selected_value='true' WHERE variable='donotlistcampus'";
6845
        Database::query($sql);
6846
    }
6847
}
6848
6849
/**
6850
 * Check whether the user type should be exclude.
6851
 * Such as invited or anonymous users.
6852
 *
6853
 * @param bool $checkDB Optional. Whether check the user status
6854
 * @param int  $userId  Options. The user id
6855
 *
6856
 * @return bool
6857
 */
6858
function api_is_excluded_user_type($checkDB = false, $userId = 0)
6859
{
6860
    if ($checkDB) {
6861
        $userId = empty($userId) ? api_get_user_id() : (int) $userId;
6862
6863
        if (0 == $userId) {
6864
            return true;
6865
        }
6866
6867
        $userInfo = api_get_user_info($userId);
6868
6869
        switch ($userInfo['status']) {
6870
            case INVITEE:
6871
            case ANONYMOUS:
6872
                return true;
6873
            default:
6874
                return false;
6875
        }
6876
    }
6877
6878
    $isInvited = api_is_invitee();
6879
    $isAnonymous = api_is_anonymous();
6880
6881
    if ($isInvited || $isAnonymous) {
6882
        return true;
6883
    }
6884
6885
    return false;
6886
}
6887
6888
/**
6889
 * Get the user status to ignore in reports.
6890
 *
6891
 * @param string $format Optional. The result type (array or string)
6892
 *
6893
 * @return array|string
6894
 */
6895
function api_get_users_status_ignored_in_reports($format = 'array')
6896
{
6897
    $excludedTypes = [
6898
        INVITEE,
6899
        ANONYMOUS,
6900
    ];
6901
6902
    if ('string' == $format) {
6903
        return implode(', ', $excludedTypes);
6904
    }
6905
6906
    return $excludedTypes;
6907
}
6908
6909
/**
6910
 * Set the Site Use Cookie Warning for 1 year.
6911
 */
6912
function api_set_site_use_cookie_warning_cookie()
6913
{
6914
    setcookie('ChamiloUsesCookies', 'ok', time() + 31556926);
6915
}
6916
6917
/**
6918
 * Return true if the Site Use Cookie Warning Cookie warning exists.
6919
 *
6920
 * @return bool
6921
 */
6922
function api_site_use_cookie_warning_cookie_exist()
6923
{
6924
    return isset($_COOKIE['ChamiloUsesCookies']);
6925
}
6926
6927
/**
6928
 * Given a number of seconds, format the time to show hours, minutes and seconds.
6929
 *
6930
 * @param int    $time         The time in seconds
6931
 * @param string $originFormat Optional. PHP o JS
6932
 *
6933
 * @return string (00h00'00")
6934
 */
6935
function api_format_time($time, $originFormat = 'php')
6936
{
6937
    $h = get_lang('h');
6938
    $hours = $time / 3600;
6939
    $mins = ($time % 3600) / 60;
6940
    $secs = ($time % 60);
6941
6942
    if ($time < 0) {
6943
        $hours = 0;
6944
        $mins = 0;
6945
        $secs = 0;
6946
    }
6947
6948
    if ('js' === $originFormat) {
6949
        $formattedTime = trim(sprintf("%02d : %02d : %02d", $hours, $mins, $secs));
6950
    } else {
6951
        $formattedTime = trim(sprintf("%02d$h%02d'%02d\"", $hours, $mins, $secs));
6952
    }
6953
6954
    return $formattedTime;
6955
}
6956
6957
/**
6958
 * Sends an email
6959
 * Sender name and email can be specified, if not specified
6960
 * name and email of the platform admin are used.
6961
 *
6962
 * @param string    name of recipient
6963
 * @param string    email of recipient
6964
 * @param string    email subject
6965
 * @param string    email body
6966
 * @param string    sender name
6967
 * @param string    sender e-mail
6968
 * @param array     extra headers in form $headers = array($name => $value) to allow parsing
6969
 * @param array     data file (path and filename)
6970
 * @param bool      True for attaching a embedded file inside content html (optional)
6971
 * @param array     Additional parameters
6972
 *
6973
 * @return bool true if mail was sent
6974
 */
6975
function api_mail_html(
6976
    $recipientName,
6977
    $recipientEmail,
6978
    $subject,
6979
    $body,
6980
    $senderName = '',
6981
    $senderEmail = '',
6982
    $extra_headers = [],
6983
    $data_file = [],
6984
    $embeddedImage = false,
6985
    $additionalParameters = []
6986
) {
6987
    if (!api_valid_email($recipientEmail)) {
6988
        return false;
6989
    }
6990
6991
    // Default values
6992
    $notification = new Notification();
6993
    $defaultEmail = $notification->getDefaultPlatformSenderEmail();
6994
    $defaultName = $notification->getDefaultPlatformSenderName();
6995
6996
    // If the parameter is set don't use the admin.
6997
    $senderName = !empty($senderName) ? $senderName : $defaultName;
6998
    $senderEmail = !empty($senderEmail) ? $senderEmail : $defaultEmail;
6999
7000
    // Reply to first
7001
    $replyToName = '';
7002
    $replyToEmail = '';
7003
    if (isset($extra_headers['reply_to'])) {
7004
        $replyToEmail = $extra_headers['reply_to']['mail'];
7005
        $replyToName = $extra_headers['reply_to']['name'];
7006
    }
7007
7008
    try {
7009
        $bus = Container::getMessengerBus();
7010
        //$sendMessage = new \Chamilo\CoreBundle\Message\SendMessage();
7011
        //$bus->dispatch($sendMessage);
7012
7013
        $message = new TemplatedEmail();
7014
        $message->subject($subject);
7015
7016
        $list = api_get_configuration_value('send_all_emails_to');
7017
        if (!empty($list) && isset($list['emails'])) {
7018
            foreach ($list['emails'] as $email) {
7019
                $message->cc($email);
7020
            }
7021
        }
7022
7023
        // Attachment
7024
        if (!empty($data_file)) {
7025
            foreach ($data_file as $file_attach) {
7026
                if (!empty($file_attach['path']) && !empty($file_attach['filename'])) {
7027
                    $message->attachFromPath($file_attach['path'], $file_attach['filename']);
7028
                }
7029
            }
7030
        }
7031
7032
        $noReply = api_get_setting('noreply_email_address');
7033
        $automaticEmailText = '';
7034
        if (!empty($noReply)) {
7035
            $automaticEmailText = '<br />'.get_lang('This is an automatic email message. Please do not reply to it.');
7036
        }
7037
7038
        $params = [
7039
            'mail_header_style' => api_get_configuration_value('mail_header_style'),
7040
            'mail_content_style' => api_get_configuration_value('mail_content_style'),
7041
            'link' => $additionalParameters['link'] ?? '',
7042
            'automatic_email_text' => $automaticEmailText,
7043
            'content' => $body,
7044
            'theme' => api_get_visual_theme(),
7045
        ];
7046
7047
        if (!empty($senderEmail)) {
7048
            $message->from(new Address($senderEmail, $senderName));
7049
        }
7050
7051
        if (!empty($recipientEmail)) {
7052
            $message->to(new Address($recipientEmail, $recipientName));
7053
        }
7054
7055
        if (!empty($replyToEmail)) {
7056
            $message->replyTo(new Address($replyToEmail, $replyToName));
7057
        }
7058
7059
        $message
7060
            ->htmlTemplate('@ChamiloCore/Mailer/Default/default.html.twig')
7061
            ->textTemplate('@ChamiloCore/Mailer/Default/default.text.twig')
7062
        ;
7063
        $message->context($params);
7064
        Container::getMailer()->send($message);
7065
7066
        return true;
7067
    } catch (Exception $e) {
7068
        error_log($e->getMessage());
7069
    }
7070
7071
    return 1;
7072
}
7073
7074
/**
7075
 * @param int  $tool       Possible values: GroupManager::GROUP_TOOL_*
7076
 * @param bool $showHeader
7077
 */
7078
function api_protect_course_group($tool, $showHeader = true)
7079
{
7080
    $groupId = api_get_group_id();
7081
    if (!empty($groupId)) {
7082
        if (api_is_platform_admin()) {
7083
            return true;
7084
        }
7085
7086
        if (api_is_allowed_to_edit(false, true, true)) {
7087
            return true;
7088
        }
7089
7090
        $userId = api_get_user_id();
7091
        $sessionId = api_get_session_id();
7092
        if (!empty($sessionId)) {
7093
            if (api_is_coach($sessionId, api_get_course_int_id())) {
7094
                return true;
7095
            }
7096
7097
            if (api_is_drh()) {
7098
                if (SessionManager::isUserSubscribedAsHRM($sessionId, $userId)) {
7099
                    return true;
7100
                }
7101
            }
7102
        }
7103
7104
        $group = api_get_group_entity($groupId);
7105
7106
        // Group doesn't exists
7107
        if (null === $group) {
7108
            api_not_allowed($showHeader);
7109
        }
7110
7111
        // Check group access
7112
        $allow = GroupManager::userHasAccess(
7113
            $userId,
7114
            $group,
7115
            $tool
7116
        );
7117
7118
        if (!$allow) {
7119
            api_not_allowed($showHeader);
7120
        }
7121
    }
7122
7123
    return false;
7124
}
7125
7126
/**
7127
 * Check if a date is in a date range.
7128
 *
7129
 * @param datetime $startDate
7130
 * @param datetime $endDate
7131
 * @param datetime $currentDate
7132
 *
7133
 * @return bool true if date is in rage, false otherwise
7134
 */
7135
function api_is_date_in_date_range($startDate, $endDate, $currentDate = null)
7136
{
7137
    $startDate = strtotime(api_get_local_time($startDate));
7138
    $endDate = strtotime(api_get_local_time($endDate));
7139
    $currentDate = strtotime(api_get_local_time($currentDate));
7140
7141
    if ($currentDate >= $startDate && $currentDate <= $endDate) {
7142
        return true;
7143
    }
7144
7145
    return false;
7146
}
7147
7148
/**
7149
 * Eliminate the duplicates of a multidimensional array by sending the key.
7150
 *
7151
 * @param array $array multidimensional array
7152
 * @param int   $key   key to find to compare
7153
 *
7154
 * @return array
7155
 */
7156
function api_unique_multidim_array($array, $key)
7157
{
7158
    $temp_array = [];
7159
    $i = 0;
7160
    $key_array = [];
7161
7162
    foreach ($array as $val) {
7163
        if (!in_array($val[$key], $key_array)) {
7164
            $key_array[$i] = $val[$key];
7165
            $temp_array[$i] = $val;
7166
        }
7167
        $i++;
7168
    }
7169
7170
    return $temp_array;
7171
}
7172
7173
/**
7174
 * Limit the access to Session Admins when the limit_session_admin_role
7175
 * configuration variable is set to true.
7176
 */
7177
function api_protect_limit_for_session_admin()
7178
{
7179
    $limitAdmin = api_get_setting('limit_session_admin_role');
7180
    if (api_is_session_admin() && 'true' === $limitAdmin) {
7181
        api_not_allowed(true);
7182
    }
7183
}
7184
7185
/**
7186
 * Limits that a session admin has access to list users.
7187
 * When limit_session_admin_list_users configuration variable is set to true.
7188
 */
7189
function api_protect_session_admin_list_users()
7190
{
7191
    $limitAdmin = api_get_configuration_value('limit_session_admin_list_users');
7192
7193
    if (api_is_session_admin() && true === $limitAdmin) {
7194
        api_not_allowed(true);
7195
    }
7196
}
7197
7198
/**
7199
 * @return bool
7200
 */
7201
function api_is_student_view_active()
7202
{
7203
    $studentView = Session::read('studentview');
7204
7205
    return 'studentview' === $studentView;
7206
}
7207
7208
/**
7209
 * Converts string value to float value.
7210
 *
7211
 * 3.141516 => 3.141516
7212
 * 3,141516 => 3.141516
7213
 *
7214
 * @todo WIP
7215
 *
7216
 * @param string $number
7217
 *
7218
 * @return float
7219
 */
7220
function api_float_val($number)
7221
{
7222
    return (float) str_replace(',', '.', trim($number));
7223
}
7224
7225
/**
7226
 * Converts float values
7227
 * Example if $decimals = 2.
7228
 *
7229
 * 3.141516 => 3.14
7230
 * 3,141516 => 3,14
7231
 *
7232
 * @param string $number            number in iso code
7233
 * @param int    $decimals
7234
 * @param string $decimalSeparator
7235
 * @param string $thousandSeparator
7236
 *
7237
 * @return bool|string
7238
 */
7239
function api_number_format($number, $decimals = 0, $decimalSeparator = '.', $thousandSeparator = ',')
7240
{
7241
    $number = api_float_val($number);
7242
7243
    return number_format($number, $decimals, $decimalSeparator, $thousandSeparator);
7244
}
7245
7246
/**
7247
 * Set location url with a exit break by default.
7248
 *
7249
 * @param string $url
7250
 * @param bool   $exit
7251
 */
7252
function api_location($url, $exit = true)
7253
{
7254
    header('Location: '.$url);
7255
7256
    if ($exit) {
7257
        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...
7258
    }
7259
}
7260
7261
/**
7262
 * @param string $from
7263
 * @param string $to
7264
 *
7265
 * @return string
7266
 */
7267
function api_get_relative_path($from, $to)
7268
{
7269
    // some compatibility fixes for Windows paths
7270
    $from = is_dir($from) ? rtrim($from, '\/').'/' : $from;
7271
    $to = is_dir($to) ? rtrim($to, '\/').'/' : $to;
7272
    $from = str_replace('\\', '/', $from);
7273
    $to = str_replace('\\', '/', $to);
7274
7275
    $from = explode('/', $from);
7276
    $to = explode('/', $to);
7277
    $relPath = $to;
7278
7279
    foreach ($from as $depth => $dir) {
7280
        // find first non-matching dir
7281
        if ($dir === $to[$depth]) {
7282
            // ignore this directory
7283
            array_shift($relPath);
7284
        } else {
7285
            // get number of remaining dirs to $from
7286
            $remaining = count($from) - $depth;
7287
            if ($remaining > 1) {
7288
                // add traversals up to first matching dir
7289
                $padLength = (count($relPath) + $remaining - 1) * -1;
7290
                $relPath = array_pad($relPath, $padLength, '..');
7291
                break;
7292
            } else {
7293
                $relPath[0] = './'.$relPath[0];
7294
            }
7295
        }
7296
    }
7297
7298
    return implode('/', $relPath);
7299
}
7300
7301
/**
7302
 * @param string $template
7303
 *
7304
 * @return string
7305
 */
7306
function api_find_template($template)
7307
{
7308
    return Template::findTemplateFilePath($template);
7309
}
7310
7311
/**
7312
 * @return array
7313
 */
7314
function api_get_language_list_for_flag()
7315
{
7316
    $table = Database::get_main_table(TABLE_MAIN_LANGUAGE);
7317
    $sql = "SELECT english_name, isocode FROM $table
7318
            ORDER BY original_name ASC";
7319
    static $languages = [];
7320
    if (empty($languages)) {
7321
        $result = Database::query($sql);
7322
        while ($row = Database::fetch_array($result)) {
7323
            $languages[$row['english_name']] = $row['isocode'];
7324
        }
7325
        $languages['english'] = 'gb';
7326
    }
7327
7328
    return $languages;
7329
}
7330
7331
function api_create_zip(string $name): ZipStream
7332
{
7333
    $zipStreamOptions = new Archive();
7334
    $zipStreamOptions->setSendHttpHeaders(true);
7335
    $zipStreamOptions->setContentDisposition('attachment');
7336
    $zipStreamOptions->setContentType('application/x-zip');
7337
7338
    return new ZipStream($name, $zipStreamOptions);
7339
}
7340
7341
function api_get_language_translate_html(): string
7342
{
7343
    $translate = 'true' === api_get_setting('editor.translate_html');
7344
7345
    if (!$translate) {
7346
        return '';
7347
    }
7348
7349
    /*$languageList = api_get_languages();
7350
    $hideAll = '';
7351
    foreach ($languageList as $isocode => $name) {
7352
        $hideAll .= '
7353
        $(".mce-translatehtml").hide();
7354
        $("span:lang('.$isocode.')").filter(
7355
            function(e, val) {
7356
                // Only find the spans if they have set the lang
7357
                if ($(this).attr("lang") == null) {
7358
                    return false;
7359
                }
7360
                // Ignore ckeditor classes
7361
                return !this.className.match(/cke(.*)/);
7362
        }).hide();'."\n";
7363
    }*/
7364
7365
    $userInfo = api_get_user_info();
7366
    if (!empty($userInfo['language'])) {
7367
        $isoCode = $userInfo['language'];
7368
7369
        return '
7370
            $(function() {
7371
                $(".mce-translatehtml").hide();
7372
                var defaultLanguageFromUser = "'.$isoCode.'";
7373
                $("span:lang('.$isoCode.')").show();
7374
            });
7375
        ';
7376
    }
7377
7378
    return '';
7379
}
7380
7381
function api_protect_webservices()
7382
{
7383
    if (api_get_configuration_value('disable_webservices')) {
7384
        echo "Webservices are disabled. \n";
7385
        echo "To enable, add \$_configuration['disable_webservices'] = true; in configuration.php";
7386
        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...
7387
    }
7388
}
7389