Passed
Push — master ( b1e54d...4a0c08 )
by Julito
07:58
created

api_unserialize_content()   B

Complexity

Conditions 7
Paths 12

Size

Total Lines 78
Code Lines 68

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 68
c 0
b 0
f 0
nc 12
nop 3
dl 0
loc 78
rs 7.7648

How to fix   Long Method   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
use Chamilo\CoreBundle\Entity\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', '7.4');
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
// CONSTANT defining the default HotPotatoes files directory
179
define('DIR_HOTPOTATOES', '/HotPotatoes_files');
180
181
// event logs types
182
define('LOG_COURSE_DELETE', 'course_deleted');
183
define('LOG_COURSE_CREATE', 'course_created');
184
define('LOG_COURSE_SETTINGS_CHANGED', 'course_settings_changed');
185
186
// @todo replace 'soc_gr' with social_group
187
define('LOG_GROUP_PORTAL_CREATED', 'soc_gr_created');
188
define('LOG_GROUP_PORTAL_UPDATED', 'soc_gr_updated');
189
define('LOG_GROUP_PORTAL_DELETED', 'soc_gr_deleted');
190
define('LOG_GROUP_PORTAL_USER_DELETE_ALL', 'soc_gr_delete_users');
191
192
define('LOG_GROUP_PORTAL_ID', 'soc_gr_portal_id');
193
define('LOG_GROUP_PORTAL_REL_USER_ARRAY', 'soc_gr_user_array');
194
195
define('LOG_GROUP_PORTAL_USER_SUBSCRIBED', 'soc_gr_u_subs');
196
define('LOG_GROUP_PORTAL_USER_UNSUBSCRIBED', 'soc_gr_u_unsubs');
197
define('LOG_GROUP_PORTAL_USER_UPDATE_ROLE', 'soc_gr_update_role');
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
// iconv extension, for PHP5 on Windows it is installed by default.
308
define('ICONV_INSTALLED', function_exists('iconv'));
309
define('MBSTRING_INSTALLED', function_exists('mb_strlen')); // mbstring extension.
310
311
// Patterns for processing paths. Examples.
312
define('REPEATED_SLASHES_PURIFIER', '/\/{2,}/'); // $path = preg_replace(REPEATED_SLASHES_PURIFIER, '/', $path);
313
define('VALID_WEB_PATH', '/https?:\/\/[^\/]*(\/.*)?/i'); // $is_valid_path = preg_match(VALID_WEB_PATH, $path);
314
// $new_path = preg_replace(VALID_WEB_SERVER_BASE, $new_base, $path);
315
define('VALID_WEB_SERVER_BASE', '/https?:\/\/[^\/]*/i');
316
// Constants for api_get_path() and api_get_path_type(), etc. - registered path types.
317
// basic (leaf elements)
318
define('REL_CODE_PATH', 'REL_CODE_PATH');
319
define('REL_COURSE_PATH', 'REL_COURSE_PATH');
320
define('REL_HOME_PATH', 'REL_HOME_PATH');
321
322
// Constants for api_get_path() and api_get_path_type(), etc. - registered path types.
323
define('WEB_PATH', 'WEB_PATH');
324
define('SYS_PATH', 'SYS_PATH');
325
define('SYMFONY_SYS_PATH', 'SYMFONY_SYS_PATH');
326
//define('SYS_UPLOAD_PATH', 'SYS_UPLOAD_PATH');
327
//define('WEB_UPLOAD_PATH', 'WEB_UPLOAD_PATH');
328
329
define('REL_PATH', 'REL_PATH');
330
define('WEB_COURSE_PATH', 'WEB_COURSE_PATH');
331
define('WEB_CODE_PATH', 'WEB_CODE_PATH');
332
define('SYS_CODE_PATH', 'SYS_CODE_PATH');
333
define('SYS_LANG_PATH', 'SYS_LANG_PATH');
334
define('WEB_IMG_PATH', 'WEB_IMG_PATH');
335
define('WEB_CSS_PATH', 'WEB_CSS_PATH');
336
define('WEB_PUBLIC_PATH', 'WEB_PUBLIC_PATH');
337
define('SYS_CSS_PATH', 'SYS_CSS_PATH');
338
define('SYS_PLUGIN_PATH', 'SYS_PLUGIN_PATH');
339
define('WEB_PLUGIN_PATH', 'WEB_PLUGIN_PATH');
340
define('WEB_PLUGIN_ASSET_PATH', 'WEB_PLUGIN_ASSET_PATH');
341
define('SYS_ARCHIVE_PATH', 'SYS_ARCHIVE_PATH');
342
define('WEB_ARCHIVE_PATH', 'WEB_ARCHIVE_PATH');
343
define('LIBRARY_PATH', 'LIBRARY_PATH');
344
define('CONFIGURATION_PATH', 'CONFIGURATION_PATH');
345
define('WEB_LIBRARY_PATH', 'WEB_LIBRARY_PATH');
346
define('WEB_LIBRARY_JS_PATH', 'WEB_LIBRARY_JS_PATH');
347
define('WEB_AJAX_PATH', 'WEB_AJAX_PATH');
348
define('SYS_TEST_PATH', 'SYS_TEST_PATH');
349
define('SYS_TEMPLATE_PATH', 'SYS_TEMPLATE_PATH');
350
define('SYS_PUBLIC_PATH', 'SYS_PUBLIC_PATH');
351
define('SYS_FONTS_PATH', 'SYS_FONTS_PATH');
352
353
// Relations type with Course manager
354
define('COURSE_RELATION_TYPE_COURSE_MANAGER', 1);
355
define('SESSION_RELATION_TYPE_COURSE_MANAGER', 1);
356
357
// Relations type with Human resources manager
358
define('COURSE_RELATION_TYPE_RRHH', 1);
359
define('SESSION_RELATION_TYPE_RRHH', 1);
360
361
//User image sizes
362
define('USER_IMAGE_SIZE_ORIGINAL', 1);
363
define('USER_IMAGE_SIZE_BIG', 2);
364
define('USER_IMAGE_SIZE_MEDIUM', 3);
365
define('USER_IMAGE_SIZE_SMALL', 4);
366
367
// Relation type between users
368
define('USER_UNKNOWN', 0);
369
define('USER_RELATION_TYPE_UNKNOWN', 1);
370
define('USER_RELATION_TYPE_PARENT', 2); // should be deprecated is useless
371
define('USER_RELATION_TYPE_FRIEND', 3);
372
define('USER_RELATION_TYPE_GOODFRIEND', 4); // should be deprecated is useless
373
define('USER_RELATION_TYPE_ENEMY', 5); // should be deprecated is useless
374
define('USER_RELATION_TYPE_DELETED', 6);
375
define('USER_RELATION_TYPE_RRHH', 7);
376
define('USER_RELATION_TYPE_BOSS', 8);
377
define('USER_RELATION_TYPE_HRM_REQUEST', 9);
378
379
// Gradebook link constants
380
// Please do not change existing values, they are used in the database !
381
define('GRADEBOOK_ITEM_LIMIT', 1000);
382
383
define('LINK_EXERCISE', 1);
384
define('LINK_DROPBOX', 2);
385
define('LINK_STUDENTPUBLICATION', 3);
386
define('LINK_LEARNPATH', 4);
387
define('LINK_FORUM_THREAD', 5);
388
//define('LINK_WORK',6);
389
define('LINK_ATTENDANCE', 7);
390
define('LINK_SURVEY', 8);
391
define('LINK_HOTPOTATOES', 9);
392
define('LINK_PORTFOLIO', 10);
393
394
// Score display types constants
395
define('SCORE_DIV', 1); // X / Y
396
define('SCORE_PERCENT', 2); // XX %
397
define('SCORE_DIV_PERCENT', 3); // X / Y (XX %)
398
define('SCORE_AVERAGE', 4); // XX %
399
define('SCORE_DECIMAL', 5); // 0.50  (X/Y)
400
define('SCORE_BAR', 6); // Uses the Display::bar_progress function
401
define('SCORE_SIMPLE', 7); // X
402
define('SCORE_IGNORE_SPLIT', 8); //  ??
403
define('SCORE_DIV_PERCENT_WITH_CUSTOM', 9); // X / Y (XX %) - Good!
404
define('SCORE_CUSTOM', 10); // Good!
405
define('SCORE_DIV_SIMPLE_WITH_CUSTOM', 11); // X - Good!
406
define('SCORE_DIV_SIMPLE_WITH_CUSTOM_LETTERS', 12); // X - Good!
407
define('SCORE_ONLY_SCORE', 13); // X - Good!
408
define('SCORE_NUMERIC', 14);
409
410
define('SCORE_BOTH', 1);
411
define('SCORE_ONLY_DEFAULT', 2);
412
define('SCORE_ONLY_CUSTOM', 3);
413
414
// From display.lib.php
415
416
define('MAX_LENGTH_BREADCRUMB', 100);
417
define('ICON_SIZE_ATOM', 8);
418
define('ICON_SIZE_TINY', 16);
419
define('ICON_SIZE_SMALL', 22);
420
define('ICON_SIZE_MEDIUM', 32);
421
define('ICON_SIZE_LARGE', 48);
422
define('ICON_SIZE_BIG', 64);
423
define('ICON_SIZE_HUGE', 128);
424
define('SHOW_TEXT_NEAR_ICONS', false);
425
426
// Session catalog
427
define('CATALOG_COURSES', 0);
428
define('CATALOG_SESSIONS', 1);
429
define('CATALOG_COURSES_SESSIONS', 2);
430
431
// Hook type events, pre-process and post-process.
432
// All means to be executed for both hook event types
433
define('HOOK_EVENT_TYPE_PRE', 0);
434
define('HOOK_EVENT_TYPE_POST', 1);
435
define('HOOK_EVENT_TYPE_ALL', 10);
436
437
// Group permissions
438
define('GROUP_PERMISSION_OPEN', '1');
439
define('GROUP_PERMISSION_CLOSED', '2');
440
441
// Group user permissions
442
define('GROUP_USER_PERMISSION_ADMIN', 1); // the admin of a group
443
define('GROUP_USER_PERMISSION_READER', 2); // a normal user
444
define('GROUP_USER_PERMISSION_PENDING_INVITATION', 3); // When an admin/moderator invites a user
445
define('GROUP_USER_PERMISSION_PENDING_INVITATION_SENT_BY_USER', 4); // an user joins a group
446
define('GROUP_USER_PERMISSION_MODERATOR', 5); // a moderator
447
define('GROUP_USER_PERMISSION_ANONYMOUS', 6); // an anonymous user
448
define('GROUP_USER_PERMISSION_HRM', 7); // a human resources manager
449
450
define('GROUP_IMAGE_SIZE_ORIGINAL', 1);
451
define('GROUP_IMAGE_SIZE_BIG', 2);
452
define('GROUP_IMAGE_SIZE_MEDIUM', 3);
453
define('GROUP_IMAGE_SIZE_SMALL', 4);
454
define('GROUP_TITLE_LENGTH', 50);
455
456
// Exercise
457
// @todo move into a class
458
define('ALL_ON_ONE_PAGE', 1);
459
define('ONE_PER_PAGE', 2);
460
461
define('EXERCISE_FEEDBACK_TYPE_END', 0); //Feedback 		 - show score and expected answers
462
define('EXERCISE_FEEDBACK_TYPE_DIRECT', 1); //DirectFeedback - Do not show score nor answers
463
define('EXERCISE_FEEDBACK_TYPE_EXAM', 2); // NoFeedback 	 - Show score only
464
define('EXERCISE_FEEDBACK_TYPE_POPUP', 3); // Popup BT#15827
465
466
define('RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS', 0); //show score and expected answers
467
define('RESULT_DISABLE_NO_SCORE_AND_EXPECTED_ANSWERS', 1); //Do not show score nor answers
468
define('RESULT_DISABLE_SHOW_SCORE_ONLY', 2); //Show score only
469
define('RESULT_DISABLE_SHOW_FINAL_SCORE_ONLY_WITH_CATEGORIES', 3); //Show final score only with categories
470
define('RESULT_DISABLE_SHOW_SCORE_ATTEMPT_SHOW_ANSWERS_LAST_ATTEMPT', 4);
471
define('RESULT_DISABLE_DONT_SHOW_SCORE_ONLY_IF_USER_FINISHES_ATTEMPTS_SHOW_ALWAYS_FEEDBACK', 5);
472
define('RESULT_DISABLE_RANKING', 6);
473
define('RESULT_DISABLE_SHOW_ONLY_IN_CORRECT_ANSWER', 7);
474
define('RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS_AND_RANKING', 8);
475
define('RESULT_DISABLE_RADAR', 9);
476
define('RESULT_DISABLE_SHOW_SCORE_ATTEMPT_SHOW_ANSWERS_LAST_ATTEMPT_NO_FEEDBACK', 10);
477
478
define('EXERCISE_MAX_NAME_SIZE', 80);
479
480
// Question types (edit next array as well when adding values)
481
// @todo move into a class
482
define('UNIQUE_ANSWER', 1);
483
define('MULTIPLE_ANSWER', 2);
484
define('FILL_IN_BLANKS', 3);
485
define('MATCHING', 4);
486
define('FREE_ANSWER', 5);
487
define('HOT_SPOT', 6);
488
define('HOT_SPOT_ORDER', 7);
489
define('HOT_SPOT_DELINEATION', 8);
490
define('MULTIPLE_ANSWER_COMBINATION', 9);
491
define('UNIQUE_ANSWER_NO_OPTION', 10);
492
define('MULTIPLE_ANSWER_TRUE_FALSE', 11);
493
define('MULTIPLE_ANSWER_COMBINATION_TRUE_FALSE', 12);
494
define('ORAL_EXPRESSION', 13);
495
define('GLOBAL_MULTIPLE_ANSWER', 14);
496
define('MEDIA_QUESTION', 15);
497
define('CALCULATED_ANSWER', 16);
498
define('UNIQUE_ANSWER_IMAGE', 17);
499
define('DRAGGABLE', 18);
500
define('MATCHING_DRAGGABLE', 19);
501
define('ANNOTATION', 20);
502
define('READING_COMPREHENSION', 21);
503
define('MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY', 22);
504
505
define('EXERCISE_CATEGORY_RANDOM_SHUFFLED', 1);
506
define('EXERCISE_CATEGORY_RANDOM_ORDERED', 2);
507
define('EXERCISE_CATEGORY_RANDOM_DISABLED', 0);
508
509
// Question selection type
510
define('EX_Q_SELECTION_ORDERED', 1);
511
define('EX_Q_SELECTION_RANDOM', 2);
512
define('EX_Q_SELECTION_CATEGORIES_ORDERED_QUESTIONS_ORDERED', 3);
513
define('EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_ORDERED', 4);
514
define('EX_Q_SELECTION_CATEGORIES_ORDERED_QUESTIONS_RANDOM', 5);
515
define('EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_RANDOM', 6);
516
define('EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_ORDERED_NO_GROUPED', 7);
517
define('EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_RANDOM_NO_GROUPED', 8);
518
define('EX_Q_SELECTION_CATEGORIES_ORDERED_BY_PARENT_QUESTIONS_ORDERED', 9);
519
define('EX_Q_SELECTION_CATEGORIES_ORDERED_BY_PARENT_QUESTIONS_RANDOM', 10);
520
521
// Used to save the skill_rel_item table
522
define('ITEM_TYPE_EXERCISE', 1);
523
define('ITEM_TYPE_HOTPOTATOES', 2);
524
define('ITEM_TYPE_LINK', 3);
525
define('ITEM_TYPE_LEARNPATH', 4);
526
define('ITEM_TYPE_GRADEBOOK', 5);
527
define('ITEM_TYPE_STUDENT_PUBLICATION', 6);
528
//define('ITEM_TYPE_FORUM', 7);
529
define('ITEM_TYPE_ATTENDANCE', 8);
530
define('ITEM_TYPE_SURVEY', 9);
531
define('ITEM_TYPE_FORUM_THREAD', 10);
532
define('ITEM_TYPE_PORTFOLIO', 11);
533
534
// Course description blocks.
535
define('ADD_BLOCK', 8);
536
537
// one big string with all question types, for the validator in pear/HTML/QuickForm/Rule/QuestionType
538
define(
539
    'QUESTION_TYPES',
540
    UNIQUE_ANSWER.':'.
541
    MULTIPLE_ANSWER.':'.
542
    FILL_IN_BLANKS.':'.
543
    MATCHING.':'.
544
    FREE_ANSWER.':'.
545
    HOT_SPOT.':'.
546
    HOT_SPOT_ORDER.':'.
547
    HOT_SPOT_DELINEATION.':'.
548
    MULTIPLE_ANSWER_COMBINATION.':'.
549
    UNIQUE_ANSWER_NO_OPTION.':'.
550
    MULTIPLE_ANSWER_TRUE_FALSE.':'.
551
    MULTIPLE_ANSWER_COMBINATION_TRUE_FALSE.':'.
552
    ORAL_EXPRESSION.':'.
553
    GLOBAL_MULTIPLE_ANSWER.':'.
554
    MEDIA_QUESTION.':'.
555
    CALCULATED_ANSWER.':'.
556
    UNIQUE_ANSWER_IMAGE.':'.
557
    DRAGGABLE.':'.
558
    MATCHING_DRAGGABLE.':'.
559
    MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY.':'.
560
    ANNOTATION
561
);
562
563
//Some alias used in the QTI exports
564
define('MCUA', 1);
565
define('TF', 1);
566
define('MCMA', 2);
567
define('FIB', 3);
568
569
// Skills
570
define('SKILL_TYPE_REQUIREMENT', 'required');
571
define('SKILL_TYPE_ACQUIRED', 'acquired');
572
define('SKILL_TYPE_BOTH', 'both');
573
574
// Message
575
define('MESSAGE_STATUS_NEW', 0);
576
define('MESSAGE_STATUS_UNREAD', 1);
577
//2 ??
578
define('MESSAGE_STATUS_DELETED', 3);
579
define('MESSAGE_STATUS_OUTBOX', 4);
580
define('MESSAGE_STATUS_INVITATION_PENDING', 5);
581
define('MESSAGE_STATUS_INVITATION_ACCEPTED', 6);
582
define('MESSAGE_STATUS_INVITATION_DENIED', 7);
583
define('MESSAGE_STATUS_WALL', 8);
584
define('MESSAGE_STATUS_WALL_DELETE', 9);
585
define('MESSAGE_STATUS_WALL_POST', 10);
586
define('MESSAGE_STATUS_CONVERSATION', 11);
587
define('MESSAGE_STATUS_FORUM', 12);
588
define('MESSAGE_STATUS_PROMOTED', 13);
589
590
// Images
591
define('IMAGE_WALL_SMALL_SIZE', 200);
592
define('IMAGE_WALL_MEDIUM_SIZE', 500);
593
define('IMAGE_WALL_BIG_SIZE', 2000);
594
define('IMAGE_WALL_SMALL', 'small');
595
define('IMAGE_WALL_MEDIUM', 'medium');
596
define('IMAGE_WALL_BIG', 'big');
597
598
// Social PLUGIN PLACES
599
define('SOCIAL_LEFT_PLUGIN', 1);
600
define('SOCIAL_CENTER_PLUGIN', 2);
601
define('SOCIAL_RIGHT_PLUGIN', 3);
602
define('CUT_GROUP_NAME', 50);
603
604
/**
605
 * FormValidator Filter.
606
 */
607
define('NO_HTML', 1);
608
define('STUDENT_HTML', 2);
609
define('TEACHER_HTML', 3);
610
define('STUDENT_HTML_FULLPAGE', 4);
611
define('TEACHER_HTML_FULLPAGE', 5);
612
613
// Timeline
614
define('TIMELINE_STATUS_ACTIVE', '1');
615
define('TIMELINE_STATUS_INACTIVE', '2');
616
617
// Event email template class
618
define('EVENT_EMAIL_TEMPLATE_ACTIVE', 1);
619
define('EVENT_EMAIL_TEMPLATE_INACTIVE', 0);
620
621
// Course home
622
define('SHORTCUTS_HORIZONTAL', 0);
623
define('SHORTCUTS_VERTICAL', 1);
624
625
// Image class
626
define('IMAGE_PROCESSOR', 'gd'); // 'imagick' or 'gd' strings
627
628
// Course copy
629
define('FILE_SKIP', 1);
630
define('FILE_RENAME', 2);
631
define('FILE_OVERWRITE', 3);
632
define('UTF8_CONVERT', false); //false by default
633
634
define('DOCUMENT', 'file');
635
define('FOLDER', 'folder');
636
637
define('RESOURCE_ASSET', 'asset');
638
define('RESOURCE_DOCUMENT', 'document');
639
define('RESOURCE_GLOSSARY', 'glossary');
640
define('RESOURCE_EVENT', 'calendar_event');
641
define('RESOURCE_LINK', 'link');
642
define('RESOURCE_COURSEDESCRIPTION', 'course_description');
643
define('RESOURCE_LEARNPATH', 'learnpath');
644
define('RESOURCE_LEARNPATH_CATEGORY', 'learnpath_category');
645
define('RESOURCE_ANNOUNCEMENT', 'announcement');
646
define('RESOURCE_FORUM', 'forum');
647
define('RESOURCE_FORUMTOPIC', 'thread');
648
define('RESOURCE_FORUMPOST', 'post');
649
define('RESOURCE_QUIZ', 'quiz');
650
define('RESOURCE_TEST_CATEGORY', 'test_category');
651
define('RESOURCE_QUIZQUESTION', 'Exercise_Question');
652
define('RESOURCE_TOOL_INTRO', 'Tool introduction');
653
define('RESOURCE_LINKCATEGORY', 'Link_Category');
654
define('RESOURCE_FORUMCATEGORY', 'Forum_Category');
655
define('RESOURCE_SCORM', 'Scorm');
656
define('RESOURCE_SURVEY', 'survey');
657
define('RESOURCE_SURVEYQUESTION', 'survey_question');
658
define('RESOURCE_SURVEYINVITATION', 'survey_invitation');
659
define('RESOURCE_WIKI', 'wiki');
660
define('RESOURCE_THEMATIC', 'thematic');
661
define('RESOURCE_ATTENDANCE', 'attendance');
662
define('RESOURCE_WORK', 'work');
663
define('RESOURCE_SESSION_COURSE', 'session_course');
664
define('RESOURCE_GRADEBOOK', 'gradebook');
665
define('ADD_THEMATIC_PLAN', 6);
666
667
// Max online users to show per page (whoisonline)
668
define('MAX_ONLINE_USERS', 12);
669
670
// Number of characters maximum to show in preview of course blog posts
671
define('BLOG_MAX_PREVIEW_CHARS', 800);
672
// HTML string to replace with a 'Read more...' link
673
define('BLOG_PAGE_BREAK', '<div style="page-break-after: always"><span style="display: none;">&nbsp;</span></div>');
674
675
// Make sure the CHAMILO_LOAD_WYSIWYG constant is defined
676
// To remove CKeditor libs from HTML, set this constant to true before loading
677
if (!defined('CHAMILO_LOAD_WYSIWYG')) {
678
    define('CHAMILO_LOAD_WYSIWYG', true);
679
}
680
681
/* Constants for course home */
682
define('TOOL_PUBLIC', 'Public');
683
define('TOOL_PUBLIC_BUT_HIDDEN', 'PublicButHide');
684
define('TOOL_COURSE_ADMIN', 'courseAdmin');
685
define('TOOL_PLATFORM_ADMIN', 'platformAdmin');
686
define('TOOL_AUTHORING', 'toolauthoring');
687
define('TOOL_INTERACTION', 'toolinteraction');
688
define('TOOL_COURSE_PLUGIN', 'toolcourseplugin'); //all plugins that can be enabled in courses
689
define('TOOL_ADMIN', 'tooladmin');
690
define('TOOL_ADMIN_PLATFORM', 'tooladminplatform');
691
define('TOOL_DRH', 'tool_drh');
692
define('TOOL_STUDENT_VIEW', 'toolstudentview');
693
define('TOOL_ADMIN_VISIBLE', 'tooladminvisible');
694
695
// Search settings (from main/inc/lib/search/IndexableChunk.class.php )
696
// some constants to avoid serialize string keys on serialized data array
697
define('SE_COURSE_ID', 0);
698
define('SE_TOOL_ID', 1);
699
define('SE_DATA', 2);
700
define('SE_USER', 3);
701
702
// in some cases we need top differenciate xapian documents of the same tool
703
define('SE_DOCTYPE_EXERCISE_EXERCISE', 0);
704
define('SE_DOCTYPE_EXERCISE_QUESTION', 1);
705
706
// xapian prefixes
707
define('XAPIAN_PREFIX_COURSEID', 'C');
708
define('XAPIAN_PREFIX_TOOLID', 'O');
709
710
/**
711
 * Returns a path to a certain resource within the Chamilo area, specifyed through a parameter.
712
 * Also, this function provides conversion between path types, in this case the input path points inside the Chamilo area too.
713
 *
714
 * See $_configuration['course_folder'] in the configuration.php to alter the WEB_COURSE_PATH and SYS_COURSE_PATH parameters.
715
716
 *
717
 * @param string $path (optional)   A path which type is to be converted. Also, it may be a defined constant for a path.
718
 *                     This parameter has meaning when $type parameter has one of the following values: TO_WEB, TO_SYS, TO_REL. Otherwise it is ignored.
719
 *
720
 * @return string the requested path or the converted path
721
 *
722
 * Notes about the current behaviour model:
723
 * 1. Windows back-slashes are converted to slashes in the result.
724
 * 2. A semi-absolute web-path is detected by its leading slash. On Linux systems, absolute system paths start with
725
 * a slash too, so an additional check about presence of leading system server base is implemented. For example, the function is
726
 * able to distinguish type difference between /var/www/chamilo/courses/ (SYS) and /chamilo/courses/ (REL).
727
 * 3. The function api_get_path() returns only these three types of paths, which in some sense are absolute. The function has
728
 * no a mechanism for processing relative web/system paths, such as: lesson01.html, ./lesson01.html, ../css/my_styles.css.
729
 * It has not been identified as needed yet.
730
 * 4. Also, resolving the meta-symbols "." and ".." within paths has not been implemented, it is to be identified as needed.
731
 *
732
 * For examples go to: *
733
 * See main/admin/system_status.php?section=paths
734
 *
735
 * Vchamilo changes : allow using an alternate configuration
736
 * to get vchamilo  instance paths
737
 */
738
function api_get_path($path = '', $configuration = [])
739
{
740
    global $paths;
741
742
    // get proper configuration data if exists
743
    global $_configuration;
744
745
    $emptyConfigurationParam = false;
746
    if (empty($configuration)) {
747
        $configuration = (array) $_configuration;
748
        $emptyConfigurationParam = true;
749
    }
750
751
    $root_sys = Container::getProjectDir();
752
753
    $root_web = '';
754
    // If no $root_web has been set so far *and* no custom config has been passed to the function
755
    // then re-use the previously-calculated (run-specific) $root_web and skip this complex calculation
756
    /*
757
    if (empty($root_web) || $emptyConfigurationParam === false || empty($configuration)) {
758
        // Resolve master hostname.
759
        if (!empty($configuration) && array_key_exists('root_web', $configuration)) {
760
            $root_web = $configuration['root_web'];
761
        } else {
762
            $root_web = '';
763
            // Try guess it from server.
764
            if (defined('SYSTEM_INSTALLATION') && SYSTEM_INSTALLATION) {
765
                if (($pos = strpos(($requested_page_rel = api_get_self()), 'main/install')) !== false) {
766
                    $root_rel = substr($requested_page_rel, 0, $pos);
767
                    // See http://www.mediawiki.org/wiki/Manual:$wgServer
768
                    $server_protocol = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https' : 'http';
769
                    $server_name =
770
                        isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME']
771
                            : (isset($_SERVER['HOSTNAME']) ? $_SERVER['HOSTNAME']
772
                            : (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST']
773
                                : (isset($_SERVER['SERVER_ADDR']) ? $_SERVER['SERVER_ADDR']
774
                                    : 'localhost')));
775
                    if (isset($_SERVER['SERVER_PORT']) && !strpos($server_name, ':')
776
                        && (($server_protocol == 'http'
777
                                && $_SERVER['SERVER_PORT'] != 80) || ($server_protocol == 'https' && $_SERVER['SERVER_PORT'] != 443))
778
                    ) {
779
                        $server_name .= ":".$_SERVER['SERVER_PORT'];
780
                    }
781
                    $root_web = $server_protocol.'://'.$server_name.$root_rel;
782
                    $root_sys = str_replace('\\', '/', realpath(__DIR__.'/../../../')).'/';
783
                }
784
                // Here we give up, so we don't touch anything.
785
            }
786
        }
787
    }*/
788
    if (isset(Container::$container)) {
789
        $root_web = Container::$container->get('router')->generate(
790
            'index',
791
            [],
792
            UrlGeneratorInterface::ABSOLUTE_URL
793
        );
794
    }
795
796
    if (isset($configuration['multiple_access_urls']) &&
797
        $configuration['multiple_access_urls']
798
    ) {
799
        // To avoid that the api_get_access_url() function fails since global.inc.php also calls the main_api.lib.php
800
        if (isset($configuration['access_url']) && !empty($configuration['access_url'])) {
801
            // We look into the DB the function api_get_access_url
802
            $urlInfo = api_get_access_url($configuration['access_url']);
803
            // Avoid default value
804
            $defaultValues = ['http://localhost/', 'https://localhost/'];
805
            if (!empty($urlInfo['url']) && !in_array($urlInfo['url'], $defaultValues)) {
806
                $root_web = 1 == $urlInfo['active'] ? $urlInfo['url'] : $configuration['root_web'];
807
            }
808
        }
809
    }
810
811
    $paths = [
812
        WEB_PATH => $root_web,
813
        SYMFONY_SYS_PATH => $root_sys,
814
        SYS_PATH => $root_sys.'public/',
815
        REL_PATH => '',
816
        CONFIGURATION_PATH => 'app/config/',
817
        LIBRARY_PATH => $root_sys.'public/main/inc/lib/',
818
819
        REL_COURSE_PATH => '',
820
        REL_CODE_PATH => '/main/',
821
822
        SYS_CODE_PATH => $root_sys.'public/main/',
823
        SYS_CSS_PATH => $root_sys.'public/build/css/',
824
        SYS_PLUGIN_PATH => $root_sys.'public/plugin/',
825
        SYS_ARCHIVE_PATH => $root_sys.'var/cache/',
826
       // SYS_UPLOAD_PATH => 'var/upload/',
827
        SYS_TEST_PATH => $root_sys.'tests/',
828
        SYS_TEMPLATE_PATH => $root_sys.'public/main/template/',
829
        SYS_PUBLIC_PATH => $root_sys.'public/',
830
        SYS_FONTS_PATH => $root_sys.'public/fonts/',
831
832
        WEB_CODE_PATH => $root_web.'main/',
833
        WEB_PLUGIN_ASSET_PATH => $root_web.'plugins/',
834
        WEB_COURSE_PATH => $root_web.'course/',
835
        WEB_IMG_PATH => $root_web.'img/',
836
        WEB_CSS_PATH => $root_web.'build/css/',
837
        WEB_AJAX_PATH => $root_web.'main/inc/ajax/',
838
        WEB_LIBRARY_PATH => $root_web.'main/inc/lib/',
839
        WEB_LIBRARY_JS_PATH => $root_web.'main/inc/lib/javascript/',
840
        WEB_PLUGIN_PATH => $root_web.'plugin/',
841
       // WEB_ARCHIVE_PATH => 'var/cache/',
842
        //WEB_UPLOAD_PATH => 'var/upload/',
843
        WEB_PUBLIC_PATH => $root_web,
844
    ];
845
846
    $root_rel = '';
847
848
    // Dealing with trailing slashes.
849
    $rootWebWithSlash = api_add_trailing_slash($root_web);
850
    $root_sys = api_add_trailing_slash($root_sys);
851
    $root_rel = api_add_trailing_slash($root_rel);
852
853
    global $virtualChamilo;
854
    if (!empty($virtualChamilo)) {
855
        $paths[SYS_ARCHIVE_PATH] = api_add_trailing_slash($virtualChamilo[SYS_ARCHIVE_PATH]);
856
        $paths[SYS_UPLOAD_PATH] = api_add_trailing_slash($virtualChamilo[SYS_UPLOAD_PATH]);
0 ignored issues
show
Bug introduced by
The constant SYS_UPLOAD_PATH was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
857
        //$paths[$root_web][WEB_UPLOAD_PATH] = api_add_trailing_slash($virtualChamilo[WEB_UPLOAD_PATH]);
858
        $paths[WEB_ARCHIVE_PATH] = api_add_trailing_slash($virtualChamilo[WEB_ARCHIVE_PATH]);
859
        //$paths[$root_web][WEB_COURSE_PATH] = api_add_trailing_slash($virtualChamilo[WEB_COURSE_PATH]);
860
861
        // WEB_UPLOAD_PATH should be handle by apache htaccess in the vhost
862
863
        // RewriteEngine On
864
        // RewriteRule /app/upload/(.*)$ http://localhost/other/upload/my-chamilo111-net/$1 [QSA,L]
865
866
        //$paths[$root_web][WEB_UPLOAD_PATH] = api_add_trailing_slash($virtualChamilo[WEB_UPLOAD_PATH]);
867
        //$paths[$root_web][REL_PATH] = $virtualChamilo[REL_PATH];
868
        //$paths[$root_web][REL_COURSE_PATH] = $virtualChamilo[REL_COURSE_PATH];
869
    }
870
871
    $path = trim($path);
872
873
    // Retrieving a common-purpose path.
874
    if (isset($paths[$path])) {
875
        return $paths[$path];
876
    }
877
878
    return false;
879
}
880
881
/**
882
 * Adds to a given path a trailing slash if it is necessary (adds "/" character at the end of the string).
883
 *
884
 * @param string $path the input path
885
 *
886
 * @return string returns the modified path
887
 */
888
function api_add_trailing_slash($path)
889
{
890
    return '/' == substr($path, -1) ? $path : $path.'/';
891
}
892
893
/**
894
 * Removes from a given path the trailing slash if it is necessary (removes "/" character from the end of the string).
895
 *
896
 * @param string $path the input path
897
 *
898
 * @return string returns the modified path
899
 */
900
function api_remove_trailing_slash($path)
901
{
902
    return '/' == substr($path, -1) ? substr($path, 0, -1) : $path;
903
}
904
905
/**
906
 * Checks the RFC 3986 syntax of a given URL.
907
 *
908
 * @param string $url      the URL to be checked
909
 * @param bool   $absolute whether the URL is absolute (beginning with a scheme such as "http:")
910
 *
911
 * @return string|false Returns the URL if it is valid, FALSE otherwise.
912
 *                      This function is an adaptation from the function valid_url(), Drupal CMS.
913
 *
914
 * @see http://drupal.org
915
 * Note: The built-in function filter_var($urs, FILTER_VALIDATE_URL) has a bug for some versions of PHP.
916
 * @see http://bugs.php.net/51192
917
 */
918
function api_valid_url($url, $absolute = false)
919
{
920
    if ($absolute) {
921
        if (preg_match("
922
            /^                                                      # Start at the beginning of the text
923
            (?:ftp|https?|feed):\/\/                                # Look for ftp, http, https or feed schemes
924
            (?:                                                     # Userinfo (optional) which is typically
925
                (?:(?:[\w\.\-\+!$&'\(\)*\+,;=]|%[0-9a-f]{2})+:)*    # a username or a username and password
926
                (?:[\w\.\-\+%!$&'\(\)*\+,;=]|%[0-9a-f]{2})+@        # combination
927
            )?
928
            (?:
929
                (?:[a-z0-9\-\.]|%[0-9a-f]{2})+                      # A domain name or a IPv4 address
930
                |(?:\[(?:[0-9a-f]{0,4}:)*(?:[0-9a-f]{0,4})\])       # or a well formed IPv6 address
931
            )
932
            (?::[0-9]+)?                                            # Server port number (optional)
933
            (?:[\/|\?]
934
                (?:[\w#!:\.\?\+=&@$'~*,;\/\(\)\[\]\-]|%[0-9a-f]{2}) # The path and query (optional)
935
            *)?
936
            $/xi", $url)) {
937
            return $url;
938
        }
939
940
        return false;
941
    } else {
942
        return preg_match("/^(?:[\w#!:\.\?\+=&@$'~*,;\/\(\)\[\]\-]|%[0-9a-f]{2})+$/i", $url) ? $url : false;
943
    }
944
}
945
946
/**
947
 * Checks whether a given string looks roughly like an email address.
948
 *
949
 * @param string $address the e-mail address to be checked
950
 *
951
 * @return mixed returns the e-mail if it is valid, FALSE otherwise
952
 */
953
function api_valid_email($address)
954
{
955
    return filter_var($address, FILTER_VALIDATE_EMAIL);
956
}
957
958
/* PROTECTION FUNCTIONS
959
   Use these functions to protect your scripts. */
960
961
/**
962
 * Function used to protect a course script.
963
 * The function blocks access when
964
 * - there is no $_SESSION["_course"] defined; or
965
 * - $is_allowed_in_course is set to false (this depends on the course
966
 * visibility and user status).
967
 *
968
 * This is only the first proposal, test and improve!
969
 *
970
 * @param bool Option to print headers when displaying error message. Default: false
971
 * @param bool whether session admins should be allowed or not
972
 * @param string $checkTool check if tool is available for users (user, group)
973
 *
974
 * @return bool True if the user has access to the current course or is out of a course context, false otherwise
975
 *
976
 * @todo replace global variable
977
 *
978
 * @author Roan Embrechts
979
 */
980
function api_protect_course_script($print_headers = false, $allow_session_admins = false, $checkTool = '')
981
{
982
    $course_info = api_get_course_info();
983
    if (empty($course_info)) {
984
        api_not_allowed($print_headers);
985
986
        return false;
987
    }
988
989
    if (api_is_drh()) {
990
        return true;
991
    }
992
993
    // Session admin has access to course
994
    $sessionAccess = api_get_configuration_value('session_admins_access_all_content');
995
    if ($sessionAccess) {
996
        $allow_session_admins = true;
997
    }
998
999
    if (api_is_platform_admin($allow_session_admins)) {
1000
        return true;
1001
    }
1002
1003
    $isAllowedInCourse = api_is_allowed_in_course();
1004
    $is_visible = false;
1005
    if (isset($course_info) && isset($course_info['visibility'])) {
1006
        switch ($course_info['visibility']) {
1007
            default:
1008
            case COURSE_VISIBILITY_CLOSED:
1009
                // Completely closed: the course is only accessible to the teachers. - 0
1010
                if ($isAllowedInCourse && api_get_user_id() && !api_is_anonymous()) {
1011
                    $is_visible = true;
1012
                }
1013
                break;
1014
            case COURSE_VISIBILITY_REGISTERED:
1015
                // Private - access authorized to course members only - 1
1016
                if ($isAllowedInCourse && api_get_user_id() && !api_is_anonymous()) {
1017
                    $is_visible = true;
1018
                }
1019
                break;
1020
            case COURSE_VISIBILITY_OPEN_PLATFORM:
1021
                // Open - access allowed for users registered on the platform - 2
1022
                if ($isAllowedInCourse && api_get_user_id() && !api_is_anonymous()) {
1023
                    $is_visible = true;
1024
                }
1025
                break;
1026
            case COURSE_VISIBILITY_OPEN_WORLD:
1027
                //Open - access allowed for the whole world - 3
1028
                $is_visible = true;
1029
                break;
1030
            case COURSE_VISIBILITY_HIDDEN:
1031
                //Completely closed: the course is only accessible to the teachers. - 0
1032
                if (api_is_platform_admin()) {
1033
                    $is_visible = true;
1034
                }
1035
                break;
1036
        }
1037
1038
        //If password is set and user is not registered to the course then the course is not visible
1039
        if (false === $isAllowedInCourse &&
1040
            isset($course_info['registration_code']) &&
1041
            !empty($course_info['registration_code'])
1042
        ) {
1043
            $is_visible = false;
1044
        }
1045
    }
1046
1047
    if (!empty($checkTool)) {
1048
        if (!api_is_allowed_to_edit(true, true, true)) {
1049
            $toolInfo = api_get_tool_information_by_name($checkTool);
1050
            if (!empty($toolInfo) && isset($toolInfo['visibility']) && 0 == $toolInfo['visibility']) {
1051
                api_not_allowed(true);
1052
1053
                return false;
1054
            }
1055
        }
1056
    }
1057
1058
    // Check session visibility
1059
    $session_id = api_get_session_id();
1060
1061
    if (!empty($session_id)) {
1062
        // $isAllowedInCourse was set in local.inc.php
1063
        if (!$isAllowedInCourse) {
1064
            $is_visible = false;
1065
        }
1066
    }
1067
1068
    if (!$is_visible) {
1069
        api_not_allowed($print_headers);
1070
1071
        return false;
1072
    }
1073
1074
    if ($is_visible && 'true' === api_get_plugin_setting('positioning', 'tool_enable')) {
1075
        $plugin = Positioning::create();
1076
        $block = $plugin->get('block_course_if_initial_exercise_not_attempted');
1077
        if ('true' === $block) {
1078
            $currentPath = $_SERVER['PHP_SELF'];
1079
            // Allowed only this course paths.
1080
            $paths = [
1081
                '/plugin/positioning/start.php',
1082
                '/plugin/positioning/start_student.php',
1083
                '/main/course_home/course_home.php',
1084
                '/main/exercise/overview.php',
1085
            ];
1086
1087
            if (!in_array($currentPath, $paths, true)) {
1088
                // Check if entering an exercise.
1089
                // @todo remove global $current_course_tool
1090
                /*global $current_course_tool;
1091
                if ('quiz' !== $current_course_tool) {
1092
                    $initialData = $plugin->getInitialExercise($course_info['real_id'], $session_id);
1093
                    if ($initialData && isset($initialData['exercise_id'])) {
1094
                        $results = Event::getExerciseResultsByUser(
1095
                            api_get_user_id(),
1096
                            $initialData['exercise_id'],
1097
                            $course_info['real_id'],
1098
                            $session_id
1099
                        );
1100
                        if (empty($results)) {
1101
                            api_not_allowed($print_headers);
1102
1103
                            return false;
1104
                        }
1105
                    }
1106
                }*/
1107
            }
1108
        }
1109
    }
1110
1111
    api_block_inactive_user();
1112
1113
    return true;
1114
}
1115
1116
/**
1117
 * Function used to protect an admin script.
1118
 *
1119
 * The function blocks access when the user has no platform admin rights
1120
 * with an error message printed on default output
1121
 *
1122
 * @param bool Whether to allow session admins as well
1123
 * @param bool Whether to allow HR directors as well
1124
 * @param string An optional message (already passed through get_lang)
1125
 *
1126
 * @return bool True if user is allowed, false otherwise.
1127
 *              The function also outputs an error message in case not allowed
1128
 *
1129
 * @author Roan Embrechts (original author)
1130
 */
1131
function api_protect_admin_script($allow_sessions_admins = false, $allow_drh = false, $message = null)
1132
{
1133
    if (!api_is_platform_admin($allow_sessions_admins, $allow_drh)) {
1134
        api_not_allowed(true, $message);
1135
1136
        return false;
1137
    }
1138
    api_block_inactive_user();
1139
1140
    return true;
1141
}
1142
1143
/**
1144
 * Blocks inactive users with a currently active session from accessing more pages "live".
1145
 *
1146
 * @return bool Returns true if the feature is disabled or the user account is still enabled.
1147
 *              Returns false (and shows a message) if the feature is enabled *and* the user is disabled.
1148
 */
1149
function api_block_inactive_user()
1150
{
1151
    $data = true;
1152
    if (1 != api_get_configuration_value('security_block_inactive_users_immediately')) {
1153
        return $data;
1154
    }
1155
1156
    $userId = api_get_user_id();
1157
    $homeUrl = api_get_path(WEB_PATH);
1158
    if (0 == $userId) {
1159
        return $data;
1160
    }
1161
1162
    $sql = "SELECT active FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1163
            WHERE id = $userId";
1164
1165
    $result = Database::query($sql);
1166
    if (Database::num_rows($result) > 0) {
1167
        $result_array = Database::fetch_array($result);
1168
        $data = (bool) $result_array['active'];
1169
    }
1170
    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...
1171
        $tpl = new Template(null, true, true, false, true, false, true, 0);
1172
        $tpl->assign('hide_login_link', 1);
1173
1174
        //api_not_allowed(true, get_lang('AccountInactive'));
1175
        // we were not in a course, return to home page
1176
        $msg = Display::return_message(
1177
            get_lang('AccountInactive'),
1178
            'error',
1179
            false
1180
        );
1181
1182
        $msg .= '<p class="text-center">
1183
                 <a class="btn btn-default" href="'.$homeUrl.'">'.get_lang('BackHome').'</a></p>';
1184
1185
        if (api_is_anonymous()) {
1186
            /*$form = api_get_not_allowed_login_form();
1187
            $msg .= '<div class="well">';
1188
            $msg .= $form->returnForm();
1189
            $msg .= '</div>';*/
1190
        }
1191
1192
        $tpl->assign('content', $msg);
1193
        $tpl->display_one_col_template();
1194
        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...
1195
    }
1196
1197
    return $data;
1198
}
1199
1200
/**
1201
 * Function used to protect a teacher script.
1202
 * The function blocks access when the user has no teacher rights.
1203
 *
1204
 * @return bool True if the current user can access the script, false otherwise
1205
 *
1206
 * @author Yoselyn Castillo
1207
 */
1208
function api_protect_teacher_script()
1209
{
1210
    if (!api_is_allowed_to_edit()) {
1211
        api_not_allowed(true);
1212
1213
        return false;
1214
    }
1215
1216
    return true;
1217
}
1218
1219
/**
1220
 * Function used to prevent anonymous users from accessing a script.
1221
 *
1222
 * @param bool $printHeaders
1223
 *
1224
 * @return bool
1225
 */
1226
function api_block_anonymous_users($printHeaders = true)
1227
{
1228
    $isAuth = Container::getAuthorizationChecker()->isGranted('IS_AUTHENTICATED_FULLY');
1229
1230
    if (false === $isAuth) {
1231
        api_not_allowed($printHeaders);
1232
1233
        return false;
1234
    }
1235
1236
    api_block_inactive_user();
1237
1238
    return true;
1239
1240
    /*$user = api_get_user_info();
1241
    if (!(isset($user['user_id']) && $user['user_id']) || api_is_anonymous($user['user_id'], true)) {
1242
        api_not_allowed($printHeaders);
1243
1244
        return false;
1245
    }
1246
    api_block_inactive_user();
1247
1248
    return true;*/
1249
}
1250
1251
/**
1252
 * Returns a rough evaluation of the browser's name and version based on very
1253
 * simple regexp.
1254
 *
1255
 * @return array with the navigator name and version ['name' => '...', 'version' => '...']
1256
 */
1257
function api_get_navigator()
1258
{
1259
    $navigator = 'Unknown';
1260
    $version = 0;
1261
1262
    if (!isset($_SERVER['HTTP_USER_AGENT'])) {
1263
        return ['name' => 'Unknown', 'version' => '0.0.0'];
1264
    }
1265
1266
    if (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Opera')) {
1267
        $navigator = 'Opera';
1268
        [, $version] = explode('Opera', $_SERVER['HTTP_USER_AGENT']);
1269
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Edge')) {
1270
        $navigator = 'Edge';
1271
        [, $version] = explode('Edge', $_SERVER['HTTP_USER_AGENT']);
1272
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE')) {
1273
        $navigator = 'Internet Explorer';
1274
        [, $version] = explode('MSIE ', $_SERVER['HTTP_USER_AGENT']);
1275
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Chrome')) {
1276
        $navigator = 'Chrome';
1277
        [, $version] = explode('Chrome', $_SERVER['HTTP_USER_AGENT']);
1278
    } elseif (false !== stripos($_SERVER['HTTP_USER_AGENT'], 'Safari')) {
1279
        $navigator = 'Safari';
1280
        if (false !== stripos($_SERVER['HTTP_USER_AGENT'], 'Version/')) {
1281
            // If this Safari does have the "Version/" string in its user agent
1282
            // then use that as a version indicator rather than what's after
1283
            // "Safari/" which is rather a "build number" or something
1284
            [, $version] = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1285
        } else {
1286
            [, $version] = explode('Safari/', $_SERVER['HTTP_USER_AGENT']);
1287
        }
1288
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Firefox')) {
1289
        $navigator = 'Firefox';
1290
        [, $version] = explode('Firefox', $_SERVER['HTTP_USER_AGENT']);
1291
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Netscape')) {
1292
        $navigator = 'Netscape';
1293
        if (false !== stripos($_SERVER['HTTP_USER_AGENT'], 'Netscape/')) {
1294
            [, $version] = explode('Netscape', $_SERVER['HTTP_USER_AGENT']);
1295
        } else {
1296
            [, $version] = explode('Navigator', $_SERVER['HTTP_USER_AGENT']);
1297
        }
1298
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Konqueror')) {
1299
        $navigator = 'Konqueror';
1300
        [, $version] = explode('Konqueror', $_SERVER['HTTP_USER_AGENT']);
1301
    } elseif (false !== stripos($_SERVER['HTTP_USER_AGENT'], 'applewebkit')) {
1302
        $navigator = 'AppleWebKit';
1303
        [, $version] = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1304
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Gecko')) {
1305
        $navigator = 'Mozilla';
1306
        [, $version] = explode('; rv:', $_SERVER['HTTP_USER_AGENT']);
1307
    }
1308
1309
    // Now cut extra stuff around (mostly *after*) the version number
1310
    $version = preg_replace('/^([\/\s])?([\d\.]+)?.*/', '\2', $version);
1311
1312
    if (false === strpos($version, '.')) {
1313
        $version = number_format(doubleval($version), 1);
1314
    }
1315
1316
    return ['name' => $navigator, 'version' => $version];
1317
}
1318
1319
/**
1320
 * @return true if user self registration is allowed, false otherwise
1321
 */
1322
function api_is_self_registration_allowed()
1323
{
1324
    return isset($GLOBALS['allowSelfReg']) ? $GLOBALS['allowSelfReg'] : false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return IssetNode ? $GLOB...'allowSelfReg'] : false could also return false which is incompatible with the documented return type true. Did you maybe forget to handle an error condition?

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

Loading history...
1325
}
1326
1327
/**
1328
 * This function returns the id of the user which is stored in the $_user array.
1329
 *
1330
 * example: The function can be used to check if a user is logged in
1331
 *          if (api_get_user_id())
1332
 *
1333
 * @return int the id of the current user, 0 if is empty
1334
 */
1335
function api_get_user_id()
1336
{
1337
    $userInfo = Session::read('_user');
1338
    if ($userInfo && isset($userInfo['user_id'])) {
1339
        return (int) $userInfo['user_id'];
1340
    }
1341
1342
    return 0;
1343
}
1344
1345
/**
1346
 * Gets the list of courses a specific user is subscribed to.
1347
 *
1348
 * @param int       User ID
1349
 * @param bool $fetch_session Whether to get session courses or not - NOT YET IMPLEMENTED
1350
 *
1351
 * @return array Array of courses in the form [0]=>('code'=>xxx,'db'=>xxx,'dir'=>xxx,'status'=>d)
1352
 *
1353
 * @deprecated use CourseManager::get_courses_list_by_user_id()
1354
 */
1355
function api_get_user_courses($userId, $fetch_session = true)
1356
{
1357
    // Get out if not integer
1358
    if ($userId != strval(intval($userId))) {
1359
        return [];
1360
    }
1361
1362
    $t_course = Database::get_main_table(TABLE_MAIN_COURSE);
1363
    $t_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
1364
1365
    $sql = "SELECT cc.id as real_id, cc.code code, cc.directory dir, cu.status status
1366
            FROM $t_course cc, $t_course_user cu
1367
            WHERE
1368
                cc.id = cu.c_id AND
1369
                cu.user_id = $userId AND
1370
                cu.relation_type <> ".COURSE_RELATION_TYPE_RRHH;
1371
    $result = Database::query($sql);
1372
    if (false === $result) {
1373
        return [];
1374
    }
1375
1376
    $courses = [];
1377
    while ($row = Database::fetch_array($result)) {
1378
        // we only need the database name of the course
1379
        $courses[] = $row;
1380
    }
1381
1382
    return $courses;
1383
}
1384
1385
/**
1386
 * Formats user information into a standard array
1387
 * This function should be only used inside api_get_user_info().
1388
 *
1389
 * @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...
1390
 * @param bool $add_password
1391
 * @param bool $loadAvatars  turn off to improve performance
1392
 *
1393
 * @return array Standard user array
1394
 */
1395
function _api_format_user($user, $add_password = false, $loadAvatars = true)
1396
{
1397
    $result = [];
1398
1399
    if (!isset($user['id'])) {
1400
        return [];
1401
    }
1402
1403
    $result['firstname'] = null;
1404
    $result['lastname'] = null;
1405
1406
    if (isset($user['firstname']) && isset($user['lastname'])) {
1407
        // with only lowercase
1408
        $result['firstname'] = $user['firstname'];
1409
        $result['lastname'] = $user['lastname'];
1410
    } elseif (isset($user['firstName']) && isset($user['lastName'])) {
1411
        // with uppercase letters
1412
        $result['firstname'] = isset($user['firstName']) ? $user['firstName'] : null;
1413
        $result['lastname'] = isset($user['lastName']) ? $user['lastName'] : null;
1414
    }
1415
1416
    if (isset($user['email'])) {
1417
        $result['mail'] = isset($user['email']) ? $user['email'] : null;
1418
        $result['email'] = isset($user['email']) ? $user['email'] : null;
1419
    } else {
1420
        $result['mail'] = isset($user['mail']) ? $user['mail'] : null;
1421
        $result['email'] = isset($user['mail']) ? $user['mail'] : null;
1422
    }
1423
1424
    $result['complete_name'] = api_get_person_name($result['firstname'], $result['lastname']);
1425
    $result['complete_name_with_username'] = $result['complete_name'];
1426
1427
    if (!empty($user['username']) && 'false' === api_get_setting('profile.hide_username_with_complete_name')) {
1428
        $result['complete_name_with_username'] = $result['complete_name'].' ('.$user['username'].')';
1429
    }
1430
1431
    $showEmail = 'true' === api_get_setting('show_email_addresses');
1432
    if (!empty($user['email'])) {
1433
        $result['complete_name_with_email_forced'] = $result['complete_name'].' ('.$user['email'].')';
1434
        if ($showEmail) {
1435
            $result['complete_name_with_email'] = $result['complete_name'].' ('.$user['email'].')';
1436
        }
1437
    } else {
1438
        $result['complete_name_with_email'] = $result['complete_name'];
1439
        $result['complete_name_with_email_forced'] = $result['complete_name'];
1440
    }
1441
1442
    // Kept for historical reasons
1443
    $result['firstName'] = $result['firstname'];
1444
    $result['lastName'] = $result['lastname'];
1445
1446
    $attributes = [
1447
        'phone',
1448
        'address',
1449
        'picture_uri',
1450
        'official_code',
1451
        'status',
1452
        'active',
1453
        'auth_source',
1454
        'username',
1455
        'theme',
1456
        'language',
1457
        'creator_id',
1458
        'registration_date',
1459
        'hr_dept_id',
1460
        'expiration_date',
1461
        'last_login',
1462
        'user_is_online',
1463
    ];
1464
1465
    if ('true' === api_get_setting('extended_profile')) {
1466
        $attributes[] = 'competences';
1467
        $attributes[] = 'diplomas';
1468
        $attributes[] = 'teach';
1469
        $attributes[] = 'openarea';
1470
    }
1471
1472
    foreach ($attributes as $attribute) {
1473
        $result[$attribute] = isset($user[$attribute]) ? $user[$attribute] : null;
1474
    }
1475
1476
    $user_id = (int) $user['id'];
1477
    // Maintain the user_id index for backwards compatibility
1478
    $result['user_id'] = $result['id'] = $user_id;
1479
1480
    $hasCertificates = Certificate::getCertificateByUser($user_id);
1481
    $result['has_certificates'] = 0;
1482
    if (!empty($hasCertificates)) {
1483
        $result['has_certificates'] = 1;
1484
    }
1485
1486
    $result['icon_status'] = '';
1487
    $result['icon_status_medium'] = '';
1488
    $result['is_admin'] = UserManager::is_admin($user_id);
1489
1490
    // Getting user avatar.
1491
    if ($loadAvatars) {
1492
        $result['avatar'] = '';
1493
        $result['avatar_no_query'] = '';
1494
        $result['avatar_small'] = '';
1495
        $result['avatar_medium'] = '';
1496
1497
        /*if (!isset($user['avatar'])) {
1498
            $originalFile = UserManager::getUserPicture(
1499
                $user_id,
1500
                USER_IMAGE_SIZE_ORIGINAL,
1501
                null,
1502
                $result
1503
            );
1504
            $result['avatar'] = $originalFile;
1505
            $avatarString = explode('?', $result['avatar']);
1506
            $result['avatar_no_query'] = reset($avatarString);
1507
        } else {
1508
            $result['avatar'] = $user['avatar'];
1509
            $avatarString = explode('?', $user['avatar']);
1510
            $result['avatar_no_query'] = reset($avatarString);
1511
        }
1512
1513
        if (!isset($user['avatar_small'])) {
1514
            $smallFile = UserManager::getUserPicture(
1515
                $user_id,
1516
                USER_IMAGE_SIZE_SMALL,
1517
                null,
1518
                $result
1519
            );
1520
            $result['avatar_small'] = $smallFile;
1521
        } else {
1522
            $result['avatar_small'] = $user['avatar_small'];
1523
        }
1524
1525
        if (!isset($user['avatar_medium'])) {
1526
            $mediumFile = UserManager::getUserPicture(
1527
                $user_id,
1528
                USER_IMAGE_SIZE_MEDIUM,
1529
                null,
1530
                $result
1531
            );
1532
            $result['avatar_medium'] = $mediumFile;
1533
        } else {
1534
            $result['avatar_medium'] = $user['avatar_medium'];
1535
        }*/
1536
1537
        $urlImg = api_get_path(WEB_IMG_PATH);
1538
        $iconStatus = '';
1539
        $iconStatusMedium = '';
1540
        $label = '';
1541
        switch ($result['status']) {
1542
            case STUDENT:
1543
                if ($result['has_certificates']) {
1544
                    $iconStatus = $urlImg.'icons/svg/identifier_graduated.svg';
1545
                    $label = get_lang('Graduated');
1546
                } else {
1547
                    $iconStatus = $urlImg.'icons/svg/identifier_student.svg';
1548
                    $label = get_lang('Student');
1549
                }
1550
                break;
1551
            case COURSEMANAGER:
1552
                if ($result['is_admin']) {
1553
                    $iconStatus = $urlImg.'icons/svg/identifier_admin.svg';
1554
                    $label = get_lang('Admin');
1555
                } else {
1556
                    $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1557
                    $label = get_lang('Teacher');
1558
                }
1559
                break;
1560
            case STUDENT_BOSS:
1561
                $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1562
                $label = get_lang('StudentBoss');
1563
                break;
1564
        }
1565
1566
        if (!empty($iconStatus)) {
1567
            $iconStatusMedium = '<img src="'.$iconStatus.'" width="32px" height="32px">';
1568
            $iconStatus = '<img src="'.$iconStatus.'" width="22px" height="22px">';
1569
        }
1570
1571
        $result['icon_status'] = $iconStatus;
1572
        $result['icon_status_label'] = $label;
1573
        $result['icon_status_medium'] = $iconStatusMedium;
1574
    }
1575
1576
    if (isset($user['user_is_online'])) {
1577
        $result['user_is_online'] = true == $user['user_is_online'] ? 1 : 0;
1578
    }
1579
    if (isset($user['user_is_online_in_chat'])) {
1580
        $result['user_is_online_in_chat'] = (int) $user['user_is_online_in_chat'];
1581
    }
1582
1583
    if ($add_password) {
1584
        $result['password'] = $user['password'];
1585
    }
1586
1587
    if (isset($result['profile_completed'])) {
1588
        $result['profile_completed'] = $user['profile_completed'];
1589
    }
1590
1591
    $result['profile_url'] = api_get_path(WEB_CODE_PATH).'social/profile.php?u='.$user_id;
1592
1593
    // Send message link
1594
    $sendMessage = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&user_id='.$user_id;
1595
    $result['complete_name_with_message_link'] = Display::url(
1596
        $result['complete_name_with_username'],
1597
        $sendMessage,
1598
        ['class' => 'ajax']
1599
    );
1600
1601
    if (isset($user['extra'])) {
1602
        $result['extra'] = $user['extra'];
1603
    }
1604
1605
    return $result;
1606
}
1607
1608
/**
1609
 * Finds all the information about a user.
1610
 * If no parameter is passed you find all the information about the current user.
1611
 *
1612
 * @param int  $user_id
1613
 * @param bool $checkIfUserOnline
1614
 * @param bool $showPassword
1615
 * @param bool $loadExtraData
1616
 * @param bool $loadOnlyVisibleExtraData Get the user extra fields that are visible
1617
 * @param bool $loadAvatars              turn off to improve performance and if avatars are not needed
1618
 * @param bool $updateCache              update apc cache if exists
1619
 *
1620
 * @return mixed $user_info user_id, lastname, firstname, username, email, etc or false on error
1621
 *
1622
 * @author Patrick Cool <[email protected]>
1623
 * @author Julio Montoya
1624
 *
1625
 * @version 21 September 2004
1626
 */
1627
function api_get_user_info(
1628
    $user_id = 0,
1629
    $checkIfUserOnline = false,
1630
    $showPassword = false,
1631
    $loadExtraData = false,
1632
    $loadOnlyVisibleExtraData = false,
1633
    $loadAvatars = true,
1634
    $updateCache = false
1635
) {
1636
    // Make sure user_id is safe
1637
    $user_id = (int) $user_id;
1638
    $user = false;
1639
    if (empty($user_id)) {
1640
        $userFromSession = Session::read('_user');
1641
        if (isset($userFromSession) && !empty($userFromSession)) {
1642
            return $userFromSession;
1643
            /*
1644
            return _api_format_user(
1645
                $userFromSession,
1646
                $showPassword,
1647
                $loadAvatars
1648
            );*/
1649
        }
1650
1651
        return false;
1652
    }
1653
1654
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1655
            WHERE id = $user_id";
1656
    $result = Database::query($sql);
1657
    if (Database::num_rows($result) > 0) {
1658
        $result_array = Database::fetch_array($result);
1659
        $result_array['user_is_online_in_chat'] = 0;
1660
        if ($checkIfUserOnline) {
1661
            $use_status_in_platform = user_is_online($user_id);
1662
            $result_array['user_is_online'] = $use_status_in_platform;
1663
            $user_online_in_chat = 0;
1664
            if ($use_status_in_platform) {
1665
                $user_status = UserManager::get_extra_user_data_by_field(
1666
                    $user_id,
1667
                    'user_chat_status',
1668
                    false,
1669
                    true
1670
                );
1671
                if (1 == (int) $user_status['user_chat_status']) {
1672
                    $user_online_in_chat = 1;
1673
                }
1674
            }
1675
            $result_array['user_is_online_in_chat'] = $user_online_in_chat;
1676
        }
1677
1678
        if ($loadExtraData) {
1679
            $fieldValue = new ExtraFieldValue('user');
1680
            $result_array['extra'] = $fieldValue->getAllValuesForAnItem(
1681
                $user_id,
1682
                $loadOnlyVisibleExtraData
1683
            );
1684
        }
1685
        $user = _api_format_user($result_array, $showPassword, $loadAvatars);
1686
    }
1687
1688
    return $user;
1689
}
1690
1691
function api_get_user_info_from_entity(
1692
    User $user,
1693
    $checkIfUserOnline = false,
1694
    $showPassword = false,
1695
    $loadExtraData = false,
1696
    $loadOnlyVisibleExtraData = false,
1697
    $loadAvatars = true,
1698
    $loadCertificate = false
1699
) {
1700
    if (!$user instanceof UserInterface) {
1701
        return false;
1702
    }
1703
1704
    // Make sure user_id is safe
1705
    $user_id = (int) $user->getId();
1706
1707
    if (empty($user_id)) {
1708
        $userFromSession = Session::read('_user');
1709
1710
        if (isset($userFromSession) && !empty($userFromSession)) {
1711
            return $userFromSession;
1712
        }
1713
1714
        return false;
1715
    }
1716
1717
    $result = [];
1718
    $result['user_is_online_in_chat'] = 0;
1719
    if ($checkIfUserOnline) {
1720
        $use_status_in_platform = user_is_online($user_id);
1721
        $result['user_is_online'] = $use_status_in_platform;
1722
        $user_online_in_chat = 0;
1723
        if ($use_status_in_platform) {
1724
            $user_status = UserManager::get_extra_user_data_by_field(
1725
                $user_id,
1726
                'user_chat_status',
1727
                false,
1728
                true
1729
            );
1730
            if (1 == (int) $user_status['user_chat_status']) {
1731
                $user_online_in_chat = 1;
1732
            }
1733
        }
1734
        $result['user_is_online_in_chat'] = $user_online_in_chat;
1735
    }
1736
1737
    if ($loadExtraData) {
1738
        $fieldValue = new ExtraFieldValue('user');
1739
        $result['extra'] = $fieldValue->getAllValuesForAnItem(
1740
            $user_id,
1741
            $loadOnlyVisibleExtraData
1742
        );
1743
    }
1744
1745
    $result['username'] = $user->getUsername();
1746
    $result['status'] = $user->getStatus();
1747
    $result['firstname'] = $user->getFirstname();
1748
    $result['lastname'] = $user->getLastname();
1749
    $result['email'] = $result['mail'] = $user->getEmail();
1750
    $result['complete_name'] = api_get_person_name($result['firstname'], $result['lastname']);
1751
    $result['complete_name_with_username'] = $result['complete_name'];
1752
1753
    if (!empty($result['username']) && 'false' === api_get_setting('profile.hide_username_with_complete_name')) {
1754
        $result['complete_name_with_username'] = $result['complete_name'].' ('.$result['username'].')';
1755
    }
1756
1757
    $showEmail = 'true' === api_get_setting('show_email_addresses');
1758
    if (!empty($result['email'])) {
1759
        $result['complete_name_with_email_forced'] = $result['complete_name'].' ('.$result['email'].')';
1760
        if ($showEmail) {
1761
            $result['complete_name_with_email'] = $result['complete_name'].' ('.$result['email'].')';
1762
        }
1763
    } else {
1764
        $result['complete_name_with_email'] = $result['complete_name'];
1765
        $result['complete_name_with_email_forced'] = $result['complete_name'];
1766
    }
1767
1768
    // Kept for historical reasons
1769
    $result['firstName'] = $result['firstname'];
1770
    $result['lastName'] = $result['lastname'];
1771
1772
    $attributes = [
1773
        'picture_uri',
1774
        'last_login',
1775
        'user_is_online',
1776
    ];
1777
1778
    $result['phone'] = $user->getPhone();
1779
    $result['address'] = $user->getAddress();
1780
    $result['official_code'] = $user->getOfficialCode();
1781
    $result['active'] = $user->getActive();
1782
    $result['auth_source'] = $user->getAuthSource();
1783
    $result['language'] = $user->getLocale();
1784
    $result['creator_id'] = $user->getCreatorId();
1785
    $result['registration_date'] = $user->getRegistrationDate()->format('Y-m-d H:i:s');
1786
    $result['hr_dept_id'] = $user->getHrDeptId();
1787
    $result['expiration_date'] = '';
1788
    if ($user->getExpirationDate()) {
1789
        $result['expiration_date'] = $user->getExpirationDate()->format('Y-m-d H:i:s');
1790
    }
1791
1792
    $result['last_login'] = null;
1793
    if ($user->getLastLogin()) {
1794
        $result['last_login'] = $user->getLastLogin()->format('Y-m-d H:i:s');
1795
    }
1796
1797
    $result['competences'] = $user->getCompetences();
1798
    $result['diplomas'] = $user->getDiplomas();
1799
    $result['teach'] = $user->getTeach();
1800
    $result['openarea'] = $user->getOpenarea();
1801
    $user_id = (int) $user->getId();
1802
1803
    // Maintain the user_id index for backwards compatibility
1804
    $result['user_id'] = $result['id'] = $user_id;
1805
1806
    if ($loadCertificate) {
1807
        $hasCertificates = Certificate::getCertificateByUser($user_id);
1808
        $result['has_certificates'] = 0;
1809
        if (!empty($hasCertificates)) {
1810
            $result['has_certificates'] = 1;
1811
        }
1812
    }
1813
1814
    $result['icon_status'] = '';
1815
    $result['icon_status_medium'] = '';
1816
    $result['is_admin'] = UserManager::is_admin($user_id);
1817
1818
    // Getting user avatar.
1819
    if ($loadAvatars) {
1820
        $result['avatar'] = '';
1821
        $result['avatar_no_query'] = '';
1822
        $result['avatar_small'] = '';
1823
        $result['avatar_medium'] = '';
1824
1825
        /*if (!isset($user['avatar'])) {
1826
            $originalFile = UserManager::getUserPicture(
1827
                $user_id,
1828
                USER_IMAGE_SIZE_ORIGINAL,
1829
                null,
1830
                $result
1831
            );
1832
            $result['avatar'] = $originalFile;
1833
            $avatarString = explode('?', $result['avatar']);
1834
            $result['avatar_no_query'] = reset($avatarString);
1835
        } else {
1836
            $result['avatar'] = $user['avatar'];
1837
            $avatarString = explode('?', $user['avatar']);
1838
            $result['avatar_no_query'] = reset($avatarString);
1839
        }
1840
1841
        if (!isset($user['avatar_small'])) {
1842
            $smallFile = UserManager::getUserPicture(
1843
                $user_id,
1844
                USER_IMAGE_SIZE_SMALL,
1845
                null,
1846
                $result
1847
            );
1848
            $result['avatar_small'] = $smallFile;
1849
        } else {
1850
            $result['avatar_small'] = $user['avatar_small'];
1851
        }
1852
1853
        if (!isset($user['avatar_medium'])) {
1854
            $mediumFile = UserManager::getUserPicture(
1855
                $user_id,
1856
                USER_IMAGE_SIZE_MEDIUM,
1857
                null,
1858
                $result
1859
            );
1860
            $result['avatar_medium'] = $mediumFile;
1861
        } else {
1862
            $result['avatar_medium'] = $user['avatar_medium'];
1863
        }*/
1864
1865
        //$urlImg = api_get_path(WEB_IMG_PATH);
1866
        $urlImg = '/';
1867
        $iconStatus = '';
1868
        $iconStatusMedium = '';
1869
1870
        switch ($user->getStatus()) {
1871
            case STUDENT:
1872
                if (isset($result['has_certificates']) && $result['has_certificates']) {
1873
                    $iconStatus = $urlImg.'icons/svg/identifier_graduated.svg';
1874
                } else {
1875
                    $iconStatus = $urlImg.'icons/svg/identifier_student.svg';
1876
                }
1877
                break;
1878
            case COURSEMANAGER:
1879
                if ($result['is_admin']) {
1880
                    $iconStatus = $urlImg.'icons/svg/identifier_admin.svg';
1881
                } else {
1882
                    $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1883
                }
1884
                break;
1885
            case STUDENT_BOSS:
1886
                $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1887
                break;
1888
        }
1889
1890
        if (!empty($iconStatus)) {
1891
            $iconStatusMedium = '<img src="'.$iconStatus.'" width="32px" height="32px">';
1892
            $iconStatus = '<img src="'.$iconStatus.'" width="22px" height="22px">';
1893
        }
1894
1895
        $result['icon_status'] = $iconStatus;
1896
        $result['icon_status_medium'] = $iconStatusMedium;
1897
    }
1898
1899
    if (isset($result['user_is_online'])) {
1900
        $result['user_is_online'] = true == $result['user_is_online'] ? 1 : 0;
1901
    }
1902
    if (isset($result['user_is_online_in_chat'])) {
1903
        $result['user_is_online_in_chat'] = $result['user_is_online_in_chat'];
1904
    }
1905
1906
    $result['password'] = '';
1907
    if ($showPassword) {
1908
        $result['password'] = $user->getPassword();
1909
    }
1910
1911
    if (isset($result['profile_completed'])) {
1912
        $result['profile_completed'] = $result['profile_completed'];
1913
    }
1914
1915
    $result['profile_url'] = api_get_path(WEB_CODE_PATH).'social/profile.php?u='.$user_id;
1916
1917
    // Send message link
1918
    $sendMessage = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&user_id='.$user_id;
1919
    $result['complete_name_with_message_link'] = Display::url(
1920
        $result['complete_name_with_username'],
1921
        $sendMessage,
1922
        ['class' => 'ajax']
1923
    );
1924
1925
    if (isset($result['extra'])) {
1926
        $result['extra'] = $result['extra'];
1927
    }
1928
1929
    return $result;
1930
}
1931
1932
function api_get_lp_entity(int $id): ?CLp
1933
{
1934
    return Database::getManager()->getRepository(CLp::class)->find($id);
1935
}
1936
1937
function api_get_user_entity(int $userId = 0): ?User
1938
{
1939
    $userId = $userId ?: api_get_user_id();
1940
    $repo = UserManager::getRepository();
1941
1942
    /** @var User $user */
1943
    $user = $repo->find($userId);
1944
1945
    return $user;
1946
}
1947
1948
function api_get_current_user(): ?User
1949
{
1950
    $isLoggedIn = Container::$container->get('security.authorization_checker')->isGranted('IS_AUTHENTICATED_REMEMBERED');
0 ignored issues
show
Bug introduced by
The method get() 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

1950
    $isLoggedIn = Container::$container->/** @scrutinizer ignore-call */ get('security.authorization_checker')->isGranted('IS_AUTHENTICATED_REMEMBERED');

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...
1951
    if (false === $isLoggedIn) {
1952
        return null;
1953
    }
1954
1955
    $token = Container::$container->get('security.token_storage')->getToken();
1956
1957
    if (null !== $token) {
1958
        return $token->getUser();
1959
    }
1960
1961
    return null;
1962
}
1963
1964
/**
1965
 * Finds all the information about a user from username instead of user id.
1966
 *
1967
 * @param string $username
1968
 *
1969
 * @return mixed $user_info array user_id, lastname, firstname, username, email or false on error
1970
 *
1971
 * @author Yannick Warnier <[email protected]>
1972
 */
1973
function api_get_user_info_from_username($username)
1974
{
1975
    if (empty($username)) {
1976
        return false;
1977
    }
1978
    $username = trim($username);
1979
1980
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1981
            WHERE username='".Database::escape_string($username)."'";
1982
    $result = Database::query($sql);
1983
    if (Database::num_rows($result) > 0) {
1984
        $resultArray = Database::fetch_array($result);
1985
1986
        return _api_format_user($resultArray);
1987
    }
1988
1989
    return false;
1990
}
1991
1992
/**
1993
 * Get first user with an email.
1994
 *
1995
 * @param string $email
1996
 *
1997
 * @return array|bool
1998
 */
1999
function api_get_user_info_from_email($email = '')
2000
{
2001
    if (empty($email)) {
2002
        return false;
2003
    }
2004
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
2005
            WHERE email ='".Database::escape_string($email)."' LIMIT 1";
2006
    $result = Database::query($sql);
2007
    if (Database::num_rows($result) > 0) {
2008
        $resultArray = Database::fetch_array($result);
2009
2010
        return _api_format_user($resultArray);
2011
    }
2012
2013
    return false;
2014
}
2015
2016
/**
2017
 * @return string
2018
 */
2019
function api_get_course_id()
2020
{
2021
    return Session::read('_cid', null);
2022
}
2023
2024
/**
2025
 * Returns the current course id (integer).
2026
 *
2027
 * @param string $code Optional course code
2028
 *
2029
 * @return int
2030
 */
2031
function api_get_course_int_id($code = null)
2032
{
2033
    if (!empty($code)) {
2034
        $code = Database::escape_string($code);
2035
        $row = Database::select(
2036
            'id',
2037
            Database::get_main_table(TABLE_MAIN_COURSE),
2038
            ['where' => ['code = ?' => [$code]]],
2039
            'first'
2040
        );
2041
2042
        if (is_array($row) && isset($row['id'])) {
2043
            return $row['id'];
2044
        } else {
2045
            return false;
2046
        }
2047
    }
2048
2049
    return Session::read('_real_cid', 0);
2050
}
2051
2052
/**
2053
 * Gets a course setting from the current course_setting table. Try always using integer values.
2054
 *
2055
 * @param string       $settingName The name of the setting we want from the table
2056
 * @param Course|array $courseInfo
2057
 * @param bool         $force       force checking the value in the database
2058
 *
2059
 * @return mixed The value of that setting in that table. Return -1 if not found.
2060
 */
2061
function api_get_course_setting($settingName, $courseInfo = null, $force = false)
2062
{
2063
    if (empty($courseInfo)) {
2064
        $courseInfo = api_get_course_info();
2065
    }
2066
2067
    if (empty($courseInfo) || empty($settingName)) {
2068
        return -1;
2069
    }
2070
2071
    if ($courseInfo instanceof Course) {
2072
        $courseId = $courseInfo->getId();
2073
    } else {
2074
        $courseId = isset($courseInfo['real_id']) && !empty($courseInfo['real_id']) ? $courseInfo['real_id'] : 0;
2075
    }
2076
2077
    if (empty($courseId)) {
2078
        return -1;
2079
    }
2080
2081
    static $courseSettingInfo = [];
2082
2083
    if ($force) {
2084
        $courseSettingInfo = [];
2085
    }
2086
2087
    if (!isset($courseSettingInfo[$courseId])) {
2088
        $table = Database::get_course_table(TABLE_COURSE_SETTING);
2089
        $settingName = Database::escape_string($settingName);
2090
2091
        $sql = "SELECT variable, value FROM $table
2092
                WHERE c_id = $courseId ";
2093
        $res = Database::query($sql);
2094
        if (Database::num_rows($res) > 0) {
2095
            $result = Database::store_result($res, 'ASSOC');
2096
            $courseSettingInfo[$courseId] = array_column($result, 'value', 'variable');
2097
2098
            if (isset($courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'])) {
2099
                $value = $courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'];
2100
                if (!is_null($value)) {
2101
                    $result = explode(',', $value);
2102
                    $courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'] = $result;
2103
                }
2104
            }
2105
        }
2106
    }
2107
2108
    if (isset($courseSettingInfo[$courseId]) && isset($courseSettingInfo[$courseId][$settingName])) {
2109
        return $courseSettingInfo[$courseId][$settingName];
2110
    }
2111
2112
    return -1;
2113
}
2114
2115
function api_get_course_plugin_setting($plugin, $settingName, $courseInfo = [])
2116
{
2117
    $value = api_get_course_setting($settingName, $courseInfo, true);
2118
2119
    if (-1 === $value) {
2120
        // Check global settings
2121
        $value = api_get_plugin_setting($plugin, $settingName);
2122
        if ('true' === $value) {
2123
            return 1;
2124
        }
2125
        if ('false' === $value) {
2126
            return 0;
2127
        }
2128
        if (null === $value) {
2129
            return -1;
2130
        }
2131
    }
2132
2133
    return $value;
2134
}
2135
2136
/**
2137
 * Gets an anonymous user ID.
2138
 *
2139
 * For some tools that need tracking, like the learnpath tool, it is necessary
2140
 * to have a usable user-id to enable some kind of tracking, even if not
2141
 * perfect. An anonymous ID is taken from the users table by looking for a
2142
 * status of "6" (anonymous).
2143
 *
2144
 * @return int User ID of the anonymous user, or O if no anonymous user found
2145
 */
2146
function api_get_anonymous_id()
2147
{
2148
    // Find if another anon is connected now
2149
    $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
2150
    $tableU = Database::get_main_table(TABLE_MAIN_USER);
2151
    $ip = Database::escape_string(api_get_real_ip());
2152
    $max = (int) api_get_configuration_value('max_anonymous_users');
2153
    if ($max >= 2) {
2154
        $sql = "SELECT * FROM $table as TEL
2155
                JOIN $tableU as U
2156
                ON U.id = TEL.login_user_id
2157
                WHERE TEL.user_ip = '$ip'
2158
                    AND U.status = ".ANONYMOUS."
2159
                    AND U.id != 2 ";
2160
2161
        $result = Database::query($sql);
2162
        if (empty(Database::num_rows($result))) {
2163
            $login = uniqid('anon_');
2164
            $anonList = UserManager::get_user_list(['status' => ANONYMOUS], ['registration_date ASC']);
2165
            if (count($anonList) >= $max) {
2166
                foreach ($anonList as $userToDelete) {
2167
                    UserManager::delete_user($userToDelete['user_id']);
2168
                    break;
2169
                }
2170
            }
2171
2172
            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...
2173
                $login,
2174
                'anon',
2175
                ANONYMOUS,
2176
                ' anonymous@localhost',
2177
                $login,
2178
                $login
2179
            );
2180
        } else {
2181
            $row = Database::fetch_array($result, 'ASSOC');
2182
2183
            return $row['id'];
2184
        }
2185
    }
2186
2187
    $table = Database::get_main_table(TABLE_MAIN_USER);
2188
    $sql = "SELECT id
2189
            FROM $table
2190
            WHERE status = ".ANONYMOUS." ";
2191
    $res = Database::query($sql);
2192
    if (Database::num_rows($res) > 0) {
2193
        $row = Database::fetch_array($res, 'ASSOC');
2194
2195
        return $row['id'];
2196
    }
2197
2198
    // No anonymous user was found.
2199
    return 0;
2200
}
2201
2202
/**
2203
 * @param int $courseId
2204
 * @param int $sessionId
2205
 * @param int $groupId
2206
 *
2207
 * @return string
2208
 */
2209
function api_get_cidreq_params($courseId, $sessionId = 0, $groupId = 0)
2210
{
2211
    $courseId = !empty($courseId) ? (int) $courseId : 0;
2212
    $sessionId = !empty($sessionId) ? (int) $sessionId : 0;
2213
    $groupId = !empty($groupId) ? (int) $groupId : 0;
2214
2215
    $url = 'cid='.$courseId;
2216
    $url .= '&sid='.$sessionId;
2217
    $url .= '&gid='.$groupId;
2218
2219
    return $url;
2220
}
2221
2222
/**
2223
 * Returns the current course url part including session, group, and gradebook params.
2224
 *
2225
 * @param bool   $addSessionId
2226
 * @param bool   $addGroupId
2227
 * @param string $origin
2228
 *
2229
 * @return string Course & session references to add to a URL
2230
 */
2231
function api_get_cidreq($addSessionId = true, $addGroupId = true, $origin = '')
2232
{
2233
    $courseId = api_get_course_int_id();
2234
    $url = empty($courseId) ? '' : 'cid='.$courseId;
2235
    $origin = empty($origin) ? api_get_origin() : Security::remove_XSS($origin);
2236
2237
    if ($addSessionId) {
2238
        if (!empty($url)) {
2239
            $url .= 0 == api_get_session_id() ? '&sid=0' : '&sid='.api_get_session_id();
2240
        }
2241
    }
2242
2243
    if ($addGroupId) {
2244
        if (!empty($url)) {
2245
            $url .= 0 == api_get_group_id() ? '&gid=0' : '&gid='.api_get_group_id();
2246
        }
2247
    }
2248
2249
    if (!empty($url)) {
2250
        $url .= '&gradebook='.(int) api_is_in_gradebook();
2251
        $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

2251
        $url .= '&origin='./** @scrutinizer ignore-type */ $origin;
Loading history...
2252
    }
2253
2254
    return $url;
2255
}
2256
2257
/**
2258
 * Get if we visited a gradebook page.
2259
 *
2260
 * @return bool
2261
 */
2262
function api_is_in_gradebook()
2263
{
2264
    return Session::read('in_gradebook', false);
2265
}
2266
2267
/**
2268
 * Set that we are in a page inside a gradebook.
2269
 */
2270
function api_set_in_gradebook()
2271
{
2272
    Session::write('in_gradebook', true);
2273
}
2274
2275
/**
2276
 * Remove gradebook session.
2277
 */
2278
function api_remove_in_gradebook()
2279
{
2280
    Session::erase('in_gradebook');
2281
}
2282
2283
/**
2284
 * Returns the current course info array see api_format_course_array()
2285
 * If the course_code is given, the returned array gives info about that
2286
 * particular course, if none given it gets the course info from the session.
2287
 *
2288
 * @param string $courseCode
2289
 *
2290
 * @return array
2291
 */
2292
function api_get_course_info($courseCode = null)
2293
{
2294
    if (!empty($courseCode)) {
2295
        $course = Container::getCourseRepository()->findOneByCode($courseCode);
2296
2297
        return api_format_course_array($course);
2298
    }
2299
2300
    $course = Session::read('_course');
2301
    if ('-1' == $course) {
2302
        $course = [];
2303
    }
2304
2305
    return $course;
2306
}
2307
2308
/**
2309
 * @param int $courseId
2310
 */
2311
function api_get_course_entity($courseId = 0): ?Course
2312
{
2313
    if (empty($courseId)) {
2314
        $courseId = api_get_course_int_id();
2315
    }
2316
2317
    if (empty($courseId)) {
2318
        return null;
2319
    }
2320
2321
    return Container::getCourseRepository()->find($courseId);
2322
}
2323
2324
/**
2325
 * @param int $id
2326
 */
2327
function api_get_session_entity($id = 0): ?SessionEntity
2328
{
2329
    if (empty($id)) {
2330
        $id = api_get_session_id();
2331
    }
2332
2333
    if (empty($id)) {
2334
        return null;
2335
    }
2336
2337
    return Container::getSessionRepository()->find($id);
2338
}
2339
2340
/**
2341
 * @param int $id
2342
 */
2343
function api_get_group_entity($id = 0): ?CGroup
2344
{
2345
    if (empty($id)) {
2346
        $id = api_get_group_id();
2347
    }
2348
2349
    return Container::getGroupRepository()->find($id);
2350
}
2351
2352
/**
2353
 * @param int $id
2354
 */
2355
function api_get_url_entity($id = 0): ?AccessUrl
2356
{
2357
    if (empty($id)) {
2358
        $id = api_get_current_access_url_id();
2359
    }
2360
2361
    return Container::getAccessUrlRepository()->find($id);
2362
}
2363
2364
/**
2365
 * Returns the current course info array.
2366
2367
 * Now if the course_code is given, the returned array gives info about that
2368
 * particular course, not specially the current one.
2369
 *
2370
 * @param int $id Numeric ID of the course
2371
 *
2372
 * @return array The course info as an array formatted by api_format_course_array, including category.name
2373
 */
2374
function api_get_course_info_by_id($id = 0)
2375
{
2376
    $id = (int) $id;
2377
    if (empty($id)) {
2378
        $course = Session::read('_course', []);
2379
2380
        return $course;
2381
    }
2382
2383
    $course = Container::getCourseRepository()->find($id);
2384
    if (empty($course)) {
2385
        return [];
2386
    }
2387
2388
    return api_format_course_array($course);
2389
}
2390
2391
/**
2392
 * Reformat the course array (output by api_get_course_info()) in order, mostly,
2393
 * to switch from 'code' to 'id' in the array.
2394
 *
2395
 * @return array
2396
 *
2397
 * @todo eradicate the false "id"=code field of the $_course array and use the int id
2398
 */
2399
function api_format_course_array(Course $course = null)
2400
{
2401
    if (empty($course)) {
2402
        return [];
2403
    }
2404
2405
    $courseData = [];
2406
    $courseData['id'] = $courseData['real_id'] = $course->getId();
2407
2408
    // Added
2409
    $courseData['code'] = $courseData['sysCode'] = $course->getCode();
2410
    $courseData['name'] = $courseData['title'] = $course->getTitle();
2411
    $courseData['official_code'] = $courseData['visual_code'] = $course->getVisualCode();
2412
    //$courseData['path'] = $courseData['directory'] = $course->getDirectory(); // Use as key in path.
2413
    $courseData['creation_date'] = $course->getCreationDate()->format('Y-m-d H:i:s');
2414
    $courseData['titular'] = $course->getTutorName();
2415
    $courseData['language'] = $courseData['course_language'] = $course->getCourseLanguage();
2416
    $courseData['extLink']['url'] = $courseData['department_url'] = $course->getDepartmentUrl();
2417
    $courseData['extLink']['name'] = $courseData['department_name'] = $course->getDepartmentName();
2418
2419
    $courseData['visibility'] = $course->getVisibility();
2420
    $courseData['subscribe_allowed'] = $courseData['subscribe'] = $course->getSubscribe();
2421
    $courseData['unsubscribe'] = $course->getUnsubscribe();
2422
    $courseData['activate_legal'] = $course->getActivateLegal();
2423
    $courseData['legal'] = $course->getLegal();
2424
    $courseData['show_score'] = $course->getShowScore(); //used in the work tool
2425
2426
    //$coursePath = api_get_path(WEB_COURSE_PATH);
2427
    $coursePath = '/course/';
2428
    $webCourseHome = $coursePath.$courseData['real_id'].'/home';
2429
2430
    // Course password
2431
    $courseData['registration_code'] = $course->getRegistrationCode();
2432
    $courseData['disk_quota'] = $course->getDiskQuota();
2433
    $courseData['course_public_url'] = $webCourseHome;
2434
    $courseData['about_url'] = $coursePath.$courseData['real_id'].'/about';
2435
    $courseData['add_teachers_to_sessions_courses'] = $course->isAddTeachersToSessionsCourses();
2436
    $courseData['entity'] = $course;
2437
2438
    $image = Display::return_icon(
2439
        'course.png',
2440
        null,
2441
        null,
2442
        ICON_SIZE_BIG,
2443
        null,
2444
        true,
2445
        false
2446
    );
2447
2448
    $illustration = Container::getIllustrationRepository()->getIllustrationUrl($course);
2449
    if (!empty($illustration)) {
2450
        $image = $illustration;
2451
    }
2452
2453
    $courseData['course_image'] = $image.'?filter=course_picture_small';
2454
2455
    // Course large image
2456
    /*$courseData['course_image_large_source'] = '';
2457
    if (file_exists($courseSys.'/course-pic.png')) {
2458
        $url_image = $webCourseHome.'/course-pic.png';
2459
        $courseData['course_image_large_source'] = $courseSys.'/course-pic.png';
2460
    } else {
2461
        $url_image = Display::return_icon(
2462
            'session_default.png',
2463
            null,
2464
            null,
2465
            null,
2466
            null,
2467
            true,
2468
            true
2469
        );
2470
    }*/
2471
2472
    $courseData['course_image_large'] = $image.'?filter=course_picture_medium';
2473
2474
    return $courseData;
2475
}
2476
2477
/**
2478
 * Returns a difficult to guess password.
2479
 *
2480
 * @param int $length the length of the password
2481
 *
2482
 * @return string the generated password
2483
 */
2484
function api_generate_password($length = 8)
2485
{
2486
    if ($length < 2) {
2487
        $length = 2;
2488
    }
2489
2490
    $charactersLowerCase = 'abcdefghijkmnopqrstuvwxyz';
2491
    $charactersUpperCase = 'ABCDEFGHJKLMNPQRSTUVWXYZ';
2492
    $minNumbers = 2;
2493
    $length = $length - $minNumbers;
2494
    $minLowerCase = round($length / 2);
2495
    $minUpperCase = $length - $minLowerCase;
2496
2497
    $password = '';
2498
    $passwordRequirements = api_get_configuration_value('password_requirements');
2499
2500
    $factory = new RandomLib\Factory();
2501
    $generator = $factory->getGenerator(new SecurityLib\Strength(SecurityLib\Strength::MEDIUM));
2502
2503
    if (!empty($passwordRequirements)) {
2504
        $length = $passwordRequirements['min']['length'];
2505
        $minNumbers = $passwordRequirements['min']['numeric'];
2506
        $minLowerCase = $passwordRequirements['min']['lowercase'];
2507
        $minUpperCase = $passwordRequirements['min']['uppercase'];
2508
2509
        $rest = $length - $minNumbers - $minLowerCase - $minUpperCase;
2510
        // Add the rest to fill the length requirement
2511
        if ($rest > 0) {
2512
            $password .= $generator->generateString($rest, $charactersLowerCase.$charactersUpperCase);
2513
        }
2514
    }
2515
2516
    // Min digits default 2
2517
    for ($i = 0; $i < $minNumbers; $i++) {
2518
        $password .= $generator->generateInt(2, 9);
2519
    }
2520
2521
    // Min lowercase
2522
    $password .= $generator->generateString($minLowerCase, $charactersLowerCase);
2523
2524
    // Min uppercase
2525
    $password .= $generator->generateString($minUpperCase, $charactersUpperCase);
2526
    $password = str_shuffle($password);
2527
2528
    return $password;
2529
}
2530
2531
/**
2532
 * Checks a password to see wether it is OK to use.
2533
 *
2534
 * @param string $password
2535
 *
2536
 * @return bool if the password is acceptable, false otherwise
2537
 *              Notes about what a password "OK to use" is:
2538
 *              1. The password should be at least 5 characters long.
2539
 *              2. Only English letters (uppercase or lowercase, it doesn't matter) and digits are allowed.
2540
 *              3. The password should contain at least 3 letters.
2541
 *              4. It should contain at least 2 digits.
2542
 *              Settings will change if the configuration value is set: password_requirements
2543
 */
2544
function api_check_password($password)
2545
{
2546
    $passwordRequirements = Security::getPasswordRequirements();
2547
2548
    $minLength = $passwordRequirements['min']['length'];
2549
    $minNumbers = $passwordRequirements['min']['numeric'];
2550
    // Optional
2551
    $minLowerCase = $passwordRequirements['min']['lowercase'];
2552
    $minUpperCase = $passwordRequirements['min']['uppercase'];
2553
2554
    $minLetters = $minLowerCase + $minUpperCase;
2555
    $passwordLength = api_strlen($password);
2556
2557
    $conditions = [
2558
        'min_length' => $passwordLength >= $minLength,
2559
    ];
2560
2561
    $digits = 0;
2562
    $lowerCase = 0;
2563
    $upperCase = 0;
2564
2565
    for ($i = 0; $i < $passwordLength; $i++) {
2566
        $currentCharacterCode = api_ord(api_substr($password, $i, 1));
2567
        if ($currentCharacterCode >= 65 && $currentCharacterCode <= 90) {
2568
            $upperCase++;
2569
        }
2570
2571
        if ($currentCharacterCode >= 97 && $currentCharacterCode <= 122) {
2572
            $lowerCase++;
2573
        }
2574
        if ($currentCharacterCode >= 48 && $currentCharacterCode <= 57) {
2575
            $digits++;
2576
        }
2577
    }
2578
2579
    // Min number of digits
2580
    $conditions['min_numeric'] = $digits >= $minNumbers;
2581
2582
    if (!empty($minUpperCase)) {
2583
        // Uppercase
2584
        $conditions['min_uppercase'] = $upperCase >= $minUpperCase;
2585
    }
2586
2587
    if (!empty($minLowerCase)) {
2588
        // Lowercase
2589
        $conditions['min_lowercase'] = $upperCase >= $minLowerCase;
2590
    }
2591
2592
    // Min letters
2593
    $letters = $upperCase + $lowerCase;
2594
    $conditions['min_letters'] = $letters >= $minLetters;
2595
2596
    $isPasswordOk = true;
2597
    foreach ($conditions as $condition) {
2598
        if (false === $condition) {
2599
            $isPasswordOk = false;
2600
            break;
2601
        }
2602
    }
2603
2604
    if (false === $isPasswordOk) {
2605
        $output = get_lang('The new password does not match the minimum security requirements').'<br />';
2606
        $output .= Security::getPasswordRequirementsToString($conditions);
2607
2608
        Display::addFlash(Display::return_message($output, 'warning', false));
2609
    }
2610
2611
    return $isPasswordOk;
2612
}
2613
2614
/**
2615
 * Returns the status string corresponding to the status code.
2616
 *
2617
 * @author Noel Dieschburg
2618
 *
2619
 * @param the int status code
2620
 *
2621
 * @return string
2622
 */
2623
function get_status_from_code($status_code)
2624
{
2625
    switch ($status_code) {
2626
        case STUDENT:
2627
            return get_lang('Student');
2628
        case COURSEMANAGER:
2629
            return get_lang('Teacher');
2630
        case SESSIONADMIN:
2631
            return get_lang('SessionsAdmin');
2632
        case DRH:
2633
            return get_lang('Drh');
2634
        case ANONYMOUS:
2635
            return get_lang('Anonymous');
2636
        case PLATFORM_ADMIN:
2637
            return get_lang('Administrator');
2638
        case SESSION_COURSE_COACH:
2639
            return get_lang('SessionCourseCoach');
2640
        case SESSION_GENERAL_COACH:
2641
            return get_lang('SessionGeneralCoach');
2642
        case COURSE_TUTOR:
2643
            return get_lang('CourseAssistant');
2644
        case STUDENT_BOSS:
2645
            return get_lang('StudentBoss');
2646
        case INVITEE:
2647
            return get_lang('Invitee');
2648
    }
2649
}
2650
2651
/**
2652
 * Gets the current Chamilo (not PHP/cookie) session ID.
2653
 *
2654
 * @return int O if no active session, the session ID otherwise
2655
 */
2656
function api_get_session_id()
2657
{
2658
    return (int) Session::read('sid', 0);
2659
}
2660
2661
/**
2662
 * Gets the current Chamilo (not social network) group ID.
2663
 *
2664
 * @return int O if no active session, the session ID otherwise
2665
 */
2666
function api_get_group_id()
2667
{
2668
    return Session::read('gid', 0);
2669
}
2670
2671
/**
2672
 * Gets the current or given session name.
2673
 *
2674
 * @param   int     Session ID (optional)
2675
 *
2676
 * @return string The session name, or null if not found
2677
 */
2678
function api_get_session_name($session_id = 0)
2679
{
2680
    if (empty($session_id)) {
2681
        $session_id = api_get_session_id();
2682
        if (empty($session_id)) {
2683
            return null;
2684
        }
2685
    }
2686
    $t = Database::get_main_table(TABLE_MAIN_SESSION);
2687
    $s = "SELECT name FROM $t WHERE id = ".(int) $session_id;
2688
    $r = Database::query($s);
2689
    $c = Database::num_rows($r);
2690
    if ($c > 0) {
2691
        //technically, there can be only one, but anyway we take the first
2692
        $rec = Database::fetch_array($r);
2693
2694
        return $rec['name'];
2695
    }
2696
2697
    return null;
2698
}
2699
2700
/**
2701
 * Gets the session info by id.
2702
 *
2703
 * @param int $id Session ID
2704
 *
2705
 * @return array information of the session
2706
 */
2707
function api_get_session_info($id)
2708
{
2709
    return SessionManager::fetch($id);
2710
}
2711
2712
/**
2713
 * Gets the session visibility by session id.
2714
 *
2715
 * @param int  $session_id
2716
 * @param int  $courseId
2717
 * @param bool $ignore_visibility_for_admins
2718
 *
2719
 * @return int
2720
 *             0 = session still available,
2721
 *             SESSION_VISIBLE_READ_ONLY = 1,
2722
 *             SESSION_VISIBLE = 2,
2723
 *             SESSION_INVISIBLE = 3
2724
 */
2725
function api_get_session_visibility(
2726
    $session_id,
2727
    $courseId = null,
2728
    $ignore_visibility_for_admins = true
2729
) {
2730
    if (api_is_platform_admin()) {
2731
        if ($ignore_visibility_for_admins) {
2732
            return SESSION_AVAILABLE;
2733
        }
2734
    }
2735
2736
    $now = time();
2737
    if (empty($session_id)) {
2738
        return 0; // Means that the session is still available.
2739
    }
2740
2741
    $session_id = (int) $session_id;
2742
    $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
2743
2744
    $result = Database::query("SELECT * FROM $tbl_session WHERE id = $session_id");
2745
2746
    if (Database::num_rows($result) <= 0) {
2747
        return SESSION_INVISIBLE;
2748
    }
2749
2750
    $row = Database::fetch_array($result, 'ASSOC');
2751
    $visibility = $row['visibility'];
2752
2753
    // I don't care the session visibility.
2754
    if (empty($row['access_start_date']) && empty($row['access_end_date'])) {
2755
        // Session duration per student.
2756
        if (isset($row['duration']) && !empty($row['duration'])) {
2757
            $duration = $row['duration'] * 24 * 60 * 60;
2758
            $courseAccess = CourseManager::getFirstCourseAccessPerSessionAndUser($session_id, api_get_user_id());
2759
2760
            // If there is a session duration but there is no previous
2761
            // access by the user, then the session is still available
2762
            if (0 == count($courseAccess)) {
2763
                return SESSION_AVAILABLE;
2764
            }
2765
2766
            $currentTime = time();
2767
            $firstAccess = isset($courseAccess['login_course_date'])
2768
                ? api_strtotime($courseAccess['login_course_date'], 'UTC')
2769
                : 0;
2770
            $userDurationData = SessionManager::getUserSession(
2771
                api_get_user_id(),
2772
                $session_id
2773
            );
2774
            $userDuration = isset($userDurationData['duration'])
2775
                ? (intval($userDurationData['duration']) * 24 * 60 * 60)
2776
                : 0;
2777
2778
            $totalDuration = $firstAccess + $duration + $userDuration;
2779
2780
            return $totalDuration > $currentTime ? SESSION_AVAILABLE : SESSION_VISIBLE_READ_ONLY;
2781
        }
2782
2783
        return SESSION_AVAILABLE;
2784
    }
2785
2786
    // If start date was set.
2787
    if (!empty($row['access_start_date'])) {
2788
        $visibility = $now > api_strtotime($row['access_start_date'], 'UTC') ? SESSION_AVAILABLE : SESSION_INVISIBLE;
2789
    }
2790
2791
    // If the end date was set.
2792
    if (!empty($row['access_end_date'])) {
2793
        // Only if date_start said that it was ok
2794
        if (SESSION_AVAILABLE === $visibility) {
2795
            $visibility = $now < api_strtotime($row['access_end_date'], 'UTC')
2796
                ? SESSION_AVAILABLE // Date still available
2797
                : $row['visibility']; // Session ends
2798
        }
2799
    }
2800
2801
    // If I'm a coach the visibility can change in my favor depending in the coach dates.
2802
    $isCoach = api_is_coach($session_id, $courseId);
2803
2804
    if ($isCoach) {
2805
        // Test start date.
2806
        if (!empty($row['coach_access_start_date'])) {
2807
            $start = api_strtotime($row['coach_access_start_date'], 'UTC');
2808
            $visibility = $start < $now ? SESSION_AVAILABLE : SESSION_INVISIBLE;
2809
        }
2810
2811
        // Test end date.
2812
        if (!empty($row['coach_access_end_date'])) {
2813
            if (SESSION_AVAILABLE === $visibility) {
2814
                $endDateCoach = api_strtotime($row['coach_access_end_date'], 'UTC');
2815
                $visibility = $endDateCoach >= $now ? SESSION_AVAILABLE : $row['visibility'];
2816
            }
2817
        }
2818
    }
2819
2820
    return $visibility;
2821
}
2822
2823
/**
2824
 * This function returns a (star) session icon if the session is not null and
2825
 * the user is not a student.
2826
 *
2827
 * @param int $sessionId
2828
 * @param int $statusId  User status id - if 5 (student), will return empty
2829
 *
2830
 * @return string Session icon
2831
 */
2832
function api_get_session_image($sessionId, $statusId)
2833
{
2834
    $sessionId = (int) $sessionId;
2835
    $image = '';
2836
    if (STUDENT != $statusId) {
2837
        // Check whether is not a student
2838
        if ($sessionId > 0) {
2839
            $image = '&nbsp;&nbsp;'.Display::return_icon(
2840
                'star.png',
2841
                get_lang('Session-specific resource'),
2842
                ['align' => 'absmiddle'],
2843
                ICON_SIZE_SMALL
2844
            );
2845
        }
2846
    }
2847
2848
    return $image;
2849
}
2850
2851
/**
2852
 * This function add an additional condition according to the session of the course.
2853
 *
2854
 * @param int    $session_id        session id
2855
 * @param bool   $and               optional, true if more than one condition false if the only condition in the query
2856
 * @param bool   $with_base_content optional, true to accept content with session=0 as well,
2857
 *                                  false for strict session condition
2858
 * @param string $session_field
2859
 *
2860
 * @return string condition of the session
2861
 */
2862
function api_get_session_condition(
2863
    $session_id,
2864
    $and = true,
2865
    $with_base_content = false,
2866
    $session_field = 'session_id'
2867
) {
2868
    $session_id = (int) $session_id;
2869
2870
    if (empty($session_field)) {
2871
        $session_field = 'session_id';
2872
    }
2873
    // Condition to show resources by session
2874
    $condition_add = $and ? ' AND ' : ' WHERE ';
2875
2876
    if ($with_base_content) {
2877
        $condition_session = $condition_add." ( $session_field = $session_id OR $session_field = 0 OR $session_field IS NULL) ";
2878
    } else {
2879
        if (empty($session_id)) {
2880
            $condition_session = $condition_add." ($session_field = $session_id OR $session_field IS NULL)";
2881
        } else {
2882
            $condition_session = $condition_add." $session_field = $session_id ";
2883
        }
2884
    }
2885
2886
    return $condition_session;
2887
}
2888
2889
/**
2890
 * Returns the value of a setting from the web-adjustable admin config settings.
2891
 *
2892
 * WARNING true/false are stored as string, so when comparing you need to check e.g.
2893
 * if (api_get_setting('show_navigation_menu') == 'true') //CORRECT
2894
 * instead of
2895
 * if (api_get_setting('show_navigation_menu') == true) //INCORRECT
2896
 *
2897
 * @param string $variable The variable name
2898
 *
2899
 * @return string|array
2900
 */
2901
function api_get_setting($variable)
2902
{
2903
    $settingsManager = Container::getSettingsManager();
2904
    if (empty($settingsManager)) {
2905
        return '';
2906
    }
2907
    $variable = trim($variable);
2908
2909
    switch ($variable) {
2910
        /*case 'header_extra_content':
2911
            $filename = api_get_path(SYS_PATH).api_get_home_path().'header_extra_content.txt';
2912
            if (file_exists($filename)) {
2913
                $value = file_get_contents($filename);
2914
2915
                return $value;
2916
            } else {
2917
                return '';
2918
            }
2919
            break;
2920
        case 'footer_extra_content':
2921
            $filename = api_get_path(SYS_PATH).api_get_home_path().'footer_extra_content.txt';
2922
            if (file_exists($filename)) {
2923
                $value = file_get_contents($filename);
2924
2925
                return $value;
2926
            } else {
2927
                return '';
2928
            }
2929
            break;*/
2930
        case 'server_type':
2931
            $test = ['dev', 'test'];
2932
            $environment = Container::getEnvironment();
2933
            if (in_array($environment, $test)) {
2934
                return 'test';
2935
            }
2936
2937
            return 'prod';
2938
        case 'stylesheets':
2939
            $variable = 'platform.theme';
2940
        // deprecated settings
2941
        // no break
2942
        case 'openid_authentication':
2943
        case 'service_ppt2lp':
2944
        case 'formLogin_hide_unhide_label':
2945
            return false;
2946
            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...
2947
        case 'tool_visible_by_default_at_creation':
2948
            $values = $settingsManager->getSetting($variable);
2949
            $newResult = [];
2950
            foreach ($values as $parameter) {
2951
                $newResult[$parameter] = 'true';
2952
            }
2953
2954
            return $newResult;
2955
            break;
2956
        default:
2957
            return $settingsManager->getSetting($variable);
2958
            break;
2959
    }
2960
}
2961
2962
/**
2963
 * @param string $variable
2964
 * @param string $option
2965
 *
2966
 * @return bool
2967
 */
2968
function api_get_setting_in_list($variable, $option)
2969
{
2970
    $value = api_get_setting($variable);
2971
2972
    return in_array($option, $value);
2973
}
2974
2975
/**
2976
 * @param string $plugin
2977
 * @param string $variable
2978
 *
2979
 * @return string
2980
 */
2981
function api_get_plugin_setting($plugin, $variable)
2982
{
2983
    $variableName = $plugin.'_'.$variable;
2984
    //$result = api_get_setting($variableName);
2985
    $params = [
2986
        'category = ? AND subkey = ? AND variable = ?' => [
2987
            'Plugins',
2988
            $plugin,
2989
            $variableName,
2990
        ],
2991
    ];
2992
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2993
    $result = Database::select(
2994
        'selected_value',
2995
        $table,
2996
        ['where' => $params],
2997
        'one'
2998
    );
2999
    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...
3000
        $value = $result['selected_value'];
3001
        $serializedValue = @unserialize($result['selected_value'], []);
3002
        if (false !== $serializedValue) {
3003
            $value = $serializedValue;
3004
        }
3005
3006
        return $value;
3007
    }
3008
3009
    return null;
3010
    /// Old code
3011
3012
    $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...
3013
    $result = api_get_setting($variableName);
3014
3015
    if (isset($result[$plugin])) {
3016
        $value = $result[$plugin];
3017
3018
        $unserialized = UnserializeApi::unserialize('not_allowed_classes', $value, true);
3019
3020
        if (false !== $unserialized) {
3021
            $value = $unserialized;
3022
        }
3023
3024
        return $value;
3025
    }
3026
3027
    return null;
3028
}
3029
3030
/**
3031
 * Returns the value of a setting from the web-adjustable admin config settings.
3032
 */
3033
function api_get_settings_params($params)
3034
{
3035
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
3036
    $result = Database::select('*', $table, ['where' => $params]);
3037
3038
    return $result;
3039
}
3040
3041
/**
3042
 * @param array $params example: [id = ? => '1']
3043
 *
3044
 * @return array
3045
 */
3046
function api_get_settings_params_simple($params)
3047
{
3048
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
3049
    $result = Database::select('*', $table, ['where' => $params], 'one');
3050
3051
    return $result;
3052
}
3053
3054
/**
3055
 * Returns the value of a setting from the web-adjustable admin config settings.
3056
 */
3057
function api_delete_settings_params($params)
3058
{
3059
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
3060
    $result = Database::delete($table, $params);
3061
3062
    return $result;
3063
}
3064
3065
/**
3066
 * Returns an escaped version of $_SERVER['PHP_SELF'] to avoid XSS injection.
3067
 *
3068
 * @return string Escaped version of $_SERVER['PHP_SELF']
3069
 */
3070
function api_get_self()
3071
{
3072
    return htmlentities($_SERVER['PHP_SELF']);
3073
}
3074
3075
/* USER PERMISSIONS */
3076
3077
/**
3078
 * Checks whether current user is a platform administrator.
3079
 *
3080
 * @param bool $allowSessionAdmins Whether session admins should be considered admins or not
3081
 * @param bool $allowDrh           Whether HR directors should be considered admins or not
3082
 *
3083
 * @return bool true if the user has platform admin rights,
3084
 *              false otherwise
3085
 *
3086
 * @see usermanager::is_admin(user_id) for a user-id specific function
3087
 */
3088
function api_is_platform_admin($allowSessionAdmins = false, $allowDrh = false)
3089
{
3090
    $currentUser = api_get_current_user();
3091
3092
    if (null === $currentUser) {
3093
        return false;
3094
    }
3095
3096
    $isAdmin = Session::read('is_platformAdmin');
3097
    if ($isAdmin) {
3098
        return true;
3099
    }
3100
    $user = api_get_user_info();
3101
3102
    return
3103
        isset($user['status']) &&
3104
        (
3105
            ($allowSessionAdmins && SESSIONADMIN == $user['status']) ||
3106
            ($allowDrh && DRH == $user['status'])
3107
        );
3108
}
3109
3110
/**
3111
 * Checks whether the user given as user id is in the admin table.
3112
 *
3113
 * @param int $user_id If none provided, will use current user
3114
 * @param int $url     URL ID. If provided, also check if the user is active on given URL
3115
 *
3116
 * @return bool True if the user is admin, false otherwise
3117
 */
3118
function api_is_platform_admin_by_id($user_id = null, $url = null)
3119
{
3120
    $user_id = (int) $user_id;
3121
    if (empty($user_id)) {
3122
        $user_id = api_get_user_id();
3123
    }
3124
    $admin_table = Database::get_main_table(TABLE_MAIN_ADMIN);
3125
    $sql = "SELECT * FROM $admin_table WHERE user_id = $user_id";
3126
    $res = Database::query($sql);
3127
    $is_admin = 1 === Database::num_rows($res);
3128
    if (!$is_admin || !isset($url)) {
3129
        return $is_admin;
3130
    }
3131
    // We get here only if $url is set
3132
    $url = (int) $url;
3133
    $url_user_table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
3134
    $sql = "SELECT * FROM $url_user_table
3135
            WHERE access_url_id = $url AND user_id = $user_id";
3136
    $res = Database::query($sql);
3137
    $result = 1 === Database::num_rows($res);
3138
3139
    return $result;
3140
}
3141
3142
/**
3143
 * Returns the user's numeric status ID from the users table.
3144
 *
3145
 * @param int $user_id If none provided, will use current user
3146
 *
3147
 * @return int User's status (1 for teacher, 5 for student, etc)
3148
 */
3149
function api_get_user_status($user_id = null)
3150
{
3151
    $user_id = (int) $user_id;
3152
    if (empty($user_id)) {
3153
        $user_id = api_get_user_id();
3154
    }
3155
    $table = Database::get_main_table(TABLE_MAIN_USER);
3156
    $sql = "SELECT status FROM $table WHERE id = $user_id ";
3157
    $result = Database::query($sql);
3158
    $status = null;
3159
    if (Database::num_rows($result)) {
3160
        $row = Database::fetch_array($result);
3161
        $status = $row['status'];
3162
    }
3163
3164
    return $status;
3165
}
3166
3167
/**
3168
 * Checks whether current user is allowed to create courses.
3169
 *
3170
 * @return bool true if the user has course creation rights,
3171
 *              false otherwise
3172
 */
3173
function api_is_allowed_to_create_course()
3174
{
3175
    if (api_is_platform_admin()) {
3176
        return true;
3177
    }
3178
3179
    // Teachers can only create courses
3180
    if (api_is_teacher()) {
3181
        if ('true' === api_get_setting('allow_users_to_create_courses')) {
3182
            return true;
3183
        } else {
3184
            return false;
3185
        }
3186
    }
3187
3188
    return Session::read('is_allowedCreateCourse');
3189
}
3190
3191
/**
3192
 * Checks whether the current user is a course administrator.
3193
 *
3194
 * @return bool True if current user is a course administrator
3195
 */
3196
function api_is_course_admin()
3197
{
3198
    if (api_is_platform_admin()) {
3199
        return true;
3200
    }
3201
3202
    $user = api_get_current_user();
3203
    if ($user) {
3204
        if (
3205
            $user->hasRole('ROLE_CURRENT_COURSE_SESSION_TEACHER') ||
3206
            $user->hasRole('ROLE_CURRENT_COURSE_TEACHER')
3207
        ) {
3208
            return true;
3209
        }
3210
    }
3211
3212
    return false;
3213
    //return Session::read('is_courseAdmin');
3214
}
3215
3216
/**
3217
 * Checks whether the current user is a course coach
3218
 * Based on the presence of user in session.id_coach (session general coach).
3219
 *
3220
 * @return bool True if current user is a course coach
3221
 */
3222
function api_is_session_general_coach()
3223
{
3224
    return Session::read('is_session_general_coach');
3225
}
3226
3227
/**
3228
 * Checks whether the current user is a course tutor
3229
 * Based on the presence of user in session_rel_course_rel_user.user_id with status = 2.
3230
 *
3231
 * @return bool True if current user is a course tutor
3232
 */
3233
function api_is_course_tutor()
3234
{
3235
    return Session::read('is_courseTutor');
3236
}
3237
3238
/**
3239
 * @param int $user_id
3240
 * @param int $courseId
3241
 * @param int $session_id
3242
 *
3243
 * @return bool
3244
 */
3245
function api_is_course_session_coach($user_id, $courseId, $session_id)
3246
{
3247
    $session_table = Database::get_main_table(TABLE_MAIN_SESSION);
3248
    $session_rel_course_rel_user_table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3249
3250
    $user_id = (int) $user_id;
3251
    $session_id = (int) $session_id;
3252
    $courseId = (int) $courseId;
3253
3254
    $sql = "SELECT DISTINCT session.id
3255
            FROM $session_table
3256
            INNER JOIN $session_rel_course_rel_user_table session_rc_ru
3257
            ON session.id = session_rc_ru.session_id
3258
            WHERE
3259
                session_rc_ru.user_id = '".$user_id."'  AND
3260
                session_rc_ru.c_id = '$courseId' AND
3261
                session_rc_ru.status = 2 AND
3262
                session_rc_ru.session_id = '$session_id'";
3263
    $result = Database::query($sql);
3264
3265
    return Database::num_rows($result) > 0;
3266
}
3267
3268
/**
3269
 * Checks whether the current user is a course or session coach.
3270
 *
3271
 * @param int $session_id
3272
 * @param int $courseId
3273
 * @param bool  Check whether we are in student view and, if we are, return false
3274
 *
3275
 * @return bool True if current user is a course or session coach
3276
 */
3277
function api_is_coach($session_id = 0, $courseId = null, $check_student_view = true)
3278
{
3279
    $userId = api_get_user_id();
3280
3281
    if (!empty($session_id)) {
3282
        $session_id = (int) $session_id;
3283
    } else {
3284
        $session_id = api_get_session_id();
3285
    }
3286
3287
    // The student preview was on
3288
    if ($check_student_view && api_is_student_view_active()) {
3289
        return false;
3290
    }
3291
3292
    if (!empty($courseId)) {
3293
        $courseId = (int) $courseId;
3294
    } else {
3295
        $courseId = api_get_course_int_id();
3296
    }
3297
3298
    $session_table = Database::get_main_table(TABLE_MAIN_SESSION);
3299
    $session_rel_course_rel_user_table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3300
    $sessionIsCoach = [];
3301
3302
    if (!empty($courseId)) {
3303
        $sql = "SELECT DISTINCT s.id, name, access_start_date, access_end_date
3304
                FROM $session_table s
3305
                INNER JOIN $session_rel_course_rel_user_table session_rc_ru
3306
                ON session_rc_ru.session_id = s.id AND session_rc_ru.user_id = '".$userId."'
3307
                WHERE
3308
                    session_rc_ru.c_id = '$courseId' AND
3309
                    session_rc_ru.status = 2 AND
3310
                    session_rc_ru.session_id = '$session_id'";
3311
        $result = Database::query($sql);
3312
        $sessionIsCoach = Database::store_result($result);
3313
    }
3314
3315
    if (!empty($session_id)) {
3316
        $sql = "SELECT DISTINCT id, name, access_start_date, access_end_date
3317
                FROM $session_table
3318
                WHERE session.id_coach = $userId AND id = $session_id
3319
                ORDER BY access_start_date, access_end_date, name";
3320
        $result = Database::query($sql);
3321
        if (!empty($sessionIsCoach)) {
3322
            $sessionIsCoach = array_merge(
3323
                $sessionIsCoach,
3324
                Database::store_result($result)
3325
            );
3326
        } else {
3327
            $sessionIsCoach = Database::store_result($result);
3328
        }
3329
    }
3330
3331
    return count($sessionIsCoach) > 0;
3332
}
3333
3334
/**
3335
 * Checks whether the current user is a session administrator.
3336
 *
3337
 * @return bool True if current user is a course administrator
3338
 */
3339
function api_is_session_admin()
3340
{
3341
    $user = api_get_user_info();
3342
3343
    return isset($user['status']) && SESSIONADMIN == $user['status'];
3344
}
3345
3346
/**
3347
 * Checks whether the current user is a human resources manager.
3348
 *
3349
 * @return bool True if current user is a human resources manager
3350
 */
3351
function api_is_drh()
3352
{
3353
    $user = api_get_user_info();
3354
3355
    return isset($user['status']) && DRH == $user['status'];
3356
}
3357
3358
/**
3359
 * Checks whether the current user is a student.
3360
 *
3361
 * @return bool True if current user is a human resources manager
3362
 */
3363
function api_is_student()
3364
{
3365
    $user = api_get_user_info();
3366
3367
    return isset($user['status']) && STUDENT == $user['status'];
3368
}
3369
3370
/**
3371
 * Checks whether the current user has the status 'teacher'.
3372
 *
3373
 * @return bool True if current user is a human resources manager
3374
 */
3375
function api_is_teacher()
3376
{
3377
    $user = api_get_user_info();
3378
3379
    return isset($user['status']) && COURSEMANAGER == $user['status'];
3380
}
3381
3382
/**
3383
 * Checks whether the current user is a invited user.
3384
 *
3385
 * @return bool
3386
 */
3387
function api_is_invitee()
3388
{
3389
    $user = api_get_user_info();
3390
3391
    return isset($user['status']) && INVITEE == $user['status'];
3392
}
3393
3394
/**
3395
 * Displays the title of a tool.
3396
 * Normal use: parameter is a string:
3397
 * api_display_tool_title("My Tool").
3398
 *
3399
 * Optionally, there can be a subtitle below
3400
 * the normal title, and / or a supra title above the normal title.
3401
 *
3402
 * e.g. supra title:
3403
 * group
3404
 * GROUP PROPERTIES
3405
 *
3406
 * e.g. subtitle:
3407
 * AGENDA
3408
 * calender & events tool
3409
 *
3410
 * @author Hugues Peeters <[email protected]>
3411
 *
3412
 * @param mixed $title_element - it could either be a string or an array
3413
 *                             containing 'supraTitle', 'mainTitle',
3414
 *                             'subTitle'
3415
 */
3416
function api_display_tool_title($title_element)
3417
{
3418
    if (is_string($title_element)) {
3419
        $tit = $title_element;
3420
        unset($title_element);
3421
        $title_element = [];
3422
        $title_element['mainTitle'] = $tit;
3423
    }
3424
    echo '<h3>';
3425
    if (!empty($title_element['supraTitle'])) {
3426
        echo '<small>'.$title_element['supraTitle'].'</small><br />';
3427
    }
3428
    if (!empty($title_element['mainTitle'])) {
3429
        echo $title_element['mainTitle'];
3430
    }
3431
    if (!empty($title_element['subTitle'])) {
3432
        echo '<br /><small>'.$title_element['subTitle'].'</small>';
3433
    }
3434
    echo '</h3>';
3435
}
3436
3437
/**
3438
 * Displays options for switching between student view and course manager view.
3439
 *
3440
 * Changes in version 1.2 (Patrick Cool)
3441
 * Student view switch now behaves as a real switch. It maintains its current state until the state
3442
 * is changed explicitly
3443
 *
3444
 * Changes in version 1.1 (Patrick Cool)
3445
 * student view now works correctly in subfolders of the document tool
3446
 * student view works correctly in the new links tool
3447
 *
3448
 * Example code for using this in your tools:
3449
 * //if ($is_courseAdmin && api_get_setting('student_view_enabled') == 'true') {
3450
 * //   display_tool_view_option($isStudentView);
3451
 * //}
3452
 * //and in later sections, use api_is_allowed_to_edit()
3453
 *
3454
 * @author Roan Embrechts
3455
 * @author Patrick Cool
3456
 * @author Julio Montoya, changes added in Chamilo
3457
 *
3458
 * @version 1.2
3459
 *
3460
 * @todo rewrite code so it is easier to understand
3461
 */
3462
function api_display_tool_view_option()
3463
{
3464
    if ('true' != api_get_setting('student_view_enabled')) {
3465
        return '';
3466
    }
3467
3468
    $sourceurl = '';
3469
    $is_framed = false;
3470
    // Exceptions apply for all multi-frames pages
3471
    if (false !== strpos($_SERVER['REQUEST_URI'], 'chat/chat_banner.php')) {
3472
        // The chat is a multiframe bit that doesn't work too well with the student_view, so do not show the link
3473
        return '';
3474
    }
3475
3476
    // Uncomment to remove student view link from document view page
3477
    if (false !== strpos($_SERVER['REQUEST_URI'], 'lp/lp_header.php')) {
3478
        if (empty($_GET['lp_id'])) {
3479
            return '';
3480
        }
3481
        $sourceurl = substr($_SERVER['REQUEST_URI'], 0, strpos($_SERVER['REQUEST_URI'], '?'));
3482
        $sourceurl = str_replace(
3483
            'lp/lp_header.php',
3484
            'lp/lp_controller.php?'.api_get_cidreq().'&action=view&lp_id='.intval($_GET['lp_id']).'&isStudentView='.('studentview' == $_SESSION['studentview'] ? 'false' : 'true'),
3485
            $sourceurl
3486
        );
3487
        //showinframes doesn't handle student view anyway...
3488
        //return '';
3489
        $is_framed = true;
3490
    }
3491
3492
    // Check whether the $_SERVER['REQUEST_URI'] contains already url parameters (thus a questionmark)
3493
    if (!$is_framed) {
3494
        if (false === strpos($_SERVER['REQUEST_URI'], '?')) {
3495
            $sourceurl = api_get_self().'?'.api_get_cidreq();
3496
        } else {
3497
            $sourceurl = $_SERVER['REQUEST_URI'];
3498
        }
3499
    }
3500
3501
    $output_string = '';
3502
    if (!empty($_SESSION['studentview'])) {
3503
        if ('studentview' == $_SESSION['studentview']) {
3504
            // We have to remove the isStudentView=true from the $sourceurl
3505
            $sourceurl = str_replace('&isStudentView=true', '', $sourceurl);
3506
            $sourceurl = str_replace('&isStudentView=false', '', $sourceurl);
3507
            $output_string .= '<a class="btn btn-primary btn-sm" href="'.$sourceurl.'&isStudentView=false" target="_self">'.
3508
                Display::returnFontAwesomeIcon('eye').' '.get_lang('Switch to teacher view').'</a>';
3509
        } elseif ('teacherview' == $_SESSION['studentview']) {
3510
            // Switching to teacherview
3511
            $sourceurl = str_replace('&isStudentView=true', '', $sourceurl);
3512
            $sourceurl = str_replace('&isStudentView=false', '', $sourceurl);
3513
            $output_string .= '<a class="btn btn-default btn-sm" href="'.$sourceurl.'&isStudentView=true" target="_self">'.
3514
                Display::returnFontAwesomeIcon('eye').' '.get_lang('Switch to student view').'</a>';
3515
        }
3516
    } else {
3517
        $output_string .= '<a class="btn btn-default btn-sm" href="'.$sourceurl.'&isStudentView=true" target="_self">'.
3518
            Display::returnFontAwesomeIcon('eye').' '.get_lang('Switch to student view').'</a>';
3519
    }
3520
    $output_string = Security::remove_XSS($output_string);
3521
    $html = Display::tag('div', $output_string, ['class' => 'view-options']);
3522
3523
    return $html;
3524
}
3525
3526
// TODO: This is for the permission section.
3527
/**
3528
 * Function that removes the need to directly use is_courseAdmin global in
3529
 * tool scripts. It returns true or false depending on the user's rights in
3530
 * this particular course.
3531
 * Optionally checking for tutor and coach roles here allows us to use the
3532
 * student_view feature altogether with these roles as well.
3533
 *
3534
 * @param bool  Whether to check if the user has the tutor role
3535
 * @param bool  Whether to check if the user has the coach role
3536
 * @param bool  Whether to check if the user has the session coach role
3537
 * @param bool  check the student view or not
3538
 *
3539
 * @author Roan Embrechts
3540
 * @author Patrick Cool
3541
 * @author Julio Montoya
3542
 *
3543
 * @version 1.1, February 2004
3544
 *
3545
 * @return bool true: the user has the rights to edit, false: he does not
3546
 */
3547
function api_is_allowed_to_edit(
3548
    $tutor = false,
3549
    $coach = false,
3550
    $session_coach = false,
3551
    $check_student_view = true
3552
) {
3553
    $allowSessionAdminEdit = true === api_get_setting('session.session_admins_edit_courses_content');
3554
    // Admins can edit anything.
3555
    if (api_is_platform_admin($allowSessionAdminEdit)) {
3556
        //The student preview was on
3557
        if ($check_student_view && api_is_student_view_active()) {
3558
            return false;
3559
        }
3560
3561
        return true;
3562
    }
3563
3564
    $sessionId = api_get_session_id();
3565
3566
    if ($sessionId && api_get_configuration_value('session_courses_read_only_mode')) {
3567
        $efv = new ExtraFieldValue('course');
3568
        $lockExrafieldField = $efv->get_values_by_handler_and_field_variable(
3569
            api_get_course_int_id(),
3570
            'session_courses_read_only_mode'
3571
        );
3572
3573
        if (!empty($lockExrafieldField['value'])) {
3574
            return false;
3575
        }
3576
    }
3577
3578
    $is_allowed_coach_to_edit = api_is_coach(null, null, $check_student_view);
3579
    $session_visibility = api_get_session_visibility($sessionId);
3580
    $is_courseAdmin = api_is_course_admin();
3581
3582
    if (!$is_courseAdmin && $tutor) {
3583
        // If we also want to check if the user is a tutor...
3584
        $is_courseAdmin = $is_courseAdmin || api_is_course_tutor();
3585
    }
3586
3587
    if (!$is_courseAdmin && $coach) {
3588
        // If we also want to check if the user is a coach...';
3589
        // Check if session visibility is read only for coaches.
3590
        if (SESSION_VISIBLE_READ_ONLY == $session_visibility) {
3591
            $is_allowed_coach_to_edit = false;
3592
        }
3593
3594
        if ('true' === api_get_setting('allow_coach_to_edit_course_session')) {
3595
            // Check if coach is allowed to edit a course.
3596
            $is_courseAdmin = $is_courseAdmin || $is_allowed_coach_to_edit;
3597
        }
3598
    }
3599
3600
    if (!$is_courseAdmin && $session_coach) {
3601
        $is_courseAdmin = $is_courseAdmin || $is_allowed_coach_to_edit;
3602
    }
3603
3604
    // Check if the student_view is enabled, and if so, if it is activated.
3605
    if ('true' === api_get_setting('student_view_enabled')) {
3606
        $studentView = api_is_student_view_active();
3607
        if (!empty($sessionId)) {
3608
            // Check if session visibility is read only for coaches.
3609
            if (SESSION_VISIBLE_READ_ONLY == $session_visibility) {
3610
                $is_allowed_coach_to_edit = false;
3611
            }
3612
3613
            $is_allowed = false;
3614
            if ('true' === api_get_setting('allow_coach_to_edit_course_session')) {
3615
                // Check if coach is allowed to edit a course.
3616
                $is_allowed = $is_allowed_coach_to_edit;
3617
            }
3618
            if ($check_student_view) {
3619
                $is_allowed = $is_allowed && false === $studentView;
3620
            }
3621
        } else {
3622
            $is_allowed = $is_courseAdmin;
3623
            if ($check_student_view) {
3624
                $is_allowed = $is_courseAdmin && false === $studentView;
3625
            }
3626
        }
3627
3628
        return $is_allowed;
3629
    } else {
3630
        return $is_courseAdmin;
3631
    }
3632
}
3633
3634
/**
3635
 * Returns true if user is a course coach of at least one course in session.
3636
 *
3637
 * @param int $sessionId
3638
 *
3639
 * @return bool
3640
 */
3641
function api_is_coach_of_course_in_session($sessionId)
3642
{
3643
    if (api_is_platform_admin()) {
3644
        return true;
3645
    }
3646
3647
    $userId = api_get_user_id();
3648
    $courseList = UserManager::get_courses_list_by_session(
3649
        $userId,
3650
        $sessionId
3651
    );
3652
3653
    // Session visibility.
3654
    $visibility = api_get_session_visibility(
3655
        $sessionId,
3656
        null,
3657
        false
3658
    );
3659
3660
    if (SESSION_VISIBLE != $visibility && !empty($courseList)) {
3661
        // Course Coach session visibility.
3662
        $blockedCourseCount = 0;
3663
        $closedVisibilityList = [
3664
            COURSE_VISIBILITY_CLOSED,
3665
            COURSE_VISIBILITY_HIDDEN,
3666
        ];
3667
3668
        foreach ($courseList as $course) {
3669
            // Checking session visibility
3670
            $sessionCourseVisibility = api_get_session_visibility(
3671
                $sessionId,
3672
                $course['real_id']
3673
            );
3674
3675
            $courseIsVisible = !in_array(
3676
                $course['visibility'],
3677
                $closedVisibilityList
3678
            );
3679
            if (false === $courseIsVisible || SESSION_INVISIBLE == $sessionCourseVisibility) {
3680
                $blockedCourseCount++;
3681
            }
3682
        }
3683
3684
        // If all courses are blocked then no show in the list.
3685
        if ($blockedCourseCount === count($courseList)) {
3686
            $visibility = SESSION_INVISIBLE;
3687
        } else {
3688
            $visibility = SESSION_VISIBLE;
3689
        }
3690
    }
3691
3692
    switch ($visibility) {
3693
        case SESSION_VISIBLE_READ_ONLY:
3694
        case SESSION_VISIBLE:
3695
        case SESSION_AVAILABLE:
3696
            return true;
3697
            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...
3698
        case SESSION_INVISIBLE:
3699
            return false;
3700
    }
3701
3702
    return false;
3703
}
3704
3705
/**
3706
 * Checks if a student can edit contents in a session depending
3707
 * on the session visibility.
3708
 *
3709
 * @param bool $tutor Whether to check if the user has the tutor role
3710
 * @param bool $coach Whether to check if the user has the coach role
3711
 *
3712
 * @return bool true: the user has the rights to edit, false: he does not
3713
 */
3714
function api_is_allowed_to_session_edit($tutor = false, $coach = false)
3715
{
3716
    if (api_is_allowed_to_edit($tutor, $coach)) {
3717
        // If I'm a teacher, I will return true in order to not affect the normal behaviour of Chamilo tools.
3718
        return true;
3719
    } else {
3720
        $sessionId = api_get_session_id();
3721
3722
        if (0 == $sessionId) {
3723
            // I'm not in a session so i will return true to not affect the normal behaviour of Chamilo tools.
3724
            return true;
3725
        } else {
3726
            // I'm in a session and I'm a student
3727
            // Get the session visibility
3728
            $session_visibility = api_get_session_visibility($sessionId);
3729
            // if 5 the session is still available
3730
            switch ($session_visibility) {
3731
                case SESSION_VISIBLE_READ_ONLY: // 1
3732
                    return false;
3733
                case SESSION_VISIBLE:           // 2
3734
                    return true;
3735
                case SESSION_INVISIBLE:         // 3
3736
                    return false;
3737
                case SESSION_AVAILABLE:         //5
3738
                    return true;
3739
            }
3740
        }
3741
    }
3742
3743
    return false;
3744
}
3745
3746
/**
3747
 * Checks whether the user is allowed in a specific tool for a specific action.
3748
 *
3749
 * @param string $tool   the tool we are checking if the user has a certain permission
3750
 * @param string $action the action we are checking (add, edit, delete, move, visibility)
3751
 *
3752
 * @return bool
3753
 *
3754
 * @author Patrick Cool <[email protected]>, Ghent University
3755
 * @author Julio Montoya
3756
 *
3757
 * @version 1.0
3758
 */
3759
function api_is_allowed($tool, $action, $task_id = 0)
3760
{
3761
    $_user = api_get_user_info();
3762
    $_course = api_get_course_info();
3763
3764
    if (api_is_course_admin()) {
3765
        return true;
3766
    }
3767
3768
    if (is_array($_course) and count($_course) > 0) {
3769
        require_once api_get_path(SYS_CODE_PATH).'permissions/permissions_functions.inc.php';
3770
3771
        // Getting the permissions of this user.
3772
        if (0 == $task_id) {
3773
            $user_permissions = get_permissions('user', $_user['user_id']);
3774
            $_SESSION['total_permissions'][$_course['code']] = $user_permissions;
3775
        }
3776
3777
        // Getting the permissions of the task.
3778
        if (0 != $task_id) {
3779
            $task_permissions = get_permissions('task', $task_id);
3780
            /* !!! */ $_SESSION['total_permissions'][$_course['code']] = $task_permissions;
3781
        }
3782
    }
3783
3784
    // If the permissions are limited, we have to map the extended ones to the limited ones.
3785
    if ('limited' == api_get_setting('permissions')) {
3786
        if ('Visibility' == $action) {
3787
            $action = 'Edit';
3788
        }
3789
        if ('Move' == $action) {
3790
            $action = 'Edit';
3791
        }
3792
    }
3793
3794
    // The session that contains all the permissions already exists for this course
3795
    // so there is no need to requery everything.
3796
    //my_print_r($_SESSION['total_permissions'][$_course['code']][$tool]);
3797
    if (is_array($_SESSION['total_permissions'][$_course['code']][$tool])) {
3798
        if (in_array($action, $_SESSION['total_permissions'][$_course['code']][$tool])) {
3799
            return true;
3800
        } else {
3801
            return false;
3802
        }
3803
    }
3804
3805
    return false;
3806
}
3807
3808
/**
3809
 * Tells whether this user is an anonymous user.
3810
 *
3811
 * @param int  $user_id  User ID (optional, will take session ID if not provided)
3812
 * @param bool $db_check Whether to check in the database (true) or simply in
3813
 *                       the session (false) to see if the current user is the anonymous user
3814
 *
3815
 * @return bool true if this user is anonymous, false otherwise
3816
 */
3817
function api_is_anonymous($user_id = null, $db_check = false)
3818
{
3819
    return !Container::getAuthorizationChecker()->isGranted('IS_AUTHENTICATED_FULLY');
3820
}
3821
3822
/**
3823
 * Displays message "You are not allowed here..." and exits the entire script.
3824
 *
3825
 * @param bool   $print_headers Whether or not to print headers (default = false -> does not print them)
3826
 * @param string $message
3827
 * @param int    $responseCode
3828
 */
3829
function api_not_allowed(
3830
    $print_headers = false,
3831
    $message = null,
3832
    $responseCode = 0
3833
) {
3834
    throw new Exception('You are not allowed');
3835
}
3836
3837
/**
3838
 * Gets a UNIX timestamp from a database (MySQL) datetime format string.
3839
 *
3840
 * @param $last_post_datetime standard output date in a sql query
3841
 *
3842
 * @return int timestamp
3843
 *
3844
 * @author Toon Van Hoecke <[email protected]>
3845
 *
3846
 * @version October 2003
3847
 * @desc convert sql date to unix timestamp
3848
 */
3849
function convert_sql_date($last_post_datetime)
3850
{
3851
    [$last_post_date, $last_post_time] = explode(' ', $last_post_datetime);
3852
    [$year, $month, $day] = explode('-', $last_post_date);
3853
    [$hour, $min, $sec] = explode(':', $last_post_time);
3854
3855
    return mktime((int) $hour, (int) $min, (int) $sec, (int) $month, (int) $day, (int) $year);
3856
}
3857
3858
/**
3859
 * Displays a combo box so the user can select his/her preferred language.
3860
 *
3861
 * @param string The desired name= value for the select
3862
 * @param bool Whether we use the JQuery Chozen library or not
3863
 * (in some cases, like the indexing language picker, it can alter the presentation)
3864
 *
3865
 * @deprecated
3866
 *
3867
 * @return string
3868
 */
3869
function api_get_languages_combo($name = 'language')
3870
{
3871
    $ret = '';
3872
    $platformLanguage = api_get_setting('platformLanguage');
3873
3874
    // Retrieve a complete list of all the languages.
3875
    $language_list = api_get_languages();
3876
3877
    if (count($language_list) < 2) {
3878
        return $ret;
3879
    }
3880
3881
    // The the current language of the user so that his/her language occurs as selected in the dropdown menu.
3882
    if (isset($_SESSION['user_language_choice'])) {
3883
        $default = $_SESSION['user_language_choice'];
3884
    } else {
3885
        $default = $platformLanguage;
3886
    }
3887
3888
    $ret .= '<select name="'.$name.'" id="language_chosen" class="selectpicker show-tick form-control">';
3889
    foreach ($language_list as $key => $value) {
3890
        if ($key == $default) {
3891
            $selected = ' selected="selected"';
3892
        } else {
3893
            $selected = '';
3894
        }
3895
        $ret .= sprintf('<option value=%s" %s>%s</option>', $key, $selected, $value);
3896
    }
3897
    $ret .= '</select>';
3898
3899
    return $ret;
3900
}
3901
3902
/**
3903
 * Displays a form (drop down menu) so the user can select his/her preferred language.
3904
 * The form works with or without javascript.
3905
 *
3906
 * @param  bool Hide form if only one language available (defaults to false = show the box anyway)
3907
 * @param bool $showAsButton
3908
 *
3909
 * @return string|null Display the box directly
3910
 */
3911
function api_display_language_form($hide_if_no_choice = false, $showAsButton = false)
3912
{
3913
    // Retrieve a complete list of all the languages.
3914
    $language_list = api_get_languages();
3915
    if (count($language_list['name']) <= 1 && $hide_if_no_choice) {
3916
        return; //don't show any form
3917
    }
3918
3919
    // The the current language of the user so that his/her language occurs as selected in the dropdown menu.
3920
    if (isset($_SESSION['user_language_choice'])) {
3921
        $user_selected_language = $_SESSION['user_language_choice'];
3922
    }
3923
    if (empty($user_selected_language)) {
3924
        $user_selected_language = api_get_setting('platformLanguage');
3925
    }
3926
3927
    $currentLanguageId = api_get_language_id($user_selected_language);
3928
    $currentLanguageInfo = api_get_language_info($currentLanguageId);
3929
    $countryCode = languageToCountryIsoCode($currentLanguageInfo['isocode']);
3930
    $url = api_get_self();
3931
    if ($showAsButton) {
3932
        $html = '<div class="btn-group">
3933
              <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
3934
                <span class="flag-icon flag-icon-'.$countryCode.'"></span>
3935
                '.$currentLanguageInfo['original_name'].'
3936
                <span class="caret">
3937
                </span>
3938
              </button>';
3939
    } else {
3940
        $html = '
3941
            <a href="'.$url.'" class="dropdown-toggle" data-toggle="dropdown" role="button">
3942
                <span class="flag-icon flag-icon-'.$countryCode.'"></span>
3943
                '.$currentLanguageInfo['original_name'].'
3944
                <span class="caret"></span>
3945
            </a>
3946
            ';
3947
    }
3948
3949
    $html .= '<ul class="dropdown-menu" role="menu">';
3950
    foreach ($language_list['all'] as $key => $data) {
3951
        $urlLink = $url.'?language='.$data['english_name'];
3952
        $html .= '<li><a href="'.$urlLink.'"><span class="flag-icon flag-icon-'.languageToCountryIsoCode($data['isocode']).'"></span> '.$data['original_name'].'</a></li>';
3953
    }
3954
    $html .= '</ul>';
3955
3956
    if ($showAsButton) {
3957
        $html .= '</div>';
3958
    }
3959
3960
    return $html;
3961
}
3962
3963
/**
3964
 * @param string $languageIsoCode
3965
 *
3966
 * @return string
3967
 */
3968
function languageToCountryIsoCode($languageIsoCode)
3969
{
3970
    $allow = api_get_configuration_value('language_flags_by_country');
3971
3972
    // @todo save in DB
3973
    switch ($languageIsoCode) {
3974
        case 'ar':
3975
            $country = 'ae';
3976
            break;
3977
        case 'bs':
3978
            $country = 'ba';
3979
            break;
3980
        case 'ca':
3981
            $country = 'es';
3982
            if ($allow) {
3983
                $country = 'catalan';
3984
            }
3985
            break;
3986
        case 'cs':
3987
            $country = 'cz';
3988
            break;
3989
        case 'da':
3990
            $country = 'dk';
3991
            break;
3992
        case 'el':
3993
            $country = 'ae';
3994
            break;
3995
        case 'en':
3996
            $country = 'gb';
3997
            break;
3998
        case 'eu': // Euskera
3999
            $country = 'es';
4000
            if ($allow) {
4001
                $country = 'basque';
4002
            }
4003
            break;
4004
        case 'gl': // galego
4005
            $country = 'es';
4006
            if ($allow) {
4007
                $country = 'galician';
4008
            }
4009
            break;
4010
        case 'he':
4011
            $country = 'il';
4012
            break;
4013
        case 'ja':
4014
            $country = 'jp';
4015
            break;
4016
        case 'ka':
4017
            $country = 'ge';
4018
            break;
4019
        case 'ko':
4020
            $country = 'kr';
4021
            break;
4022
        case 'ms':
4023
            $country = 'my';
4024
            break;
4025
        case 'pt-BR':
4026
            $country = 'br';
4027
            break;
4028
        case 'qu':
4029
            $country = 'pe';
4030
            break;
4031
        case 'sl':
4032
            $country = 'si';
4033
            break;
4034
        case 'sv':
4035
            $country = 'se';
4036
            break;
4037
        case 'uk': // Ukraine
4038
            $country = 'ua';
4039
            break;
4040
        case 'zh-TW':
4041
        case 'zh':
4042
            $country = 'cn';
4043
            break;
4044
        default:
4045
            $country = $languageIsoCode;
4046
            break;
4047
    }
4048
    $country = strtolower($country);
4049
4050
    return $country;
4051
}
4052
4053
/**
4054
 * Returns a list of all the languages that are made available by the admin.
4055
 *
4056
 * @return array An array with all languages. Structure of the array is
4057
 *               array['name'] = An array with the name of every language
4058
 *               array['folder'] = An array with the corresponding names of the language-folders in the filesystem
4059
 */
4060
function api_get_languages()
4061
{
4062
    $table = Database::get_main_table(TABLE_MAIN_LANGUAGE);
4063
    $sql = "SELECT * FROM $table WHERE available='1'
4064
            ORDER BY original_name ASC";
4065
    $result = Database::query($sql);
4066
    $languages = [];
4067
    while ($row = Database::fetch_array($result, 'ASSOC')) {
4068
        $languages[$row['isocode']] = $row['original_name'];
4069
    }
4070
4071
    return $languages;
4072
}
4073
4074
/**
4075
 * Returns a list of all the languages that are made available by the admin.
4076
 *
4077
 * @return array
4078
 */
4079
function api_get_languages_to_array()
4080
{
4081
    $tbl_language = Database::get_main_table(TABLE_MAIN_LANGUAGE);
4082
    $sql = "SELECT * FROM $tbl_language WHERE available='1' ORDER BY original_name ASC";
4083
    $result = Database::query($sql);
4084
    $languages = [];
4085
    while ($row = Database::fetch_array($result)) {
4086
        $languages[$row['english_name']] = $row['original_name'];
4087
    }
4088
4089
    return $languages;
4090
}
4091
4092
/**
4093
 * Returns the id (the database id) of a language.
4094
 *
4095
 * @param   string  language name (the corresponding name of the language-folder in the filesystem)
4096
 *
4097
 * @return int id of the language
4098
 */
4099
function api_get_language_id($language)
4100
{
4101
    $tbl_language = Database::get_main_table(TABLE_MAIN_LANGUAGE);
4102
    if (empty($language)) {
4103
        return null;
4104
    }
4105
    $language = Database::escape_string($language);
4106
    $sql = "SELECT id FROM $tbl_language
4107
            WHERE english_name = '$language' LIMIT 1";
4108
    $result = Database::query($sql);
4109
    $row = Database::fetch_array($result);
4110
4111
    return $row['id'];
4112
}
4113
4114
/**
4115
 * Get the language information by its id.
4116
 *
4117
 * @param int $languageId
4118
 *
4119
 * @throws Exception
4120
 *
4121
 * @return array
4122
 */
4123
function api_get_language_info($languageId)
4124
{
4125
    if (empty($languageId)) {
4126
        return [];
4127
    }
4128
4129
    $language = Database::getManager()->find(Language::class, $languageId);
4130
4131
    if (!$language) {
4132
        return [];
4133
    }
4134
4135
    return [
4136
        'id' => $language->getId(),
4137
        'original_name' => $language->getOriginalName(),
4138
        'english_name' => $language->getEnglishName(),
4139
        'isocode' => $language->getIsocode(),
4140
        'available' => $language->getAvailable(),
4141
        'parent_id' => $language->getParent() ? $language->getParent()->getId() : null,
4142
    ];
4143
}
4144
4145
/**
4146
 * @param string $code
4147
 *
4148
 * @return Language
4149
 */
4150
function api_get_language_from_iso($code)
4151
{
4152
    $em = Database::getManager();
4153
4154
    return $em->getRepository(Language::class)->findOneBy(['isocode' => $code]);
4155
}
4156
4157
/**
4158
 * Returns the name of the visual (CSS) theme to be applied on the current page.
4159
 * The returned name depends on the platform, course or user -wide settings.
4160
 *
4161
 * @return string The visual theme's name, it is the name of a folder inside web/css/themes
4162
 */
4163
function api_get_visual_theme()
4164
{
4165
    static $visual_theme;
4166
    if (!isset($visual_theme)) {
4167
        // Get style directly from DB
4168
        /*$styleFromDatabase = api_get_settings_params_simple(
4169
            [
4170
                'variable = ? AND access_url = ?' => [
4171
                    'stylesheets',
4172
                    api_get_current_access_url_id(),
4173
                ],
4174
            ]
4175
        );
4176
4177
        if ($styleFromDatabase) {
4178
            $platform_theme = $styleFromDatabase['selected_value'];
4179
        } else {
4180
            $platform_theme = api_get_setting('stylesheets');
4181
        }*/
4182
        $platform_theme = api_get_setting('stylesheets');
4183
4184
        // Platform's theme.
4185
        $visual_theme = $platform_theme;
4186
        if ('true' == api_get_setting('user_selected_theme')) {
4187
            $user_info = api_get_user_info();
4188
            if (isset($user_info['theme'])) {
4189
                $user_theme = $user_info['theme'];
4190
4191
                if (!empty($user_theme)) {
4192
                    $visual_theme = $user_theme;
4193
                    // User's theme.
4194
                }
4195
            }
4196
        }
4197
4198
        $course_id = api_get_course_id();
4199
        if (!empty($course_id)) {
4200
            if ('true' == api_get_setting('allow_course_theme')) {
4201
                $course_theme = api_get_course_setting('course_theme', $course_id);
4202
4203
                if (!empty($course_theme) && -1 != $course_theme) {
4204
                    if (!empty($course_theme)) {
4205
                        // Course's theme.
4206
                        $visual_theme = $course_theme;
4207
                    }
4208
                }
4209
4210
                $allow_lp_theme = api_get_course_setting('allow_learning_path_theme');
4211
                if (1 == $allow_lp_theme) {
4212
                    /*global $lp_theme_css, $lp_theme_config;
4213
                    // These variables come from the file lp_controller.php.
4214
                    if (!$lp_theme_config) {
4215
                        if (!empty($lp_theme_css)) {
4216
                            // LP's theme.
4217
                            $visual_theme = $lp_theme_css;
4218
                        }
4219
                    }*/
4220
                }
4221
            }
4222
        }
4223
4224
        if (empty($visual_theme)) {
4225
            $visual_theme = 'chamilo';
4226
        }
4227
4228
        /*global $lp_theme_log;
4229
        if ($lp_theme_log) {
4230
            $visual_theme = $platform_theme;
4231
        }*/
4232
    }
4233
4234
    return $visual_theme;
4235
}
4236
4237
/**
4238
 * Returns a list of CSS themes currently available in the CSS folder
4239
 * The folder must have a default.css file.
4240
 *
4241
 * @param bool $getOnlyThemeFromVirtualInstance Used by the vchamilo plugin
4242
 *
4243
 * @return array list of themes directories from the css folder
4244
 *               Note: Directory names (names of themes) in the file system should contain ASCII-characters only
4245
 */
4246
function api_get_themes($getOnlyThemeFromVirtualInstance = false)
4247
{
4248
    // This configuration value is set by the vchamilo plugin
4249
    $virtualTheme = api_get_configuration_value('virtual_css_theme_folder');
4250
4251
    $readCssFolder = function ($dir) use ($virtualTheme) {
4252
        $finder = new Finder();
4253
        $themes = $finder->directories()->in($dir)->depth(0)->sortByName();
4254
        $list = [];
4255
        /** @var Symfony\Component\Finder\SplFileInfo $theme */
4256
        foreach ($themes as $theme) {
4257
            $folder = $theme->getFilename();
4258
            // A theme folder is consider if there's a default.css file
4259
            if (!file_exists($theme->getPathname().'/default.css')) {
4260
                continue;
4261
            }
4262
            $name = ucwords(str_replace('_', ' ', $folder));
4263
            if ($folder == $virtualTheme) {
4264
                continue;
4265
            }
4266
            $list[$folder] = $name;
4267
        }
4268
4269
        return $list;
4270
    };
4271
4272
    $dir = api_get_path(SYS_CSS_PATH).'themes/';
4273
    $list = $readCssFolder($dir);
4274
4275
    if (!empty($virtualTheme)) {
4276
        $newList = $readCssFolder($dir.'/'.$virtualTheme);
4277
        if ($getOnlyThemeFromVirtualInstance) {
4278
            return $newList;
4279
        }
4280
        $list = $list + $newList;
4281
        asort($list);
4282
    }
4283
4284
    return $list;
4285
}
4286
4287
/**
4288
 * Find the largest sort value in a given user_course_category
4289
 * This function is used when we are moving a course to a different category
4290
 * and also when a user subscribes to courses (the new course is added at the end of the main category.
4291
 *
4292
 * @param int $courseCategoryId the id of the user_course_category
4293
 * @param int $userId
4294
 *
4295
 * @return int the value of the highest sort of the user_course_category
4296
 */
4297
function api_max_sort_value($courseCategoryId, $userId)
4298
{
4299
    $user = api_get_user_entity($userId);
4300
    $userCourseCategory = Database::getManager()->getRepository(UserCourseCategory::class)->find($courseCategoryId);
4301
4302
    return null === $user ? 0 : $user->getMaxSortValue($userCourseCategory);
4303
}
4304
4305
/**
4306
 * Transforms a number of seconds in hh:mm:ss format.
4307
 *
4308
 * @author Julian Prud'homme
4309
 *
4310
 * @param int    $seconds      number of seconds
4311
 * @param string $space
4312
 * @param bool   $showSeconds
4313
 * @param bool   $roundMinutes
4314
 *
4315
 * @return string the formatted time
4316
 */
4317
function api_time_to_hms($seconds, $space = ':', $showSeconds = true, $roundMinutes = false)
4318
{
4319
    // $seconds = -1 means that we have wrong data in the db.
4320
    if (-1 == $seconds) {
4321
        return
4322
            get_lang('Unknown').
4323
            Display::return_icon(
4324
                'info2.gif',
4325
                get_lang('The datas about this user were registered when the calculation of time spent on the platform wasn\'t possible.'),
4326
                ['align' => 'absmiddle', 'hspace' => '3px']
4327
            );
4328
    }
4329
4330
    // How many hours ?
4331
    $hours = floor($seconds / 3600);
4332
4333
    // How many minutes ?
4334
    $min = floor(($seconds - ($hours * 3600)) / 60);
4335
4336
    if ($roundMinutes) {
4337
        if ($min >= 45) {
4338
            $min = 45;
4339
        }
4340
4341
        if ($min >= 30 && $min <= 44) {
4342
            $min = 30;
4343
        }
4344
4345
        if ($min >= 15 && $min <= 29) {
4346
            $min = 15;
4347
        }
4348
4349
        if ($min >= 0 && $min <= 14) {
4350
            $min = 0;
4351
        }
4352
    }
4353
4354
    // How many seconds
4355
    $sec = floor($seconds - ($hours * 3600) - ($min * 60));
4356
4357
    if ($hours < 10) {
4358
        $hours = "0$hours";
4359
    }
4360
4361
    if ($sec < 10) {
4362
        $sec = "0$sec";
4363
    }
4364
4365
    if ($min < 10) {
4366
        $min = "0$min";
4367
    }
4368
4369
    $seconds = '';
4370
    if ($showSeconds) {
4371
        $seconds = $space.$sec;
4372
    }
4373
4374
    return $hours.$space.$min.$seconds;
4375
}
4376
4377
/* FILE SYSTEM RELATED FUNCTIONS */
4378
4379
/**
4380
 * Returns the permissions to be assigned to every newly created directory by the web-server.
4381
 * The return value is based on the platform administrator's setting
4382
 * "Administration > Configuration settings > Security > Permissions for new directories".
4383
 *
4384
 * @return int returns the permissions in the format "Owner-Group-Others, Read-Write-Execute", as an integer value
4385
 */
4386
function api_get_permissions_for_new_directories()
4387
{
4388
    static $permissions;
4389
    if (!isset($permissions)) {
4390
        $permissions = trim(api_get_setting('permissions_for_new_directories'));
4391
        // The default value 0777 is according to that in the platform administration panel after fresh system installation.
4392
        $permissions = octdec(!empty($permissions) ? $permissions : '0777');
4393
    }
4394
4395
    return $permissions;
4396
}
4397
4398
/**
4399
 * Returns the permissions to be assigned to every newly created directory by the web-server.
4400
 * The return value is based on the platform administrator's setting
4401
 * "Administration > Configuration settings > Security > Permissions for new files".
4402
 *
4403
 * @return int returns the permissions in the format
4404
 *             "Owner-Group-Others, Read-Write-Execute", as an integer value
4405
 */
4406
function api_get_permissions_for_new_files()
4407
{
4408
    static $permissions;
4409
    if (!isset($permissions)) {
4410
        $permissions = trim(api_get_setting('permissions_for_new_files'));
4411
        // The default value 0666 is according to that in the platform
4412
        // administration panel after fresh system installation.
4413
        $permissions = octdec(!empty($permissions) ? $permissions : '0666');
4414
    }
4415
4416
    return $permissions;
4417
}
4418
4419
/**
4420
 * Deletes a file, or a folder and its contents.
4421
 *
4422
 * @author      Aidan Lister <[email protected]>
4423
 *
4424
 * @version     1.0.3
4425
 *
4426
 * @param string $dirname Directory to delete
4427
 * @param       bool     Deletes only the content or not
4428
 * @param bool $strict if one folder/file fails stop the loop
4429
 *
4430
 * @return bool Returns TRUE on success, FALSE on failure
4431
 *
4432
 * @see http://aidanlister.com/2004/04/recursively-deleting-a-folder-in-php/
4433
 *
4434
 * @author      Yannick Warnier, adaptation for the Chamilo LMS, April, 2008
4435
 * @author      Ivan Tcholakov, a sanity check about Directory class creation has been added, September, 2009
4436
 */
4437
function rmdirr($dirname, $delete_only_content_in_folder = false, $strict = false)
4438
{
4439
    $res = true;
4440
    // A sanity check.
4441
    if (!file_exists($dirname)) {
4442
        return false;
4443
    }
4444
    $php_errormsg = '';
4445
    // Simple delete for a file.
4446
    if (is_file($dirname) || is_link($dirname)) {
4447
        $res = unlink($dirname);
4448
        if (false === $res) {
4449
            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);
4450
        }
4451
4452
        return $res;
4453
    }
4454
4455
    // Loop through the folder.
4456
    $dir = dir($dirname);
4457
    // A sanity check.
4458
    $is_object_dir = is_object($dir);
4459
    if ($is_object_dir) {
4460
        while (false !== $entry = $dir->read()) {
4461
            // Skip pointers.
4462
            if ('.' == $entry || '..' == $entry) {
4463
                continue;
4464
            }
4465
4466
            // Recurse.
4467
            if ($strict) {
4468
                $result = rmdirr("$dirname/$entry");
4469
                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...
4470
                    $res = false;
4471
                    break;
4472
                }
4473
            } else {
4474
                rmdirr("$dirname/$entry");
4475
            }
4476
        }
4477
    }
4478
4479
    // Clean up.
4480
    if ($is_object_dir) {
4481
        $dir->close();
4482
    }
4483
4484
    if (false == $delete_only_content_in_folder) {
4485
        $res = rmdir($dirname);
4486
        if (false === $res) {
4487
            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);
4488
        }
4489
    }
4490
4491
    return $res;
4492
}
4493
4494
// TODO: This function is to be simplified. File access modes to be implemented.
4495
/**
4496
 * function adapted from a php.net comment
4497
 * copy recursively a folder.
4498
 *
4499
 * @param the source folder
4500
 * @param the dest folder
4501
 * @param an array of excluded file_name (without extension)
4502
 * @param copied_files the returned array of copied files
4503
 * @param string $source
4504
 * @param string $dest
4505
 */
4506
function copyr($source, $dest, $exclude = [], $copied_files = [])
4507
{
4508
    if (empty($dest)) {
4509
        return false;
4510
    }
4511
    // Simple copy for a file
4512
    if (is_file($source)) {
4513
        $path_info = pathinfo($source);
4514
        if (!in_array($path_info['filename'], $exclude)) {
4515
            copy($source, $dest);
4516
        }
4517
4518
        return true;
4519
    } elseif (!is_dir($source)) {
4520
        //then source is not a dir nor a file, return
4521
        return false;
4522
    }
4523
4524
    // Make destination directory.
4525
    if (!is_dir($dest)) {
4526
        mkdir($dest, api_get_permissions_for_new_directories());
4527
    }
4528
4529
    // Loop through the folder.
4530
    $dir = dir($source);
4531
    while (false !== $entry = $dir->read()) {
4532
        // Skip pointers
4533
        if ('.' == $entry || '..' == $entry) {
4534
            continue;
4535
        }
4536
4537
        // Deep copy directories.
4538
        if ($dest !== "$source/$entry") {
4539
            $files = copyr("$source/$entry", "$dest/$entry", $exclude, $copied_files);
4540
        }
4541
    }
4542
    // Clean up.
4543
    $dir->close();
4544
4545
    return true;
4546
}
4547
4548
/**
4549
 * @todo: Using DIRECTORY_SEPARATOR is not recommended, this is an obsolete approach.
4550
 * Documentation header to be added here.
4551
 *
4552
 * @param string $pathname
4553
 * @param string $base_path_document
4554
 * @param int    $session_id
4555
 *
4556
 * @return mixed True if directory already exists, false if a file already exists at
4557
 *               the destination and null if everything goes according to plan
4558
 */
4559
function copy_folder_course_session(
4560
    $pathname,
4561
    $base_path_document,
4562
    $session_id,
4563
    $course_info,
4564
    $document,
4565
    $source_course_id
4566
) {
4567
    $table = Database::get_course_table(TABLE_DOCUMENT);
4568
    $session_id = intval($session_id);
4569
    $source_course_id = intval($source_course_id);
4570
4571
    // Check whether directory already exists.
4572
    if (is_dir($pathname) || empty($pathname)) {
4573
        return true;
4574
    }
4575
4576
    // Ensure that a file with the same name does not already exist.
4577
    if (is_file($pathname)) {
4578
        trigger_error('copy_folder_course_session(): File exists', E_USER_WARNING);
4579
4580
        return false;
4581
    }
4582
4583
    $course_id = $course_info['real_id'];
4584
    $folders = explode(DIRECTORY_SEPARATOR, str_replace($base_path_document.DIRECTORY_SEPARATOR, '', $pathname));
4585
    $new_pathname = $base_path_document;
4586
    $path = '';
4587
4588
    foreach ($folders as $folder) {
4589
        $new_pathname .= DIRECTORY_SEPARATOR.$folder;
4590
        $path .= DIRECTORY_SEPARATOR.$folder;
4591
4592
        if (!file_exists($new_pathname)) {
4593
            $path = Database::escape_string($path);
4594
4595
            $sql = "SELECT * FROM $table
4596
                    WHERE
4597
                        c_id = $source_course_id AND
4598
                        path = '$path' AND
4599
                        filetype = 'folder' AND
4600
                        session_id = '$session_id'";
4601
            $rs1 = Database::query($sql);
4602
            $num_rows = Database::num_rows($rs1);
4603
4604
            if (0 == $num_rows) {
4605
                mkdir($new_pathname, api_get_permissions_for_new_directories());
4606
4607
                // Insert new folder with destination session_id.
4608
                $params = [
4609
                    'c_id' => $course_id,
4610
                    'path' => $path,
4611
                    'comment' => $document->comment,
4612
                    'title' => basename($new_pathname),
4613
                    'filetype' => 'folder',
4614
                    'size' => '0',
4615
                    'session_id' => $session_id,
4616
                ];
4617
                Database::insert($table, $params);
4618
            }
4619
        }
4620
    } // en foreach
4621
}
4622
4623
// TODO: chmodr() is a better name. Some corrections are needed. Documentation header to be added here.
4624
/**
4625
 * @param string $path
4626
 */
4627
function api_chmod_R($path, $filemode)
4628
{
4629
    if (!is_dir($path)) {
4630
        return chmod($path, $filemode);
4631
    }
4632
4633
    $handler = opendir($path);
4634
    while ($file = readdir($handler)) {
4635
        if ('.' != $file && '..' != $file) {
4636
            $fullpath = "$path/$file";
4637
            if (!is_dir($fullpath)) {
4638
                if (!chmod($fullpath, $filemode)) {
4639
                    return false;
4640
                }
4641
            } else {
4642
                if (!api_chmod_R($fullpath, $filemode)) {
4643
                    return false;
4644
                }
4645
            }
4646
        }
4647
    }
4648
4649
    closedir($handler);
4650
4651
    return chmod($path, $filemode);
4652
}
4653
4654
// TODO: Where the following function has been copy/pased from? There is no information about author and license. Style, coding conventions...
4655
/**
4656
 * Parse info file format. (e.g: file.info).
4657
 *
4658
 * Files should use an ini-like format to specify values.
4659
 * White-space generally doesn't matter, except inside values.
4660
 * e.g.
4661
 *
4662
 * @verbatim
4663
 *   key = value
4664
 *   key = "value"
4665
 *   key = 'value'
4666
 *   key = "multi-line
4667
 *
4668
 *   value"
4669
 *   key = 'multi-line
4670
 *
4671
 *   value'
4672
 *   key
4673
 *   =
4674
 *   'value'
4675
 * @endverbatim
4676
 *
4677
 * Arrays are created using a GET-like syntax:
4678
 *
4679
 * @verbatim
4680
 *   key[] = "numeric array"
4681
 *   key[index] = "associative array"
4682
 *   key[index][] = "nested numeric array"
4683
 *   key[index][index] = "nested associative array"
4684
 * @endverbatim
4685
 *
4686
 * PHP constants are substituted in, but only when used as the entire value:
4687
 *
4688
 * Comments should start with a semi-colon at the beginning of a line.
4689
 *
4690
 * This function is NOT for placing arbitrary module-specific settings. Use
4691
 * variable_get() and variable_set() for that.
4692
 *
4693
 * Information stored in the module.info file:
4694
 * - name: The real name of the module for display purposes.
4695
 * - description: A brief description of the module.
4696
 * - dependencies: An array of shortnames of other modules this module depends on.
4697
 * - package: The name of the package of modules this module belongs to.
4698
 *
4699
 * Example of .info file:
4700
 * <code>
4701
 * @verbatim
4702
 *   name = Forum
4703
 *   description = Enables threaded discussions about general topics.
4704
 *   dependencies[] = taxonomy
4705
 *   dependencies[] = comment
4706
 *   package = Core - optional
4707
 *   version = VERSION
4708
 * @endverbatim
4709
 * </code>
4710
 *
4711
 * @param string $filename
4712
 *                         The file we are parsing. Accepts file with relative or absolute path.
4713
 *
4714
 * @return
4715
 *   The info array
4716
 */
4717
function api_parse_info_file($filename)
4718
{
4719
    $info = [];
4720
4721
    if (!file_exists($filename)) {
4722
        return $info;
4723
    }
4724
4725
    $data = file_get_contents($filename);
4726
    if (preg_match_all('
4727
        @^\s*                           # Start at the beginning of a line, ignoring leading whitespace
4728
        ((?:
4729
          [^=;\[\]]|                    # Key names cannot contain equal signs, semi-colons or square brackets,
4730
          \[[^\[\]]*\]                  # unless they are balanced and not nested
4731
        )+?)
4732
        \s*=\s*                         # Key/value pairs are separated by equal signs (ignoring white-space)
4733
        (?:
4734
          ("(?:[^"]|(?<=\\\\)")*")|     # Double-quoted string, which may contain slash-escaped quotes/slashes
4735
          (\'(?:[^\']|(?<=\\\\)\')*\')| # Single-quoted string, which may contain slash-escaped quotes/slashes
4736
          ([^\r\n]*?)                   # Non-quoted string
4737
        )\s*$                           # Stop at the next end of a line, ignoring trailing whitespace
4738
        @msx', $data, $matches, PREG_SET_ORDER)) {
4739
        $key = $value1 = $value2 = $value3 = '';
4740
        foreach ($matches as $match) {
4741
            // Fetch the key and value string.
4742
            $i = 0;
4743
            foreach (['key', 'value1', 'value2', 'value3'] as $var) {
4744
                $$var = isset($match[++$i]) ? $match[$i] : '';
4745
            }
4746
            $value = stripslashes(substr($value1, 1, -1)).stripslashes(substr($value2, 1, -1)).$value3;
4747
4748
            // Parse array syntax.
4749
            $keys = preg_split('/\]?\[/', rtrim($key, ']'));
4750
            $last = array_pop($keys);
4751
            $parent = &$info;
4752
4753
            // Create nested arrays.
4754
            foreach ($keys as $key) {
4755
                if ('' == $key) {
4756
                    $key = count($parent);
4757
                }
4758
                if (!isset($parent[$key]) || !is_array($parent[$key])) {
4759
                    $parent[$key] = [];
4760
                }
4761
                $parent = &$parent[$key];
4762
            }
4763
4764
            // Handle PHP constants.
4765
            if (defined($value)) {
4766
                $value = constant($value);
4767
            }
4768
4769
            // Insert actual value.
4770
            if ('' == $last) {
4771
                $last = count($parent);
4772
            }
4773
            $parent[$last] = $value;
4774
        }
4775
    }
4776
4777
    return $info;
4778
}
4779
4780
/**
4781
 * Gets Chamilo version from the configuration files.
4782
 *
4783
 * @return string A string of type "1.8.4", or an empty string if the version could not be found
4784
 */
4785
function api_get_version()
4786
{
4787
    return (string) api_get_configuration_value('system_version');
4788
}
4789
4790
/**
4791
 * Gets the software name (the name/brand of the Chamilo-based customized system).
4792
 *
4793
 * @return string
4794
 */
4795
function api_get_software_name()
4796
{
4797
    $name = api_get_configuration_value('software_name');
4798
    if (!empty($name)) {
4799
        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...
4800
    } else {
4801
        return 'Chamilo';
4802
    }
4803
}
4804
4805
function api_get_status_list()
4806
{
4807
    $list = [];
4808
    // Table of status
4809
    $list[COURSEMANAGER] = 'teacher'; // 1
4810
    $list[SESSIONADMIN] = 'session_admin'; // 3
4811
    $list[DRH] = 'drh'; // 4
4812
    $list[STUDENT] = 'user'; // 5
4813
    $list[ANONYMOUS] = 'anonymous'; // 6
4814
    $list[INVITEE] = 'invited'; // 20
4815
4816
    return $list;
4817
}
4818
4819
/**
4820
 * Checks whether status given in parameter exists in the platform.
4821
 *
4822
 * @param mixed the status (can be either int either string)
4823
 *
4824
 * @return bool if the status exists, else returns false
4825
 */
4826
function api_status_exists($status_asked)
4827
{
4828
    $list = api_get_status_list();
4829
4830
    return in_array($status_asked, $list) ? true : isset($list[$status_asked]);
4831
}
4832
4833
/**
4834
 * Checks whether status given in parameter exists in the platform. The function
4835
 * returns the status ID or false if it does not exist, but given the fact there
4836
 * is no "0" status, the return value can be checked against
4837
 * if(api_status_key()) to know if it exists.
4838
 *
4839
 * @param   mixed   The status (can be either int or string)
4840
 *
4841
 * @return mixed Status ID if exists, false otherwise
4842
 */
4843
function api_status_key($status)
4844
{
4845
    $list = api_get_status_list();
4846
4847
    return isset($list[$status]) ? $status : array_search($status, $list);
4848
}
4849
4850
/**
4851
 * Gets the status langvars list.
4852
 *
4853
 * @return string[] the list of status with their translations
4854
 */
4855
function api_get_status_langvars()
4856
{
4857
    return [
4858
        COURSEMANAGER => get_lang('Teacher'),
4859
        SESSIONADMIN => get_lang('SessionsAdmin'),
4860
        DRH => get_lang('Human Resources Manager'),
4861
        STUDENT => get_lang('Learner'),
4862
        ANONYMOUS => get_lang('Anonymous'),
4863
        STUDENT_BOSS => get_lang('RoleStudentBoss'),
4864
        INVITEE => get_lang('Invited'),
4865
    ];
4866
}
4867
4868
/**
4869
 * The function that retrieves all the possible settings for a certain config setting.
4870
 *
4871
 * @author Patrick Cool <[email protected]>, Ghent University
4872
 */
4873
function api_get_settings_options($var)
4874
{
4875
    $table_settings_options = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
4876
    $var = Database::escape_string($var);
4877
    $sql = "SELECT * FROM $table_settings_options
4878
            WHERE variable = '$var'
4879
            ORDER BY id";
4880
    $result = Database::query($sql);
4881
    $settings_options_array = [];
4882
    while ($row = Database::fetch_array($result, 'ASSOC')) {
4883
        $settings_options_array[] = $row;
4884
    }
4885
4886
    return $settings_options_array;
4887
}
4888
4889
/**
4890
 * @param array $params
4891
 */
4892
function api_set_setting_option($params)
4893
{
4894
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
4895
    if (empty($params['id'])) {
4896
        Database::insert($table, $params);
4897
    } else {
4898
        Database::update($table, $params, ['id = ? ' => $params['id']]);
4899
    }
4900
}
4901
4902
/**
4903
 * @param array $params
4904
 */
4905
function api_set_setting_simple($params)
4906
{
4907
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
4908
    $url_id = api_get_current_access_url_id();
4909
4910
    if (empty($params['id'])) {
4911
        $params['access_url'] = $url_id;
4912
        Database::insert($table, $params);
4913
    } else {
4914
        Database::update($table, $params, ['id = ? ' => [$params['id']]]);
4915
    }
4916
}
4917
4918
/**
4919
 * @param int $id
4920
 */
4921
function api_delete_setting_option($id)
4922
{
4923
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
4924
    if (!empty($id)) {
4925
        Database::delete($table, ['id = ? ' => $id]);
4926
    }
4927
}
4928
4929
/**
4930
 * Sets a platform configuration setting to a given value.
4931
 *
4932
 * @param string    The variable we want to update
4933
 * @param string    The value we want to record
4934
 * @param string    The sub-variable if any (in most cases, this will remain null)
4935
 * @param string    The category if any (in most cases, this will remain null)
4936
 * @param int       The access_url for which this parameter is valid
4937
 * @param string $cat
4938
 *
4939
 * @return bool|null
4940
 */
4941
function api_set_setting($var, $value, $subvar = null, $cat = null, $access_url = 1)
4942
{
4943
    if (empty($var)) {
4944
        return false;
4945
    }
4946
    $t_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
4947
    $var = Database::escape_string($var);
4948
    $value = Database::escape_string($value);
4949
    $access_url = (int) $access_url;
4950
    if (empty($access_url)) {
4951
        $access_url = 1;
4952
    }
4953
    $select = "SELECT id FROM $t_settings WHERE variable = '$var' ";
4954
    if (!empty($subvar)) {
4955
        $subvar = Database::escape_string($subvar);
4956
        $select .= " AND subkey = '$subvar'";
4957
    }
4958
    if (!empty($cat)) {
4959
        $cat = Database::escape_string($cat);
4960
        $select .= " AND category = '$cat'";
4961
    }
4962
    if ($access_url > 1) {
4963
        $select .= " AND access_url = $access_url";
4964
    } else {
4965
        $select .= " AND access_url = 1 ";
4966
    }
4967
4968
    $res = Database::query($select);
4969
    if (Database::num_rows($res) > 0) {
4970
        // Found item for this access_url.
4971
        $row = Database::fetch_array($res);
4972
        $sql = "UPDATE $t_settings SET selected_value = '$value'
4973
                WHERE id = ".$row['id'];
4974
        Database::query($sql);
4975
    } else {
4976
        // Item not found for this access_url, we have to check if it exist with access_url = 1
4977
        $select = "SELECT * FROM $t_settings
4978
                   WHERE variable = '$var' AND access_url = 1 ";
4979
        // Just in case
4980
        if (1 == $access_url) {
4981
            if (!empty($subvar)) {
4982
                $select .= " AND subkey = '$subvar'";
4983
            }
4984
            if (!empty($cat)) {
4985
                $select .= " AND category = '$cat'";
4986
            }
4987
            $res = Database::query($select);
4988
            if (Database::num_rows($res) > 0) {
4989
                // We have a setting for access_url 1, but none for the current one, so create one.
4990
                $row = Database::fetch_array($res);
4991
                $insert = "INSERT INTO $t_settings (variable, subkey, type,category, selected_value, title, comment, scope, subkeytext, access_url)
4992
                        VALUES
4993
                        ('".$row['variable']."',".(!empty($row['subkey']) ? "'".$row['subkey']."'" : "NULL").",".
4994
                    "'".$row['type']."','".$row['category']."',".
4995
                    "'$value','".$row['title']."',".
4996
                    "".(!empty($row['comment']) ? "'".$row['comment']."'" : "NULL").",".(!empty($row['scope']) ? "'".$row['scope']."'" : "NULL").",".
4997
                    "".(!empty($row['subkeytext']) ? "'".$row['subkeytext']."'" : "NULL").",$access_url)";
4998
                Database::query($insert);
4999
            } else {
5000
                // Such a setting does not exist.
5001
                //error_log(__FILE__.':'.__LINE__.': Attempting to update setting '.$var.' ('.$subvar.') which does not exist at all', 0);
5002
            }
5003
        } else {
5004
            // Other access url.
5005
            if (!empty($subvar)) {
5006
                $select .= " AND subkey = '$subvar'";
5007
            }
5008
            if (!empty($cat)) {
5009
                $select .= " AND category = '$cat'";
5010
            }
5011
            $res = Database::query($select);
5012
5013
            if (Database::num_rows($res) > 0) {
5014
                // We have a setting for access_url 1, but none for the current one, so create one.
5015
                $row = Database::fetch_array($res);
5016
                if (1 == $row['access_url_changeable']) {
5017
                    $insert = "INSERT INTO $t_settings (variable,subkey, type,category, selected_value,title, comment,scope, subkeytext,access_url, access_url_changeable) VALUES
5018
                            ('".$row['variable']."',".
5019
                        (!empty($row['subkey']) ? "'".$row['subkey']."'" : "NULL").",".
5020
                        "'".$row['type']."','".$row['category']."',".
5021
                        "'$value','".$row['title']."',".
5022
                        "".(!empty($row['comment']) ? "'".$row['comment']."'" : "NULL").",".
5023
                        (!empty($row['scope']) ? "'".$row['scope']."'" : "NULL").",".
5024
                        "".(!empty($row['subkeytext']) ? "'".$row['subkeytext']."'" : "NULL").",$access_url,".$row['access_url_changeable'].")";
5025
                    Database::query($insert);
5026
                }
5027
            } else { // Such a setting does not exist.
5028
                //error_log(__FILE__.':'.__LINE__.': Attempting to update setting '.$var.' ('.$subvar.') which does not exist at all. The access_url is: '.$access_url.' ',0);
5029
            }
5030
        }
5031
    }
5032
}
5033
5034
/**
5035
 * Sets a whole category of settings to one specific value.
5036
 *
5037
 * @param string    Category
5038
 * @param string    Value
5039
 * @param int       Access URL. Optional. Defaults to 1
5040
 * @param array     Optional array of filters on field type
5041
 * @param string $category
5042
 * @param string $value
5043
 *
5044
 * @return bool
5045
 */
5046
function api_set_settings_category($category, $value = null, $access_url = 1, $fieldtype = [])
5047
{
5048
    if (empty($category)) {
5049
        return false;
5050
    }
5051
    $category = Database::escape_string($category);
5052
    $t_s = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5053
    $access_url = (int) $access_url;
5054
    if (empty($access_url)) {
5055
        $access_url = 1;
5056
    }
5057
    if (isset($value)) {
5058
        $value = Database::escape_string($value);
5059
        $sql = "UPDATE $t_s SET selected_value = '$value'
5060
                WHERE category = '$category' AND access_url = $access_url";
5061
        if (is_array($fieldtype) && count($fieldtype) > 0) {
5062
            $sql .= " AND ( ";
5063
            $i = 0;
5064
            foreach ($fieldtype as $type) {
5065
                if ($i > 0) {
5066
                    $sql .= ' OR ';
5067
                }
5068
                $type = Database::escape_string($type);
5069
                $sql .= " type='".$type."' ";
5070
                $i++;
5071
            }
5072
            $sql .= ")";
5073
        }
5074
        $res = Database::query($sql);
5075
5076
        return false !== $res;
5077
    } else {
5078
        $sql = "UPDATE $t_s SET selected_value = NULL
5079
                WHERE category = '$category' AND access_url = $access_url";
5080
        if (is_array($fieldtype) && count($fieldtype) > 0) {
5081
            $sql .= " AND ( ";
5082
            $i = 0;
5083
            foreach ($fieldtype as $type) {
5084
                if ($i > 0) {
5085
                    $sql .= ' OR ';
5086
                }
5087
                $type = Database::escape_string($type);
5088
                $sql .= " type='".$type."' ";
5089
                $i++;
5090
            }
5091
            $sql .= ")";
5092
        }
5093
        $res = Database::query($sql);
5094
5095
        return false !== $res;
5096
    }
5097
}
5098
5099
/**
5100
 * Gets all available access urls in an array (as in the database).
5101
 *
5102
 * @return array An array of database records
5103
 */
5104
function api_get_access_urls($from = 0, $to = 1000000, $order = 'url', $direction = 'ASC')
5105
{
5106
    $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5107
    $from = (int) $from;
5108
    $to = (int) $to;
5109
    $order = Database::escape_string($order);
5110
    $direction = Database::escape_string($direction);
5111
    $direction = !in_array(strtolower(trim($direction)), ['asc', 'desc']) ? 'asc' : $direction;
5112
    $sql = "SELECT id, url, description, active, created_by, tms
5113
            FROM $table
5114
            ORDER BY `$order` $direction
5115
            LIMIT $to OFFSET $from";
5116
    $res = Database::query($sql);
5117
5118
    return Database::store_result($res);
5119
}
5120
5121
/**
5122
 * Gets the access url info in an array.
5123
 *
5124
 * @param int  $id            Id of the access url
5125
 * @param bool $returnDefault Set to false if you want the real URL if URL 1 is still 'http://localhost/'
5126
 *
5127
 * @return array All the info (url, description, active, created_by, tms)
5128
 *               from the access_url table
5129
 *
5130
 * @author Julio Montoya
5131
 */
5132
function api_get_access_url($id, $returnDefault = true)
5133
{
5134
    static $staticResult;
5135
    $id = (int) $id;
5136
5137
    if (isset($staticResult[$id])) {
5138
        $result = $staticResult[$id];
5139
    } else {
5140
        // Calling the Database:: library dont work this is handmade.
5141
        $table_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5142
        $sql = "SELECT url, description, active, created_by, tms
5143
                FROM $table_access_url WHERE id = '$id' ";
5144
        $res = Database::query($sql);
5145
        $result = @Database::fetch_array($res);
5146
        $staticResult[$id] = $result;
5147
    }
5148
5149
    // If the result url is 'http://localhost/' (the default) and the root_web
5150
    // (=current url) is different, and the $id is = 1 (which might mean
5151
    // api_get_current_access_url_id() returned 1 by default), then return the
5152
    // root_web setting instead of the current URL
5153
    // This is provided as an option to avoid breaking the storage of URL-specific
5154
    // homepages in home/localhost/
5155
    if (1 === $id && false === $returnDefault) {
5156
        $currentUrl = api_get_current_access_url_id();
5157
        // only do this if we are on the main URL (=1), otherwise we could get
5158
        // information on another URL instead of the one asked as parameter
5159
        if (1 === $currentUrl) {
5160
            $rootWeb = api_get_path(WEB_PATH);
5161
            $default = 'http://localhost/';
5162
            if ($result['url'] === $default && $rootWeb != $default) {
5163
                $result['url'] = $rootWeb;
5164
            }
5165
        }
5166
    }
5167
5168
    return $result;
5169
}
5170
5171
/**
5172
 * Gets all the current settings for a specific access url.
5173
 *
5174
 * @param string    The category, if any, that we want to get
5175
 * @param string    Whether we want a simple list (display a category) or
5176
 * a grouped list (group by variable as in settings.php default). Values: 'list' or 'group'
5177
 * @param int       Access URL's ID. Optional. Uses 1 by default, which is the unique URL
5178
 *
5179
 * @return array Array of database results for the current settings of the current access URL
5180
 */
5181
function &api_get_settings($cat = null, $ordering = 'list', $access_url = 1, $url_changeable = 0)
5182
{
5183
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5184
    $access_url = (int) $access_url;
5185
    $where_condition = '';
5186
    if (1 == $url_changeable) {
5187
        $where_condition = " AND access_url_changeable= '1' ";
5188
    }
5189
    if (empty($access_url) || -1 == $access_url) {
5190
        $access_url = 1;
5191
    }
5192
    $sql = "SELECT * FROM $table
5193
            WHERE access_url = $access_url  $where_condition ";
5194
5195
    if (!empty($cat)) {
5196
        $cat = Database::escape_string($cat);
5197
        $sql .= " AND category='$cat' ";
5198
    }
5199
    if ('group' == $ordering) {
5200
        $sql .= " ORDER BY id ASC";
5201
    } else {
5202
        $sql .= " ORDER BY 1,2 ASC";
5203
    }
5204
    $result = Database::query($sql);
5205
    if (null === $result) {
5206
        return [];
5207
    }
5208
    $result = Database::store_result($result, 'ASSOC');
5209
5210
    return $result;
5211
}
5212
5213
/**
5214
 * @param string $value       The value we want to record
5215
 * @param string $variable    The variable name we want to insert
5216
 * @param string $subKey      The subkey for the variable we want to insert
5217
 * @param string $type        The type for the variable we want to insert
5218
 * @param string $category    The category for the variable we want to insert
5219
 * @param string $title       The title
5220
 * @param string $comment     The comment
5221
 * @param string $scope       The scope
5222
 * @param string $subKeyText  The subkey text
5223
 * @param int    $accessUrlId The access_url for which this parameter is valid
5224
 * @param int    $visibility  The changeability of this setting for non-master urls
5225
 *
5226
 * @return int The setting ID
5227
 */
5228
function api_add_setting(
5229
    $value,
5230
    $variable,
5231
    $subKey = '',
5232
    $type = 'textfield',
5233
    $category = '',
5234
    $title = '',
5235
    $comment = '',
5236
    $scope = '',
5237
    $subKeyText = '',
5238
    $accessUrlId = 1,
5239
    $visibility = 0
5240
) {
5241
    $em = Database::getManager();
5242
5243
    $settingRepo = $em->getRepository(SettingsCurrent::class);
5244
    $accessUrlId = (int) $accessUrlId ?: 1;
5245
5246
    if (is_array($value)) {
5247
        $value = serialize($value);
5248
    } else {
5249
        $value = trim($value);
5250
    }
5251
5252
    $criteria = ['variable' => $variable, 'url' => $accessUrlId];
5253
5254
    if (!empty($subKey)) {
5255
        $criteria['subkey'] = $subKey;
5256
    }
5257
5258
    // Check if this variable doesn't exist already
5259
    /** @var SettingsCurrent $setting */
5260
    $setting = $settingRepo->findOneBy($criteria);
5261
5262
    if ($setting) {
0 ignored issues
show
introduced by
$setting is of type Chamilo\CoreBundle\Entity\SettingsCurrent, thus it always evaluated to true.
Loading history...
5263
        $setting->setSelectedValue($value);
5264
5265
        $em->persist($setting);
5266
        $em->flush();
5267
5268
        return $setting->getId();
5269
    }
5270
5271
    // Item not found for this access_url, we have to check if the whole thing is missing
5272
    // (in which case we ignore the insert) or if there *is* a record but just for access_url = 1
5273
    $setting = new SettingsCurrent();
5274
    $url = api_get_url_entity();
5275
5276
    $setting
5277
        ->setVariable($variable)
5278
        ->setSelectedValue($value)
5279
        ->setType($type)
5280
        ->setCategory($category)
5281
        ->setSubkey($subKey)
5282
        ->setTitle($title)
5283
        ->setComment($comment)
5284
        ->setScope($scope)
5285
        ->setSubkeytext($subKeyText)
5286
        ->setUrl(api_get_url_entity())
5287
        ->setAccessUrlChangeable($visibility);
5288
5289
    $em->persist($setting);
5290
    $em->flush();
5291
5292
    return $setting->getId();
5293
}
5294
5295
/**
5296
 * Checks wether a user can or can't view the contents of a course.
5297
 *
5298
 * @deprecated use CourseManager::is_user_subscribed_in_course
5299
 *
5300
 * @param int $userid User id or NULL to get it from $_SESSION
5301
 * @param int $cid    course id to check whether the user is allowed
5302
 *
5303
 * @return bool
5304
 */
5305
function api_is_course_visible_for_user($userid = null, $cid = null)
5306
{
5307
    if (null === $userid) {
5308
        $userid = api_get_user_id();
5309
    }
5310
    if (empty($userid) || strval(intval($userid)) != $userid) {
5311
        if (api_is_anonymous()) {
5312
            $userid = api_get_anonymous_id();
5313
        } else {
5314
            return false;
5315
        }
5316
    }
5317
    $cid = Database::escape_string($cid);
5318
5319
    $courseInfo = api_get_course_info($cid);
5320
    $courseId = $courseInfo['real_id'];
5321
    $is_platformAdmin = api_is_platform_admin();
5322
5323
    $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
5324
    $course_cat_table = Database::get_main_table(TABLE_MAIN_CATEGORY);
5325
5326
    $sql = "SELECT
5327
                $course_cat_table.code AS category_code,
5328
                $course_table.visibility,
5329
                $course_table.code,
5330
                $course_cat_table.code
5331
            FROM $course_table
5332
            LEFT JOIN $course_cat_table
5333
                ON $course_table.category_id = $course_cat_table.id
5334
            WHERE
5335
                $course_table.code = '$cid'
5336
            LIMIT 1";
5337
5338
    $result = Database::query($sql);
5339
5340
    if (Database::num_rows($result) > 0) {
5341
        $visibility = Database::fetch_array($result);
5342
        $visibility = $visibility['visibility'];
5343
    } else {
5344
        $visibility = 0;
5345
    }
5346
    // Shortcut permissions in case the visibility is "open to the world".
5347
    if (COURSE_VISIBILITY_OPEN_WORLD === $visibility) {
5348
        return true;
5349
    }
5350
5351
    $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
5352
5353
    $sql = "SELECT
5354
                is_tutor, status
5355
            FROM $tbl_course_user
5356
            WHERE
5357
                user_id  = '$userid' AND
5358
                relation_type <> '".COURSE_RELATION_TYPE_RRHH."' AND
5359
                c_id = $courseId
5360
            LIMIT 1";
5361
5362
    $result = Database::query($sql);
5363
5364
    if (Database::num_rows($result) > 0) {
5365
        // This user has got a recorded state for this course.
5366
        $cuData = Database::fetch_array($result);
5367
        $is_courseMember = true;
5368
        $is_courseAdmin = (1 == $cuData['status']);
5369
    }
5370
5371
    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...
5372
        // This user has no status related to this course.
5373
        // Is it the session coach or the session admin?
5374
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
5375
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
5376
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
5377
5378
        $sql = "SELECT
5379
                    session.id_coach, session_admin_id, session.id
5380
                FROM
5381
                    $tbl_session as session
5382
                INNER JOIN $tbl_session_course
5383
                    ON session_rel_course.session_id = session.id
5384
                    AND session_rel_course.c_id = '$courseId'
5385
                LIMIT 1";
5386
5387
        $result = Database::query($sql);
5388
        $row = Database::store_result($result);
5389
5390
        if ($row[0]['id_coach'] == $userid) {
5391
            $is_courseMember = true;
5392
            $is_courseAdmin = false;
5393
        } elseif ($row[0]['session_admin_id'] == $userid) {
5394
            $is_courseMember = false;
5395
            $is_courseAdmin = false;
5396
        } else {
5397
            // Check if the current user is the course coach.
5398
            $sql = "SELECT 1
5399
                    FROM $tbl_session_course
5400
                    WHERE session_rel_course.c_id = '$courseId'
5401
                    AND session_rel_course.id_coach = '$userid'
5402
                    LIMIT 1";
5403
5404
            $result = Database::query($sql);
5405
5406
            //if ($row = Database::fetch_array($result)) {
5407
            if (Database::num_rows($result) > 0) {
5408
                $is_courseMember = true;
5409
                $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
5410
5411
                $sql = "SELECT status FROM $tbl_user
5412
                        WHERE id = $userid
5413
                        LIMIT 1";
5414
5415
                $result = Database::query($sql);
5416
5417
                if (1 == Database::result($result, 0, 0)) {
5418
                    $is_courseAdmin = true;
5419
                } else {
5420
                    $is_courseAdmin = false;
5421
                }
5422
            } else {
5423
                // Check if the user is a student is this session.
5424
                $sql = "SELECT  id
5425
                        FROM $tbl_session_course_user
5426
                        WHERE
5427
                            user_id  = '$userid' AND
5428
                            c_id = '$courseId'
5429
                        LIMIT 1";
5430
5431
                if (Database::num_rows($result) > 0) {
5432
                    // This user haa got a recorded state for this course.
5433
                    while ($row = Database::fetch_array($result)) {
5434
                        $is_courseMember = true;
5435
                        $is_courseAdmin = false;
5436
                    }
5437
                }
5438
            }
5439
        }
5440
    }
5441
5442
    switch ($visibility) {
5443
        case COURSE_VISIBILITY_OPEN_WORLD:
5444
            return true;
5445
        case COURSE_VISIBILITY_OPEN_PLATFORM:
5446
            return isset($userid);
5447
        case COURSE_VISIBILITY_REGISTERED:
5448
        case COURSE_VISIBILITY_CLOSED:
5449
            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...
5450
        case COURSE_VISIBILITY_HIDDEN:
5451
            return $is_platformAdmin;
5452
    }
5453
5454
    return false;
5455
}
5456
5457
/**
5458
 * Returns whether an element (forum, message, survey ...) belongs to a session or not.
5459
 *
5460
 * @param string the tool of the element
5461
 * @param int the element id in database
5462
 * @param int the session_id to compare with element session id
5463
 *
5464
 * @return bool true if the element is in the session, false else
5465
 */
5466
function api_is_element_in_the_session($tool, $element_id, $session_id = null)
5467
{
5468
    if (is_null($session_id)) {
5469
        $session_id = api_get_session_id();
5470
    }
5471
5472
    $element_id = (int) $element_id;
5473
5474
    if (empty($element_id)) {
5475
        return false;
5476
    }
5477
5478
    // Get information to build query depending of the tool.
5479
    switch ($tool) {
5480
        case TOOL_SURVEY:
5481
            $table_tool = Database::get_course_table(TABLE_SURVEY);
5482
            $key_field = 'survey_id';
5483
            break;
5484
        case TOOL_ANNOUNCEMENT:
5485
            $table_tool = Database::get_course_table(TABLE_ANNOUNCEMENT);
5486
            $key_field = 'id';
5487
            break;
5488
        case TOOL_AGENDA:
5489
            $table_tool = Database::get_course_table(TABLE_AGENDA);
5490
            $key_field = 'id';
5491
            break;
5492
        case TOOL_GROUP:
5493
            $table_tool = Database::get_course_table(TABLE_GROUP);
5494
            $key_field = 'id';
5495
            break;
5496
        default:
5497
            return false;
5498
    }
5499
    $course_id = api_get_course_int_id();
5500
5501
    $sql = "SELECT session_id FROM $table_tool
5502
            WHERE c_id = $course_id AND $key_field =  ".$element_id;
5503
    $rs = Database::query($sql);
5504
    if ($element_session_id = Database::result($rs, 0, 0)) {
5505
        if ($element_session_id == intval($session_id)) {
5506
            // The element belongs to the session.
5507
            return true;
5508
        }
5509
    }
5510
5511
    return false;
5512
}
5513
5514
/**
5515
 * Replaces "forbidden" characters in a filename string.
5516
 *
5517
 * @param string $filename
5518
 * @param bool   $treat_spaces_as_hyphens
5519
 *
5520
 * @return string
5521
 */
5522
function api_replace_dangerous_char($filename, $treat_spaces_as_hyphens = true)
5523
{
5524
    // Some non-properly encoded file names can cause the whole file to be
5525
    // skipped when uploaded. Avoid this by detecting the encoding and
5526
    // converting to UTF-8, setting the source as ASCII (a reasonably
5527
    // limited characters set) if nothing could be found (BT#
5528
    $encoding = api_detect_encoding($filename);
5529
    if (empty($encoding)) {
5530
        $encoding = 'ASCII';
5531
        if (!api_is_valid_ascii($filename)) {
5532
            // try iconv and try non standard ASCII a.k.a CP437
5533
            // see BT#15022
5534
            if (function_exists('iconv')) {
5535
                $result = iconv('CP437', 'UTF-8', $filename);
5536
                if (api_is_valid_utf8($result)) {
5537
                    $filename = $result;
5538
                    $encoding = 'UTF-8';
5539
                }
5540
            }
5541
        }
5542
    }
5543
5544
    $filename = api_to_system_encoding($filename, $encoding);
5545
5546
    $url = URLify::filter(
5547
        $filename,
5548
        250,
5549
        '',
5550
        true,
5551
        false,
5552
        false,
5553
        false
5554
    );
5555
5556
    return $url;
5557
}
5558
5559
/**
5560
 * Fixes the $_SERVER['REQUEST_URI'] that is empty in IIS6.
5561
 *
5562
 * @author Ivan Tcholakov, 28-JUN-2006.
5563
 */
5564
function api_request_uri()
5565
{
5566
    if (!empty($_SERVER['REQUEST_URI'])) {
5567
        return $_SERVER['REQUEST_URI'];
5568
    }
5569
    $uri = $_SERVER['SCRIPT_NAME'];
5570
    if (!empty($_SERVER['QUERY_STRING'])) {
5571
        $uri .= '?'.$_SERVER['QUERY_STRING'];
5572
    }
5573
    $_SERVER['REQUEST_URI'] = $uri;
5574
5575
    return $uri;
5576
}
5577
5578
/** Gets the current access_url id of the Chamilo Platform.
5579
 * @author Julio Montoya <[email protected]>
5580
 *
5581
 * @return int access_url_id of the current Chamilo Installation
5582
 */
5583
function api_get_current_access_url_id()
5584
{
5585
    if (false === api_get_multiple_access_url()) {
5586
        return 1;
5587
    }
5588
5589
    static $id;
5590
    if (!empty($id)) {
5591
        return $id;
5592
    }
5593
5594
    $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5595
    $path = Database::escape_string(api_get_path(WEB_PATH));
5596
    $sql = "SELECT id FROM $table WHERE url = '".$path."'";
5597
    $result = Database::query($sql);
5598
    if (Database::num_rows($result) > 0) {
5599
        $id = Database::result($result, 0, 0);
5600
        if (false === $id) {
5601
            return -1;
5602
        }
5603
5604
        return (int) $id;
5605
    }
5606
5607
    $id = 1;
5608
5609
    //if the url in WEB_PATH was not found, it can only mean that there is
5610
    // either a configuration problem or the first URL has not been defined yet
5611
    // (by default it is http://localhost/). Thus the more sensible thing we can
5612
    // do is return 1 (the main URL) as the user cannot hack this value anyway
5613
    return 1;
5614
}
5615
5616
/**
5617
 * Gets the registered urls from a given user id.
5618
 *
5619
 * @author Julio Montoya <[email protected]>
5620
 *
5621
 * @param int $user_id
5622
 *
5623
 * @return array
5624
 */
5625
function api_get_access_url_from_user($user_id)
5626
{
5627
    $user_id = (int) $user_id;
5628
    $table_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
5629
    $table_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5630
    $sql = "SELECT access_url_id
5631
            FROM $table_url_rel_user url_rel_user
5632
            INNER JOIN $table_url u
5633
            ON (url_rel_user.access_url_id = u.id)
5634
            WHERE user_id = ".$user_id;
5635
    $result = Database::query($sql);
5636
    $list = [];
5637
    while ($row = Database::fetch_array($result, 'ASSOC')) {
5638
        $list[] = $row['access_url_id'];
5639
    }
5640
5641
    return $list;
5642
}
5643
5644
/**
5645
 * Checks whether the curent user is in a group or not.
5646
 *
5647
 * @param string        The group id - optional (takes it from session if not given)
5648
 * @param string        The course code - optional (no additional check by course if course code is not given)
5649
 *
5650
 * @return bool
5651
 *
5652
 * @author Ivan Tcholakov
5653
 */
5654
function api_is_in_group($groupIdParam = null, $courseCodeParam = null)
5655
{
5656
    if (!empty($courseCodeParam)) {
5657
        $courseCode = api_get_course_id();
5658
        if (!empty($courseCode)) {
5659
            if ($courseCodeParam != $courseCode) {
5660
                return false;
5661
            }
5662
        } else {
5663
            return false;
5664
        }
5665
    }
5666
5667
    $groupId = api_get_group_id();
5668
5669
    if (isset($groupId) && '' != $groupId) {
5670
        if (!empty($groupIdParam)) {
5671
            return $groupIdParam == $groupId;
5672
        } else {
5673
            return true;
5674
        }
5675
    }
5676
5677
    return false;
5678
}
5679
5680
/**
5681
 * Checks whether a secret key is valid.
5682
 *
5683
 * @param string $original_key_secret - secret key from (webservice) client
5684
 * @param string $security_key        - security key from Chamilo
5685
 *
5686
 * @return bool - true if secret key is valid, false otherwise
5687
 */
5688
function api_is_valid_secret_key($original_key_secret, $security_key)
5689
{
5690
    if (empty($original_key_secret) || empty($security_key)) {
5691
        return false;
5692
    }
5693
5694
    return (string) $original_key_secret === sha1($security_key);
5695
}
5696
5697
/**
5698
 * Checks whether the server's operating system is Windows (TM).
5699
 *
5700
 * @return bool - true if the operating system is Windows, false otherwise
5701
 */
5702
function api_is_windows_os()
5703
{
5704
    if (function_exists('php_uname')) {
5705
        // php_uname() exists as of PHP 4.0.2, according to the documentation.
5706
        // We expect that this function will always work for Chamilo 1.8.x.
5707
        $os = php_uname();
5708
    }
5709
    // The following methods are not needed, but let them stay, just in case.
5710
    elseif (isset($_ENV['OS'])) {
5711
        // Sometimes $_ENV['OS'] may not be present (bugs?)
5712
        $os = $_ENV['OS'];
5713
    } elseif (defined('PHP_OS')) {
5714
        // PHP_OS means on which OS PHP was compiled, this is why
5715
        // using PHP_OS is the last choice for detection.
5716
        $os = PHP_OS;
5717
    } else {
5718
        return false;
5719
    }
5720
5721
    return 'win' == strtolower(substr((string) $os, 0, 3));
5722
}
5723
5724
/**
5725
 * This function informs whether the sent request is XMLHttpRequest.
5726
 */
5727
function api_is_xml_http_request()
5728
{
5729
    return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && 'xmlhttprequest' == strtolower($_SERVER['HTTP_X_REQUESTED_WITH']);
5730
}
5731
5732
/**
5733
 * Returns a list of Chamilo's tools or
5734
 * checks whether a given identificator is a valid Chamilo's tool.
5735
 *
5736
 * @author Isaac flores paz
5737
 *
5738
 * @param string The tool name to filter
5739
 *
5740
 * @return mixed Filtered string or array
5741
 */
5742
function api_get_tools_lists($my_tool = null)
5743
{
5744
    $tools_list = [
5745
        TOOL_DOCUMENT,
5746
        TOOL_THUMBNAIL,
5747
        TOOL_HOTPOTATOES,
5748
        TOOL_CALENDAR_EVENT,
5749
        TOOL_LINK,
5750
        TOOL_COURSE_DESCRIPTION,
5751
        TOOL_SEARCH,
5752
        TOOL_LEARNPATH,
5753
        TOOL_ANNOUNCEMENT,
5754
        TOOL_FORUM,
5755
        TOOL_THREAD,
5756
        TOOL_POST,
5757
        TOOL_DROPBOX,
5758
        TOOL_QUIZ,
5759
        TOOL_USER,
5760
        TOOL_GROUP,
5761
        TOOL_BLOGS,
5762
        TOOL_CHAT,
5763
        TOOL_STUDENTPUBLICATION,
5764
        TOOL_TRACKING,
5765
        TOOL_HOMEPAGE_LINK,
5766
        TOOL_COURSE_SETTING,
5767
        TOOL_BACKUP,
5768
        TOOL_COPY_COURSE_CONTENT,
5769
        TOOL_RECYCLE_COURSE,
5770
        TOOL_COURSE_HOMEPAGE,
5771
        TOOL_COURSE_RIGHTS_OVERVIEW,
5772
        TOOL_UPLOAD,
5773
        TOOL_COURSE_MAINTENANCE,
5774
        TOOL_SURVEY,
5775
        TOOL_WIKI,
5776
        TOOL_GLOSSARY,
5777
        TOOL_GRADEBOOK,
5778
        TOOL_NOTEBOOK,
5779
        TOOL_ATTENDANCE,
5780
        TOOL_COURSE_PROGRESS,
5781
    ];
5782
    if (empty($my_tool)) {
5783
        return $tools_list;
5784
    }
5785
5786
    return in_array($my_tool, $tools_list) ? $my_tool : '';
5787
}
5788
5789
/**
5790
 * Checks whether we already approved the last version term and condition.
5791
 *
5792
 * @param int user id
5793
 *
5794
 * @return bool true if we pass false otherwise
5795
 */
5796
function api_check_term_condition($userId)
5797
{
5798
    if ('true' === api_get_setting('allow_terms_conditions')) {
5799
        // Check if exists terms and conditions
5800
        if (0 == LegalManager::count()) {
5801
            return true;
5802
        }
5803
5804
        $extraFieldValue = new ExtraFieldValue('user');
5805
        $data = $extraFieldValue->get_values_by_handler_and_field_variable(
5806
            $userId,
5807
            'legal_accept'
5808
        );
5809
5810
        if (!empty($data) && isset($data['value']) && !empty($data['value'])) {
5811
            $result = $data['value'];
5812
            $user_conditions = explode(':', $result);
5813
            $version = $user_conditions[0];
5814
            $langId = $user_conditions[1];
5815
            $realVersion = LegalManager::get_last_version($langId);
5816
5817
            return $version >= $realVersion;
5818
        }
5819
5820
        return false;
5821
    }
5822
5823
    return false;
5824
}
5825
5826
/**
5827
 * Gets all information of a tool into course.
5828
 *
5829
 * @param int The tool id
5830
 *
5831
 * @return array
5832
 */
5833
function api_get_tool_information_by_name($name)
5834
{
5835
    $t_tool = Database::get_course_table(TABLE_TOOL_LIST);
5836
    $course_id = api_get_course_int_id();
5837
5838
    $sql = "SELECT id FROM tool
5839
            WHERE name = '".Database::escape_string($name)."' ";
5840
    $rs = Database::query($sql);
5841
    $data = Database::fetch_array($rs);
5842
    if ($data) {
5843
        $tool = $data['id'];
5844
        $sql = "SELECT * FROM $t_tool
5845
                WHERE c_id = $course_id  AND tool_id = '".$tool."' ";
5846
        $rs = Database::query($sql);
5847
5848
        return Database::fetch_array($rs, 'ASSOC');
5849
    }
5850
5851
    return [];
5852
}
5853
5854
/**
5855
 * Function used to protect a "global" admin script.
5856
 * The function blocks access when the user has no global platform admin rights.
5857
 * Global admins are the admins that are registered in the main.admin table
5858
 * AND the users who have access to the "principal" portal.
5859
 * That means that there is a record in the main.access_url_rel_user table
5860
 * with his user id and the access_url_id=1.
5861
 *
5862
 * @author Julio Montoya
5863
 *
5864
 * @param int $user_id
5865
 *
5866
 * @return bool
5867
 */
5868
function api_is_global_platform_admin($user_id = null)
5869
{
5870
    $user_id = (int) $user_id;
5871
    if (empty($user_id)) {
5872
        $user_id = api_get_user_id();
5873
    }
5874
    if (api_is_platform_admin_by_id($user_id)) {
5875
        $urlList = api_get_access_url_from_user($user_id);
5876
        // The admin is registered in the first "main" site with access_url_id = 1
5877
        if (in_array(1, $urlList)) {
5878
            return true;
5879
        } else {
5880
            return false;
5881
        }
5882
    }
5883
5884
    return false;
5885
}
5886
5887
/**
5888
 * @param int  $admin_id_to_check
5889
 * @param int  $my_user_id
5890
 * @param bool $allow_session_admin
5891
 *
5892
 * @return bool
5893
 */
5894
function api_global_admin_can_edit_admin(
5895
    $admin_id_to_check,
5896
    $my_user_id = null,
5897
    $allow_session_admin = false
5898
) {
5899
    if (empty($my_user_id)) {
5900
        $my_user_id = api_get_user_id();
5901
    }
5902
5903
    $iam_a_global_admin = api_is_global_platform_admin($my_user_id);
5904
    $user_is_global_admin = api_is_global_platform_admin($admin_id_to_check);
5905
5906
    if ($iam_a_global_admin) {
5907
        // Global admin can edit everything
5908
        return true;
5909
    } else {
5910
        // If i'm a simple admin
5911
        $is_platform_admin = api_is_platform_admin_by_id($my_user_id);
5912
5913
        if ($allow_session_admin) {
5914
            $is_platform_admin = api_is_platform_admin_by_id($my_user_id) || (SESSIONADMIN == api_get_user_status($my_user_id));
5915
        }
5916
5917
        if ($is_platform_admin) {
5918
            if ($user_is_global_admin) {
5919
                return false;
5920
            } else {
5921
                return true;
5922
            }
5923
        } else {
5924
            return false;
5925
        }
5926
    }
5927
}
5928
5929
/**
5930
 * @param int  $admin_id_to_check
5931
 * @param int  $my_user_id
5932
 * @param bool $allow_session_admin
5933
 *
5934
 * @return bool|null
5935
 */
5936
function api_protect_super_admin($admin_id_to_check, $my_user_id = null, $allow_session_admin = false)
5937
{
5938
    if (api_global_admin_can_edit_admin($admin_id_to_check, $my_user_id, $allow_session_admin)) {
5939
        return true;
5940
    } else {
5941
        api_not_allowed();
5942
    }
5943
}
5944
5945
/**
5946
 * Function used to protect a global admin script.
5947
 * The function blocks access when the user has no global platform admin rights.
5948
 * See also the api_is_global_platform_admin() function wich defines who's a "global" admin.
5949
 *
5950
 * @author Julio Montoya
5951
 */
5952
function api_protect_global_admin_script()
5953
{
5954
    if (!api_is_global_platform_admin()) {
5955
        api_not_allowed();
5956
5957
        return false;
5958
    }
5959
5960
    return true;
5961
}
5962
5963
/**
5964
 * Check browser support for specific file types or features
5965
 * This function checks if the user's browser supports a file format or given
5966
 * feature, or returns the current browser and major version when
5967
 * $format=check_browser. Only a limited number of formats and features are
5968
 * checked by this method. Make sure you check its definition first.
5969
 *
5970
 * @param string $format Can be a file format (extension like svg, webm, ...) or a feature (like autocapitalize, ...)
5971
 *
5972
 * @deprecated
5973
 *
5974
 * @return bool or return text array if $format=check_browser
5975
 *
5976
 * @author Juan Carlos Raña Trabado
5977
 */
5978
function api_browser_support($format = '')
5979
{
5980
    return true;
5981
5982
    $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...
5983
    $current_browser = $browser->getBrowser();
5984
    $a_versiontemp = explode('.', $browser->getVersion());
5985
    $current_majorver = $a_versiontemp[0];
5986
5987
    static $result;
5988
5989
    if (isset($result[$format])) {
5990
        return $result[$format];
5991
    }
5992
5993
    // Native svg support
5994
    if ('svg' == $format) {
5995
        if (('Internet Explorer' == $current_browser && $current_majorver >= 9) ||
5996
            ('Firefox' == $current_browser && $current_majorver > 1) ||
5997
            ('Safari' == $current_browser && $current_majorver >= 4) ||
5998
            ('Chrome' == $current_browser && $current_majorver >= 1) ||
5999
            ('Opera' == $current_browser && $current_majorver >= 9)
6000
        ) {
6001
            $result[$format] = true;
6002
6003
            return true;
6004
        } else {
6005
            $result[$format] = false;
6006
6007
            return false;
6008
        }
6009
    } elseif ('pdf' == $format) {
6010
        // native pdf support
6011
        if ('Chrome' == $current_browser && $current_majorver >= 6) {
6012
            $result[$format] = true;
6013
6014
            return true;
6015
        } else {
6016
            $result[$format] = false;
6017
6018
            return false;
6019
        }
6020
    } elseif ('tif' == $format || 'tiff' == $format) {
6021
        //native tif support
6022
        if ('Safari' == $current_browser && $current_majorver >= 5) {
6023
            $result[$format] = true;
6024
6025
            return true;
6026
        } else {
6027
            $result[$format] = false;
6028
6029
            return false;
6030
        }
6031
    } elseif ('ogg' == $format || 'ogx' == $format || 'ogv' == $format || 'oga' == $format) {
6032
        //native ogg, ogv,oga support
6033
        if (('Firefox' == $current_browser && $current_majorver >= 3) ||
6034
            ('Chrome' == $current_browser && $current_majorver >= 3) ||
6035
            ('Opera' == $current_browser && $current_majorver >= 9)) {
6036
            $result[$format] = true;
6037
6038
            return true;
6039
        } else {
6040
            $result[$format] = false;
6041
6042
            return false;
6043
        }
6044
    } elseif ('mpg' == $format || 'mpeg' == $format) {
6045
        //native mpg support
6046
        if (('Safari' == $current_browser && $current_majorver >= 5)) {
6047
            $result[$format] = true;
6048
6049
            return true;
6050
        } else {
6051
            $result[$format] = false;
6052
6053
            return false;
6054
        }
6055
    } elseif ('mp4' == $format) {
6056
        //native mp4 support (TODO: Android, iPhone)
6057
        if ('Android' == $current_browser || 'iPhone' == $current_browser) {
6058
            $result[$format] = true;
6059
6060
            return true;
6061
        } else {
6062
            $result[$format] = false;
6063
6064
            return false;
6065
        }
6066
    } elseif ('mov' == $format) {
6067
        //native mov support( TODO:check iPhone)
6068
        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...
6069
            $result[$format] = true;
6070
6071
            return true;
6072
        } else {
6073
            $result[$format] = false;
6074
6075
            return false;
6076
        }
6077
    } elseif ('avi' == $format) {
6078
        //native avi support
6079
        if ('Safari' == $current_browser && $current_majorver >= 5) {
6080
            $result[$format] = true;
6081
6082
            return true;
6083
        } else {
6084
            $result[$format] = false;
6085
6086
            return false;
6087
        }
6088
    } elseif ('wmv' == $format) {
6089
        //native wmv support
6090
        if ('Firefox' == $current_browser && $current_majorver >= 4) {
6091
            $result[$format] = true;
6092
6093
            return true;
6094
        } else {
6095
            $result[$format] = false;
6096
6097
            return false;
6098
        }
6099
    } elseif ('webm' == $format) {
6100
        //native webm support (TODO:check IE9, Chrome9, Android)
6101
        if (('Firefox' == $current_browser && $current_majorver >= 4) ||
6102
            ('Opera' == $current_browser && $current_majorver >= 9) ||
6103
            ('Internet Explorer' == $current_browser && $current_majorver >= 9) ||
6104
            ('Chrome' == $current_browser && $current_majorver >= 9) ||
6105
            'Android' == $current_browser
6106
        ) {
6107
            $result[$format] = true;
6108
6109
            return true;
6110
        } else {
6111
            $result[$format] = false;
6112
6113
            return false;
6114
        }
6115
    } elseif ('wav' == $format) {
6116
        //native wav support (only some codecs !)
6117
        if (('Firefox' == $current_browser && $current_majorver >= 4) ||
6118
            ('Safari' == $current_browser && $current_majorver >= 5) ||
6119
            ('Opera' == $current_browser && $current_majorver >= 9) ||
6120
            ('Internet Explorer' == $current_browser && $current_majorver >= 9) ||
6121
            ('Chrome' == $current_browser && $current_majorver > 9) ||
6122
            'Android' == $current_browser ||
6123
            'iPhone' == $current_browser
6124
        ) {
6125
            $result[$format] = true;
6126
6127
            return true;
6128
        } else {
6129
            $result[$format] = false;
6130
6131
            return false;
6132
        }
6133
    } elseif ('mid' == $format || 'kar' == $format) {
6134
        //native midi support (TODO:check Android)
6135
        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...
6136
            $result[$format] = true;
6137
6138
            return true;
6139
        } else {
6140
            $result[$format] = false;
6141
6142
            return false;
6143
        }
6144
    } elseif ('wma' == $format) {
6145
        //native wma support
6146
        if ('Firefox' == $current_browser && $current_majorver >= 4) {
6147
            $result[$format] = true;
6148
6149
            return true;
6150
        } else {
6151
            $result[$format] = false;
6152
6153
            return false;
6154
        }
6155
    } elseif ('au' == $format) {
6156
        //native au support
6157
        if ('Safari' == $current_browser && $current_majorver >= 5) {
6158
            $result[$format] = true;
6159
6160
            return true;
6161
        } else {
6162
            $result[$format] = false;
6163
6164
            return false;
6165
        }
6166
    } elseif ('mp3' == $format) {
6167
        //native mp3 support (TODO:check Android, iPhone)
6168
        if (('Safari' == $current_browser && $current_majorver >= 5) ||
6169
            ('Chrome' == $current_browser && $current_majorver >= 6) ||
6170
            ('Internet Explorer' == $current_browser && $current_majorver >= 9) ||
6171
            'Android' == $current_browser ||
6172
            'iPhone' == $current_browser ||
6173
            'Firefox' == $current_browser
6174
        ) {
6175
            $result[$format] = true;
6176
6177
            return true;
6178
        } else {
6179
            $result[$format] = false;
6180
6181
            return false;
6182
        }
6183
    } elseif ('autocapitalize' == $format) {
6184
        // Help avoiding showing the autocapitalize option if the browser doesn't
6185
        // support it: this attribute is against the HTML5 standard
6186
        if ('Safari' == $current_browser || 'iPhone' == $current_browser) {
6187
            return true;
6188
        } else {
6189
            return false;
6190
        }
6191
    } elseif ("check_browser" == $format) {
6192
        $array_check_browser = [$current_browser, $current_majorver];
6193
6194
        return $array_check_browser;
6195
    } else {
6196
        $result[$format] = false;
6197
6198
        return false;
6199
    }
6200
}
6201
6202
/**
6203
 * This function checks if exist path and file browscap.ini
6204
 * In order for this to work, your browscap configuration setting in php.ini
6205
 * must point to the correct location of the browscap.ini file on your system
6206
 * http://php.net/manual/en/function.get-browser.php.
6207
 *
6208
 * @return bool
6209
 *
6210
 * @author Juan Carlos Raña Trabado
6211
 */
6212
function api_check_browscap()
6213
{
6214
    $setting = ini_get('browscap');
6215
    if ($setting) {
6216
        $browser = get_browser($_SERVER['HTTP_USER_AGENT'], true);
6217
        if (strpos($setting, 'browscap.ini') && !empty($browser)) {
6218
            return true;
6219
        }
6220
    }
6221
6222
    return false;
6223
}
6224
6225
/**
6226
 * Returns the <script> HTML tag.
6227
 */
6228
function api_get_js($file)
6229
{
6230
    return '<script type="text/javascript" src="'.api_get_path(WEB_LIBRARY_PATH).'javascript/'.$file.'"></script>'."\n";
6231
}
6232
6233
function api_get_build_js($file)
6234
{
6235
    return '<script type="text/javascript" src="'.api_get_path(WEB_PUBLIC_PATH).'build/'.$file.'"></script>'."\n";
6236
}
6237
6238
function api_get_build_css($file, $media = 'screen')
6239
{
6240
    return '<link
6241
        href="'.api_get_path(WEB_PUBLIC_PATH).'build/'.$file.'" rel="stylesheet" media="'.$media.'" type="text/css" />'."\n";
6242
}
6243
6244
/**
6245
 * Returns the <script> HTML tag.
6246
 *
6247
 * @return string
6248
 */
6249
function api_get_asset($file)
6250
{
6251
    return '<script type="text/javascript" src="'.api_get_path(WEB_PUBLIC_PATH).'build/libs/'.$file.'"></script>'."\n";
6252
}
6253
6254
/**
6255
 * Returns the <script> HTML tag.
6256
 *
6257
 * @param string $file
6258
 * @param string $media
6259
 *
6260
 * @return string
6261
 */
6262
function api_get_css_asset($file, $media = 'screen')
6263
{
6264
    return '<link href="'.api_get_path(WEB_PUBLIC_PATH).'build/libs/'.$file.'" rel="stylesheet" media="'.$media.'" type="text/css" />'."\n";
6265
}
6266
6267
/**
6268
 * Returns the <link> HTML tag.
6269
 *
6270
 * @param string $file
6271
 * @param string $media
6272
 */
6273
function api_get_css($file, $media = 'screen')
6274
{
6275
    return '<link href="'.$file.'" rel="stylesheet" media="'.$media.'" type="text/css" />'."\n";
6276
}
6277
6278
function api_get_bootstrap_and_font_awesome($returnOnlyPath = false, $returnFileLocation = false)
6279
{
6280
    $url = api_get_path(WEB_PUBLIC_PATH).'build/css/bootstrap.css';
6281
6282
    if ($returnOnlyPath) {
6283
        if ($returnFileLocation) {
6284
            return api_get_path(SYS_PUBLIC_PATH).'build/css/bootstrap.css';
6285
        }
6286
6287
        return $url;
6288
    }
6289
6290
    return '<link href="'.$url.'" rel="stylesheet" type="text/css" />'."\n";
6291
}
6292
6293
/**
6294
 * Returns the js header to include the jquery library.
6295
 */
6296
function api_get_jquery_js()
6297
{
6298
    return api_get_asset('jquery/jquery.min.js');
6299
}
6300
6301
/**
6302
 * Returns the jquery path.
6303
 *
6304
 * @return string
6305
 */
6306
function api_get_jquery_web_path()
6307
{
6308
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery/jquery.min.js';
6309
}
6310
6311
/**
6312
 * @return string
6313
 */
6314
function api_get_jquery_ui_js_web_path()
6315
{
6316
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery-ui/jquery-ui.min.js';
6317
}
6318
6319
/**
6320
 * @return string
6321
 */
6322
function api_get_jquery_ui_css_web_path()
6323
{
6324
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery-ui/themes/smoothness/jquery-ui.min.css';
6325
}
6326
6327
/**
6328
 * Returns the jquery-ui library js headers.
6329
 *
6330
 * @return string html tags
6331
 */
6332
function api_get_jquery_ui_js()
6333
{
6334
    $libraries = [];
6335
6336
    return api_get_jquery_libraries_js($libraries);
6337
}
6338
6339
function api_get_jqgrid_js()
6340
{
6341
    return api_get_build_css('free-jqgrid.css').PHP_EOL
6342
        .api_get_build_js('free-jqgrid.js');
6343
}
6344
6345
/**
6346
 * Returns the jquery library js and css headers.
6347
 *
6348
 * @param   array   list of jquery libraries supported jquery-ui
6349
 * @param   bool    add the jquery library
6350
 *
6351
 * @return string html tags
6352
 */
6353
function api_get_jquery_libraries_js($libraries)
6354
{
6355
    $js = '';
6356
6357
    //Document multiple upload funcionality
6358
    if (in_array('jquery-uploadzs', $libraries)) {
6359
        $js .= api_get_asset('blueimp-load-image/js/load-image.all.min.js');
6360
        $js .= api_get_asset('blueimp-canvas-to-blob/js/canvas-to-blob.min.js');
6361
        $js .= api_get_asset('jquery-file-upload/js/jquery.iframe-transport.js');
6362
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload.js');
6363
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-process.js');
6364
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-image.js');
6365
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-audio.js');
6366
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-video.js');
6367
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-validate.js');
6368
6369
        $js .= api_get_css(api_get_path(WEB_PUBLIC_PATH).'assets/jquery-file-upload/css/jquery.fileupload.css');
6370
        $js .= api_get_css(api_get_path(WEB_PUBLIC_PATH).'assets/jquery-file-upload/css/jquery.fileupload-ui.css');
6371
    }
6372
6373
    // jquery datepicker
6374
    if (in_array('datepicker', $libraries)) {
6375
        $languaje = 'en-GB';
6376
        $platform_isocode = strtolower(api_get_language_isocode());
6377
6378
        $datapicker_langs = [
6379
            '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',
6380
        ];
6381
        if (in_array($platform_isocode, $datapicker_langs)) {
6382
            $languaje = $platform_isocode;
6383
        }
6384
6385
        $js .= api_get_js('jquery-ui/jquery-ui-i18n.min.js');
6386
        $script = '<script>
6387
        $(function(){
6388
            $.datepicker.setDefaults($.datepicker.regional["'.$languaje.'"]);
6389
            $.datepicker.regional["local"] = $.datepicker.regional["'.$languaje.'"];
6390
        });
6391
        </script>
6392
        ';
6393
        $js .= $script;
6394
    }
6395
6396
    return $js;
6397
}
6398
6399
/**
6400
 * Returns the URL to the course or session, removing the complexity of the URL
6401
 * building piece by piece.
6402
 *
6403
 * This function relies on api_get_course_info()
6404
 *
6405
 * @param int    $courseId The course code - optional (takes it from context if not given)
6406
 * @param int    $sessionId  The session ID  - optional (takes it from context if not given)
6407
 * @param int    $groupId    The group ID - optional (takes it from context if not given)
6408
 *
6409
 * @return string The URL to a course, a session, or empty string if nothing works
6410
 *                e.g. https://localhost/courses/ABC/index.php?session_id=3&gidReq=1
6411
 *
6412
 * @author  Julio Montoya
6413
 */
6414
function api_get_course_url($courseId = null, $sessionId = null, $groupId = null)
6415
{
6416
    $url = '';
6417
    // If courseCode not set, get context or []
6418
    if (empty($courseId)) {
6419
        $courseId = api_get_course_int_id();
6420
    }
6421
6422
    // If sessionId not set, get context or 0
6423
    if (empty($sessionId)) {
6424
        $sessionId = api_get_session_id();
6425
    }
6426
6427
    // If groupId not set, get context or 0
6428
    if (empty($groupId)) {
6429
        $groupId = api_get_group_id();
6430
    }
6431
6432
    // Build the URL
6433
    if (!empty($courseId)) {
6434
        $webCourseHome = '/course/'.$courseId.'/home';
6435
        // directory not empty, so we do have a course
6436
        $url = $webCourseHome.'?sid='.$sessionId.'&gid='.$groupId;
6437
    } else {
6438
        if (!empty($sessionId) && 'true' !== api_get_setting('session.remove_session_url')) {
6439
            // if the course was unset and the session was set, send directly to the session
6440
            $url = api_get_path(WEB_CODE_PATH).'session/index.php?session_id='.$sessionId;
6441
        }
6442
    }
6443
6444
    // if not valid combination was found, return an empty string
6445
    return $url;
6446
}
6447
6448
/**
6449
 * Check if the current portal has the $_configuration['multiple_access_urls'] parameter on.
6450
 */
6451
function api_get_multiple_access_url(): bool
6452
{
6453
    global $_configuration;
6454
    if (isset($_configuration['multiple_access_urls']) && $_configuration['multiple_access_urls']) {
6455
        return true;
6456
    }
6457
6458
    return false;
6459
}
6460
6461
function api_is_multiple_url_enabled(): bool
6462
{
6463
    return api_get_multiple_access_url();
6464
}
6465
6466
/**
6467
 * Returns a md5 unique id.
6468
 *
6469
 * @todo add more parameters
6470
 */
6471
function api_get_unique_id()
6472
{
6473
    return md5(time().uniqid().api_get_user_id().api_get_course_id().api_get_session_id());
6474
}
6475
6476
/**
6477
 * @param int Course id
6478
 * @param int tool id: TOOL_QUIZ, TOOL_FORUM, TOOL_STUDENTPUBLICATION, TOOL_LEARNPATH
6479
 * @param int the item id (tool id, exercise id, lp id)
6480
 *
6481
 * @return bool
6482
 */
6483
function api_resource_is_locked_by_gradebook($item_id, $link_type, $course_code = null)
6484
{
6485
    if (api_is_platform_admin()) {
6486
        return false;
6487
    }
6488
    if ('true' == api_get_setting('gradebook_locking_enabled')) {
6489
        if (empty($course_code)) {
6490
            $course_code = api_get_course_id();
6491
        }
6492
        $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_LINK);
6493
        $item_id = (int) $item_id;
6494
        $link_type = (int) $link_type;
6495
        $course_code = Database::escape_string($course_code);
6496
        $sql = "SELECT locked FROM $table
6497
                WHERE locked = 1 AND ref_id = $item_id AND type = $link_type AND course_code = '$course_code' ";
6498
        $result = Database::query($sql);
6499
        if (Database::num_rows($result)) {
6500
            return true;
6501
        }
6502
    }
6503
6504
    return false;
6505
}
6506
6507
/**
6508
 * Blocks a page if the item was added in a gradebook.
6509
 *
6510
 * @param int       exercise id, work id, thread id,
6511
 * @param int       LINK_EXERCISE, LINK_STUDENTPUBLICATION, LINK_LEARNPATH LINK_FORUM_THREAD, LINK_ATTENDANCE
6512
 * see gradebook/lib/be/linkfactory
6513
 * @param string    course code
6514
 *
6515
 * @return false|null
6516
 */
6517
function api_block_course_item_locked_by_gradebook($item_id, $link_type, $course_code = null)
6518
{
6519
    if (api_is_platform_admin()) {
6520
        return false;
6521
    }
6522
6523
    if (api_resource_is_locked_by_gradebook($item_id, $link_type, $course_code)) {
6524
        $message = Display::return_message(
6525
            get_lang(
6526
                '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.'
6527
            ),
6528
            'warning'
6529
        );
6530
        api_not_allowed(true, $message);
6531
    }
6532
}
6533
6534
/**
6535
 * Checks the PHP version installed is enough to run Chamilo.
6536
 *
6537
 * @param string Include path (used to load the error page)
6538
 */
6539
function api_check_php_version()
6540
{
6541
    if (!function_exists('version_compare') ||
6542
        version_compare(PHP_VERSION, REQUIRED_PHP_VERSION, '<')
6543
    ) {
6544
        throw new Exception('Wrong PHP version');
6545
    }
6546
}
6547
6548
/**
6549
 * Checks whether the Archive directory is present and writeable. If not,
6550
 * prints a warning message.
6551
 */
6552
function api_check_archive_dir()
6553
{
6554
    if (is_dir(api_get_path(SYS_ARCHIVE_PATH)) && !is_writable(api_get_path(SYS_ARCHIVE_PATH))) {
6555
        $message = Display::return_message(
6556
            get_lang(
6557
                'The app/cache/ directory, used by this tool, is not writeable. Please contact your platform administrator.'
6558
            ),
6559
            'warning'
6560
        );
6561
        api_not_allowed(true, $message);
6562
    }
6563
}
6564
6565
/**
6566
 * Returns an array of global configuration settings which should be ignored
6567
 * when printing the configuration settings screens.
6568
 *
6569
 * @return array Array of strings, each identifying one of the excluded settings
6570
 */
6571
function api_get_locked_settings()
6572
{
6573
    return [
6574
        'permanently_remove_deleted_files',
6575
        'account_valid_duration',
6576
        'service_ppt2lp',
6577
        'wcag_anysurfer_public_pages',
6578
        'upload_extensions_list_type',
6579
        'upload_extensions_blacklist',
6580
        'upload_extensions_whitelist',
6581
        'upload_extensions_skip',
6582
        'upload_extensions_replace_by',
6583
        'hide_dltt_markup',
6584
        'split_users_upload_directory',
6585
        'permissions_for_new_directories',
6586
        'permissions_for_new_files',
6587
        'platform_charset',
6588
        'ldap_description',
6589
        'cas_activate',
6590
        'cas_server',
6591
        'cas_server_uri',
6592
        'cas_port',
6593
        'cas_protocol',
6594
        'cas_add_user_activate',
6595
        'update_user_info_cas_with_ldap',
6596
        'languagePriority1',
6597
        'languagePriority2',
6598
        'languagePriority3',
6599
        'languagePriority4',
6600
        'login_is_email',
6601
        'chamilo_database_version',
6602
    ];
6603
}
6604
6605
/**
6606
 * Guess the real ip for register in the database, even in reverse proxy cases.
6607
 * To be recognized, the IP has to be found in either $_SERVER['REMOTE_ADDR'] or
6608
 * in $_SERVER['HTTP_X_FORWARDED_FOR'], which is in common use with rproxies.
6609
 * Note: the result of this function is not SQL-safe. Please escape it before
6610
 * inserting in a database.
6611
 *
6612
 * @return string the user's real ip (unsafe - escape it before inserting to db)
6613
 *
6614
 * @author Jorge Frisancho Jibaja <[email protected]>, USIL - Some changes to allow the use of real IP using reverse proxy
6615
 *
6616
 * @version CEV CHANGE 24APR2012
6617
 */
6618
function api_get_real_ip()
6619
{
6620
    $ip = trim($_SERVER['REMOTE_ADDR']);
6621
    if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
6622
        if (preg_match('/,/', $_SERVER['HTTP_X_FORWARDED_FOR'])) {
6623
            @list($ip1, $ip2) = @explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
6624
        } else {
6625
            $ip1 = $_SERVER['HTTP_X_FORWARDED_FOR'];
6626
        }
6627
        $ip = trim($ip1);
6628
    }
6629
6630
    return $ip;
6631
}
6632
6633
/**
6634
 * Checks whether an IP is included inside an IP range.
6635
 *
6636
 * @param string IP address
6637
 * @param string IP range
6638
 * @param string $ip
6639
 *
6640
 * @return bool True if IP is in the range, false otherwise
6641
 *
6642
 * @author claudiu at cnixs dot com  on http://www.php.net/manual/fr/ref.network.php#55230
6643
 * @author Yannick Warnier for improvements and managment of multiple ranges
6644
 *
6645
 * @todo check for IPv6 support
6646
 */
6647
function api_check_ip_in_range($ip, $range)
6648
{
6649
    if (empty($ip) or empty($range)) {
6650
        return false;
6651
    }
6652
    $ip_ip = ip2long($ip);
6653
    // divide range param into array of elements
6654
    if (false !== strpos($range, ',')) {
6655
        $ranges = explode(',', $range);
6656
    } else {
6657
        $ranges = [$range];
6658
    }
6659
    foreach ($ranges as $range) {
0 ignored issues
show
introduced by
$range is overwriting one of the parameters of this function.
Loading history...
6660
        $range = trim($range);
6661
        if (empty($range)) {
6662
            continue;
6663
        }
6664
        if (false === strpos($range, '/')) {
6665
            if (0 === strcmp($ip, $range)) {
6666
                return true; // there is a direct IP match, return OK
6667
            }
6668
            continue; //otherwise, get to the next range
6669
        }
6670
        // the range contains a "/", so analyse completely
6671
        [$net, $mask] = explode("/", $range);
6672
6673
        $ip_net = ip2long($net);
6674
        // mask binary magic
6675
        $ip_mask = ~((1 << (32 - $mask)) - 1);
6676
6677
        $ip_ip_net = $ip_ip & $ip_mask;
6678
        if ($ip_ip_net == $ip_net) {
6679
            return true;
6680
        }
6681
    }
6682
6683
    return false;
6684
}
6685
6686
function api_check_user_access_to_legal($course_visibility)
6687
{
6688
    $course_visibility_list = [COURSE_VISIBILITY_OPEN_WORLD, COURSE_VISIBILITY_OPEN_PLATFORM];
6689
6690
    return in_array($course_visibility, $course_visibility_list) || api_is_drh();
6691
}
6692
6693
/**
6694
 * Checks if the global chat is enabled or not.
6695
 *
6696
 * @return bool
6697
 */
6698
function api_is_global_chat_enabled()
6699
{
6700
    return
6701
        !api_is_anonymous() &&
6702
        'true' === api_get_setting('allow_global_chat') &&
6703
        'true' === api_get_setting('allow_social_tool');
6704
}
6705
6706
/**
6707
 * @param int   $item_id
6708
 * @param int   $tool_id
6709
 * @param int   $group_id   id
6710
 * @param array $courseInfo
6711
 * @param int   $sessionId
6712
 * @param int   $userId
6713
 *
6714
 * @deprecated
6715
 */
6716
function api_set_default_visibility(
6717
    $item_id,
6718
    $tool_id,
6719
    $group_id = 0,
6720
    $courseInfo = [],
6721
    $sessionId = 0,
6722
    $userId = 0
6723
) {
6724
    $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
6725
    $courseId = $courseInfo['real_id'];
6726
    $courseCode = $courseInfo['code'];
6727
    $sessionId = empty($sessionId) ? api_get_session_id() : $sessionId;
6728
    $userId = empty($userId) ? api_get_user_id() : $userId;
6729
6730
    // if group is null force group_id = 0, this force is needed to create a LP folder with group = 0
6731
    if (is_null($group_id)) {
6732
        $group_id = 0;
6733
    } else {
6734
        $group_id = empty($group_id) ? api_get_group_id() : $group_id;
6735
    }
6736
6737
    $groupInfo = [];
6738
    if (!empty($group_id)) {
6739
        $groupInfo = GroupManager::get_group_properties($group_id);
6740
    }
6741
    $original_tool_id = $tool_id;
6742
6743
    switch ($tool_id) {
6744
        case TOOL_LINK:
6745
        case TOOL_LINK_CATEGORY:
6746
            $tool_id = 'links';
6747
            break;
6748
        case TOOL_DOCUMENT:
6749
            $tool_id = 'documents';
6750
            break;
6751
        case TOOL_LEARNPATH:
6752
            $tool_id = 'learning';
6753
            break;
6754
        case TOOL_ANNOUNCEMENT:
6755
            $tool_id = 'announcements';
6756
            break;
6757
        case TOOL_FORUM:
6758
        case TOOL_FORUM_CATEGORY:
6759
        case TOOL_FORUM_THREAD:
6760
            $tool_id = 'forums';
6761
            break;
6762
        case TOOL_QUIZ:
6763
            $tool_id = 'quiz';
6764
            break;
6765
    }
6766
    $setting = api_get_setting('tool_visible_by_default_at_creation');
6767
6768
    if (isset($setting[$tool_id])) {
6769
        $visibility = 'invisible';
6770
        if ('true' == $setting[$tool_id]) {
6771
            $visibility = 'visible';
6772
        }
6773
6774
        // Read the portal and course default visibility
6775
        if ('documents' === $tool_id) {
6776
            $visibility = DocumentManager::getDocumentDefaultVisibility($courseInfo);
6777
        }
6778
6779
        // Fixes default visibility for tests
6780
        switch ($original_tool_id) {
6781
            case TOOL_QUIZ:
6782
                if (empty($sessionId)) {
6783
                    $objExerciseTmp = new Exercise($courseId);
6784
                    $objExerciseTmp->read($item_id);
6785
                    if ('visible' == $visibility) {
6786
                        $objExerciseTmp->enable();
6787
                        $objExerciseTmp->save();
6788
                    } else {
6789
                        $objExerciseTmp->disable();
6790
                        $objExerciseTmp->save();
6791
                    }
6792
                }
6793
                break;
6794
        }
6795
    }
6796
}
6797
6798
/**
6799
 * @param int $user_id
6800
 * @param int $courseId
6801
 * @param int $session_id
6802
 *
6803
 * @return array
6804
 */
6805
function api_detect_user_roles($user_id, $courseId, $session_id = 0)
6806
{
6807
    $user_roles = [];
6808
    $courseInfo = api_get_course_info_by_id($courseId);
6809
    $course_code = $courseInfo['code'];
6810
6811
    $url_id = api_get_current_access_url_id();
6812
    if (api_is_platform_admin_by_id($user_id, $url_id)) {
6813
        $user_roles[] = PLATFORM_ADMIN;
6814
    }
6815
6816
    /*if (api_is_drh()) {
6817
        $user_roles[] = DRH;
6818
    }*/
6819
6820
    if (!empty($session_id)) {
6821
        if (SessionManager::user_is_general_coach($user_id, $session_id)) {
6822
            $user_roles[] = SESSION_GENERAL_COACH;
6823
        }
6824
    }
6825
6826
    if (!empty($course_code)) {
6827
        if (empty($session_id)) {
6828
            if (CourseManager::isCourseTeacher($user_id, $courseInfo['real_id'])) {
6829
                $user_roles[] = COURSEMANAGER;
6830
            }
6831
            if (CourseManager::get_tutor_in_course_status($user_id, $courseInfo['real_id'])) {
6832
                $user_roles[] = COURSE_TUTOR;
6833
            }
6834
6835
            if (CourseManager::is_user_subscribed_in_course($user_id, $course_code)) {
6836
                $user_roles[] = COURSE_STUDENT;
6837
            }
6838
        } else {
6839
            $user_status_in_session = SessionManager::get_user_status_in_course_session(
6840
                $user_id,
6841
                $courseId,
6842
                $session_id
6843
            );
6844
6845
            if (!empty($user_status_in_session)) {
6846
                if (0 == $user_status_in_session) {
6847
                    $user_roles[] = SESSION_STUDENT;
6848
                }
6849
                if (2 == $user_status_in_session) {
6850
                    $user_roles[] = SESSION_COURSE_COACH;
6851
                }
6852
            }
6853
6854
            /*if (api_is_course_session_coach($user_id, $course_code, $session_id)) {
6855
               $user_roles[] = SESSION_COURSE_COACH;
6856
            }*/
6857
        }
6858
    }
6859
6860
    return $user_roles;
6861
}
6862
6863
/**
6864
 * @param int $courseId
6865
 * @param int $session_id
6866
 *
6867
 * @return bool
6868
 */
6869
function api_coach_can_edit_view_results($courseId = null, $session_id = null)
6870
{
6871
    if (api_is_platform_admin()) {
6872
        return true;
6873
    }
6874
6875
    $user_id = api_get_user_id();
6876
6877
    if (empty($courseId)) {
6878
        $courseId = api_get_course_int_id();
6879
    }
6880
6881
    if (empty($session_id)) {
6882
        $session_id = api_get_session_id();
6883
    }
6884
6885
    $roles = api_detect_user_roles($user_id, $courseId, $session_id);
6886
6887
    if (in_array(SESSION_COURSE_COACH, $roles)) {
6888
        //return api_get_setting('session_tutor_reports_visibility') == 'true';
6889
        return true;
6890
    } else {
6891
        if (in_array(COURSEMANAGER, $roles)) {
6892
            return true;
6893
        }
6894
6895
        return false;
6896
    }
6897
}
6898
6899
/**
6900
 * @param string $file
6901
 *
6902
 * @return string
6903
 */
6904
function api_get_js_simple($file)
6905
{
6906
    return '<script type="text/javascript" src="'.$file.'"></script>'."\n";
6907
}
6908
6909
/**
6910
 * Modify default memory_limit and max_execution_time limits
6911
 * Needed when processing long tasks.
6912
 */
6913
function api_set_more_memory_and_time_limits()
6914
{
6915
    if (function_exists('ini_set')) {
6916
        api_set_memory_limit('256M');
6917
        ini_set('max_execution_time', 1800);
6918
    }
6919
}
6920
6921
/**
6922
 * Tries to set memory limit, if authorized and new limit is higher than current.
6923
 *
6924
 * @param string $mem New memory limit
6925
 *
6926
 * @return bool True on success, false on failure or current is higher than suggested
6927
 * @assert (null) === false
6928
 * @assert (-1) === false
6929
 * @assert (0) === true
6930
 * @assert ('1G') === true
6931
 */
6932
function api_set_memory_limit($mem)
6933
{
6934
    //if ini_set() not available, this function is useless
6935
    if (!function_exists('ini_set') || is_null($mem) || -1 == $mem) {
6936
        return false;
6937
    }
6938
6939
    $memory_limit = ini_get('memory_limit');
6940
    if (api_get_bytes_memory_limit($mem) > api_get_bytes_memory_limit($memory_limit)) {
6941
        ini_set('memory_limit', $mem);
6942
6943
        return true;
6944
    }
6945
6946
    return false;
6947
}
6948
6949
/**
6950
 * Gets memory limit in bytes.
6951
 *
6952
 * @param string The memory size (128M, 1G, 1000K, etc)
6953
 *
6954
 * @return int
6955
 * @assert (null) === false
6956
 * @assert ('1t')  === 1099511627776
6957
 * @assert ('1g')  === 1073741824
6958
 * @assert ('1m')  === 1048576
6959
 * @assert ('100k') === 102400
6960
 */
6961
function api_get_bytes_memory_limit($mem)
6962
{
6963
    $size = strtolower(substr($mem, -1));
6964
6965
    switch ($size) {
6966
        case 't':
6967
            $mem = intval(substr($mem, -1)) * 1024 * 1024 * 1024 * 1024;
6968
            break;
6969
        case 'g':
6970
            $mem = intval(substr($mem, 0, -1)) * 1024 * 1024 * 1024;
6971
            break;
6972
        case 'm':
6973
            $mem = intval(substr($mem, 0, -1)) * 1024 * 1024;
6974
            break;
6975
        case 'k':
6976
            $mem = intval(substr($mem, 0, -1)) * 1024;
6977
            break;
6978
        default:
6979
            // we assume it's integer only
6980
            $mem = intval($mem);
6981
            break;
6982
    }
6983
6984
    return $mem;
6985
}
6986
6987
/**
6988
 * Finds all the information about a user from username instead of user id.
6989
 *
6990
 * @param string $officialCode
6991
 *
6992
 * @return array $user_info user_id, lastname, firstname, username, email, ...
6993
 *
6994
 * @author Yannick Warnier <[email protected]>
6995
 */
6996
function api_get_user_info_from_official_code($officialCode)
6997
{
6998
    if (empty($officialCode)) {
6999
        return false;
7000
    }
7001
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
7002
            WHERE official_code ='".Database::escape_string($officialCode)."'";
7003
    $result = Database::query($sql);
7004
    if (Database::num_rows($result) > 0) {
7005
        $result_array = Database::fetch_array($result);
7006
7007
        return _api_format_user($result_array);
7008
    }
7009
7010
    return false;
7011
}
7012
7013
/**
7014
 * @param string $usernameInputId
7015
 * @param string $passwordInputId
7016
 *
7017
 * @return string|null
7018
 */
7019
function api_get_password_checker_js($usernameInputId, $passwordInputId)
7020
{
7021
    $checkPass = api_get_setting('allow_strength_pass_checker');
7022
    $useStrengthPassChecker = 'true' === $checkPass;
7023
7024
    if (false === $useStrengthPassChecker) {
7025
        return null;
7026
    }
7027
7028
    $translations = [
7029
        'wordLength' => get_lang('The password is too short'),
7030
        'wordNotEmail' => get_lang('Your password cannot be the same as your email'),
7031
        'wordSimilarToUsername' => get_lang('Your password cannot contain your username'),
7032
        'wordTwoCharacterClasses' => get_lang('Use different character classes'),
7033
        'wordRepetitions' => get_lang('Too many repetitions'),
7034
        'wordSequences' => get_lang('Your password contains sequences'),
7035
        'errorList' => get_lang('errors found'),
7036
        'veryWeak' => get_lang('Very weak'),
7037
        'weak' => get_lang('Weak'),
7038
        'normal' => get_lang('Normal'),
7039
        'medium' => get_lang('Medium'),
7040
        'strong' => get_lang('Strong'),
7041
        'veryStrong' => get_lang('Very strong'),
7042
    ];
7043
7044
    $js = api_get_asset('pwstrength-bootstrap/dist/pwstrength-bootstrap.js');
7045
    $js .= "<script>
7046
    var errorMessages = {
7047
        password_to_short : \"".get_lang('The password is too short')."\",
7048
        same_as_username : \"".get_lang('Your password cannot be the same as your username')."\"
7049
    };
7050
7051
    $(function() {
7052
        var lang = ".json_encode($translations).";
7053
        var options = {
7054
            onLoad : function () {
7055
                //$('#messages').text('Start typing password');
7056
            },
7057
            onKeyUp: function (evt) {
7058
                $(evt.target).pwstrength('outputErrorList');
7059
            },
7060
            errorMessages : errorMessages,
7061
            viewports: {
7062
                progress: '#password_progress',
7063
                verdict: '#password-verdict',
7064
                errors: '#password-errors'
7065
            },
7066
            usernameField: '$usernameInputId'
7067
        };
7068
        options.i18n = {
7069
            t: function (key) {
7070
                var result = lang[key];
7071
                return result === key ? '' : result; // This assumes you return the
7072
            }
7073
        };
7074
        $('".$passwordInputId."').pwstrength(options);
7075
    });
7076
    </script>";
7077
7078
    return $js;
7079
}
7080
7081
/**
7082
 * create an user extra field called 'captcha_blocked_until_date'.
7083
 *
7084
 * @param string $username
7085
 *
7086
 * @return bool
7087
 */
7088
function api_block_account_captcha($username)
7089
{
7090
    $userInfo = api_get_user_info_from_username($username);
7091
    if (empty($userInfo)) {
7092
        return false;
7093
    }
7094
    $minutesToBlock = api_get_setting('captcha_time_to_block');
7095
    $time = time() + $minutesToBlock * 60;
7096
    UserManager::update_extra_field_value(
7097
        $userInfo['user_id'],
7098
        'captcha_blocked_until_date',
7099
        api_get_utc_datetime($time)
7100
    );
7101
7102
    return true;
7103
}
7104
7105
/**
7106
 * @param string $username
7107
 *
7108
 * @return bool
7109
 */
7110
function api_clean_account_captcha($username)
7111
{
7112
    $userInfo = api_get_user_info_from_username($username);
7113
    if (empty($userInfo)) {
7114
        return false;
7115
    }
7116
    Session::erase('loginFailedCount');
7117
    UserManager::update_extra_field_value(
7118
        $userInfo['user_id'],
7119
        'captcha_blocked_until_date',
7120
        null
7121
    );
7122
7123
    return true;
7124
}
7125
7126
/**
7127
 * @param string $username
7128
 *
7129
 * @return bool
7130
 */
7131
function api_get_user_blocked_by_captcha($username)
7132
{
7133
    $userInfo = api_get_user_info_from_username($username);
7134
    if (empty($userInfo)) {
7135
        return false;
7136
    }
7137
    $data = UserManager::get_extra_user_data_by_field(
7138
        $userInfo['user_id'],
7139
        'captcha_blocked_until_date'
7140
    );
7141
    if (isset($data) && isset($data['captcha_blocked_until_date'])) {
7142
        return $data['captcha_blocked_until_date'];
7143
    }
7144
7145
    return false;
7146
}
7147
7148
/**
7149
 * Remove tags from HTML anf return the $in_number_char first non-HTML char
7150
 * Postfix the text with "..." if it has been truncated.
7151
 *
7152
 * @param string $text
7153
 * @param int    $number
7154
 *
7155
 * @return string
7156
 *
7157
 * @author hubert borderiou
7158
 */
7159
function api_get_short_text_from_html($text, $number)
7160
{
7161
    // Delete script and style tags
7162
    $text = preg_replace('/(<(script|style)\b[^>]*>).*?(<\/\2>)/is', "$1$3", $text);
7163
    $text = api_html_entity_decode($text);
7164
    $out_res = api_remove_tags_with_space($text, false);
7165
    $postfix = "...";
7166
    if (strlen($out_res) > $number) {
7167
        $out_res = substr($out_res, 0, $number).$postfix;
7168
    }
7169
7170
    return $out_res;
7171
}
7172
7173
/**
7174
 * Replace tags with a space in a text.
7175
 * If $in_double_quote_replace, replace " with '' (for HTML attribute purpose, for exemple).
7176
 *
7177
 * @return string
7178
 *
7179
 * @author hubert borderiou
7180
 */
7181
function api_remove_tags_with_space($in_html, $in_double_quote_replace = true)
7182
{
7183
    $out_res = $in_html;
7184
    if ($in_double_quote_replace) {
7185
        $out_res = str_replace('"', "''", $out_res);
7186
    }
7187
    // avoid text stuck together when tags are removed, adding a space after >
7188
    $out_res = str_replace(">", "> ", $out_res);
7189
    $out_res = strip_tags($out_res);
7190
7191
    return $out_res;
7192
}
7193
7194
/**
7195
 * If true, the drh can access all content (courses, users) inside a session.
7196
 *
7197
 * @return bool
7198
 */
7199
function api_drh_can_access_all_session_content()
7200
{
7201
    return 'true' === api_get_setting('drh_can_access_all_session_content');
7202
}
7203
7204
/**
7205
 * @param string $tool
7206
 * @param string $setting
7207
 * @param int    $defaultValue
7208
 *
7209
 * @return string
7210
 */
7211
function api_get_default_tool_setting($tool, $setting, $defaultValue)
7212
{
7213
    global $_configuration;
7214
    if (isset($_configuration[$tool]) &&
7215
        isset($_configuration[$tool]['default_settings']) &&
7216
        isset($_configuration[$tool]['default_settings'][$setting])
7217
    ) {
7218
        return $_configuration[$tool]['default_settings'][$setting];
7219
    }
7220
7221
    return $defaultValue;
7222
}
7223
7224
/**
7225
 * Checks if user can login as another user.
7226
 *
7227
 * @param int $loginAsUserId the user id to log in
7228
 * @param int $userId        my user id
7229
 *
7230
 * @return bool
7231
 */
7232
function api_can_login_as($loginAsUserId, $userId = null)
7233
{
7234
    $loginAsUserId = (int) $loginAsUserId;
7235
7236
    if (empty($loginAsUserId)) {
7237
        return false;
7238
    }
7239
7240
    if (empty($userId)) {
7241
        $userId = api_get_user_id();
7242
    }
7243
7244
    if ($loginAsUserId == $userId) {
7245
        return false;
7246
    }
7247
7248
    // Check if the user to login is an admin
7249
    if (api_is_platform_admin_by_id($loginAsUserId)) {
7250
        // Only super admins can login to admin accounts
7251
        if (!api_global_admin_can_edit_admin($loginAsUserId)) {
7252
            return false;
7253
        }
7254
    }
7255
7256
    $userInfo = api_get_user_info($loginAsUserId);
7257
7258
    $isDrh = function () use ($loginAsUserId) {
7259
        if (api_is_drh()) {
7260
            if (api_drh_can_access_all_session_content()) {
7261
                $users = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus(
7262
                    'drh_all',
7263
                    api_get_user_id()
7264
                );
7265
                $userList = [];
7266
                if (is_array($users)) {
7267
                    foreach ($users as $user) {
7268
                        $userList[] = $user['id'];
7269
                    }
7270
                }
7271
                if (in_array($loginAsUserId, $userList)) {
7272
                    return true;
7273
                }
7274
            } else {
7275
                if (api_is_drh() &&
7276
                    UserManager::is_user_followed_by_drh($loginAsUserId, api_get_user_id())
7277
                ) {
7278
                    return true;
7279
                }
7280
            }
7281
        }
7282
7283
        return false;
7284
    };
7285
7286
    $loginAsStatusForSessionAdmins = [STUDENT];
7287
7288
    if (api_get_setting('session.allow_session_admin_login_as_teacher')) {
7289
        $loginAsStatusForSessionAdmins[] = COURSEMANAGER;
7290
    }
7291
7292
    return api_is_platform_admin() ||
7293
        (api_is_session_admin() && in_array($userInfo['status'], $loginAsStatusForSessionAdmins)) ||
7294
        $isDrh();
7295
}
7296
7297
/**
7298
 * @return bool
7299
 */
7300
function api_is_allowed_in_course()
7301
{
7302
    if (api_is_platform_admin()) {
7303
        return true;
7304
    }
7305
7306
    $user = api_get_current_user();
7307
    if ($user instanceof User) {
7308
        if ($user->hasRole('ROLE_CURRENT_COURSE_SESSION_STUDENT') ||
7309
            $user->hasRole('ROLE_CURRENT_COURSE_SESSION_TEACHER') ||
7310
            $user->hasRole('ROLE_CURRENT_COURSE_STUDENT') ||
7311
            $user->hasRole('ROLE_CURRENT_COURSE_TEACHER')
7312
        ) {
7313
            return true;
7314
        }
7315
    }
7316
7317
    return false;
7318
}
7319
7320
/**
7321
 * Return true on https install.
7322
 *
7323
 * @return bool
7324
 */
7325
function api_is_https()
7326
{
7327
    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...
7328
        'https' == $_SERVER['HTTP_X_FORWARDED_PROTO'] || !empty(api_get_configuration_value('force_https_forwarded_proto'))
7329
    ) {
7330
        $isSecured = true;
7331
    } else {
7332
        if (!empty($_SERVER['HTTPS']) && 'off' != $_SERVER['HTTPS']) {
7333
            $isSecured = true;
7334
        } else {
7335
            $isSecured = false;
7336
            // last chance
7337
            if (!empty($_SERVER['SERVER_PORT']) && 443 == $_SERVER['SERVER_PORT']) {
7338
                $isSecured = true;
7339
            }
7340
        }
7341
    }
7342
7343
    return $isSecured;
7344
}
7345
7346
/**
7347
 * Return protocol (http or https).
7348
 *
7349
 * @return string
7350
 */
7351
function api_get_protocol()
7352
{
7353
    return api_is_https() ? 'https' : 'http';
7354
}
7355
7356
/**
7357
 * Get origin.
7358
 *
7359
 * @param string
7360
 *
7361
 * @return string
7362
 */
7363
function api_get_origin()
7364
{
7365
    return isset($_REQUEST['origin']) ? urlencode(Security::remove_XSS(urlencode($_REQUEST['origin']))) : '';
7366
}
7367
7368
/**
7369
 * Warns an user that the portal reach certain limit.
7370
 *
7371
 * @param string $limitName
7372
 */
7373
function api_warn_hosting_contact($limitName)
7374
{
7375
    $hostingParams = api_get_configuration_value(1);
7376
    $email = null;
7377
7378
    if (!empty($hostingParams)) {
7379
        if (isset($hostingParams['hosting_contact_mail'])) {
7380
            $email = $hostingParams['hosting_contact_mail'];
7381
        }
7382
    }
7383
7384
    if (!empty($email)) {
7385
        $subject = get_lang('Hosting warning reached');
7386
        $body = get_lang('Portal name').': '.api_get_path(WEB_PATH)." \n ";
7387
        $body .= get_lang('Portal\'s limit type').': '.$limitName." \n ";
7388
        if (isset($hostingParams[$limitName])) {
7389
            $body .= get_lang('Value').': '.$hostingParams[$limitName];
7390
        }
7391
        api_mail_html(null, $email, $subject, $body);
7392
    }
7393
}
7394
7395
/**
7396
 * Gets value of a variable from config/configuration.php
7397
 * Variables that are not set in the configuration.php file but set elsewhere:
7398
 * - virtual_css_theme_folder (vchamilo plugin)
7399
 * - access_url (global.inc.php)
7400
 * - apc/apc_prefix (global.inc.php).
7401
 *
7402
 * @param string $variable
7403
 *
7404
 * @return bool|mixed
7405
 */
7406
function api_get_configuration_value($variable)
7407
{
7408
    global $_configuration;
7409
    // Check the current url id, id = 1 by default
7410
    $urlId = isset($_configuration['access_url']) ? (int) $_configuration['access_url'] : 1;
7411
7412
    $variable = trim($variable);
7413
7414
    // Check if variable exists
7415
    if (isset($_configuration[$variable])) {
7416
        if (is_array($_configuration[$variable])) {
7417
            // Check if it exists for the sub portal
7418
            if (array_key_exists($urlId, $_configuration[$variable])) {
7419
                return $_configuration[$variable][$urlId];
7420
            } else {
7421
                // Try to found element with id = 1 (master portal)
7422
                if (array_key_exists(1, $_configuration[$variable])) {
7423
                    return $_configuration[$variable][1];
7424
                }
7425
            }
7426
        }
7427
7428
        return $_configuration[$variable];
7429
    }
7430
7431
    return false;
7432
}
7433
7434
/**
7435
 * Retreives and returns a value in a hierarchical configuration array
7436
 * api_get_configuration_sub_value('a/b/c') returns api_get_configuration_value('a')['b']['c'].
7437
 *
7438
 * @param string $path      the successive array keys, separated by the separator
7439
 * @param mixed  $default   value to be returned if not found, null by default
7440
 * @param string $separator '/' by default
7441
 * @param array  $array     the active configuration array by default
7442
 *
7443
 * @return mixed the found value or $default
7444
 */
7445
function api_get_configuration_sub_value($path, $default = null, $separator = '/', $array = null)
7446
{
7447
    $pos = strpos($path, $separator);
7448
    if (false === $pos) {
7449
        if (is_null($array)) {
7450
            return api_get_configuration_value($path);
7451
        }
7452
        if (is_array($array) && array_key_exists($path, $array)) {
7453
            return $array[$path];
7454
        }
7455
7456
        return $default;
7457
    }
7458
    $key = substr($path, 0, $pos);
7459
    if (is_null($array)) {
7460
        $newArray = api_get_configuration_value($key);
7461
    } elseif (is_array($array) && array_key_exists($key, $array)) {
7462
        $newArray = $array[$key];
7463
    } else {
7464
        return $default;
7465
    }
7466
    if (is_array($newArray)) {
7467
        $newPath = substr($path, $pos + 1);
7468
7469
        return api_get_configuration_sub_value($newPath, $default, $separator, $newArray);
7470
    }
7471
7472
    return $default;
7473
}
7474
7475
/**
7476
 * Retrieves and returns a value in a hierarchical configuration array
7477
 * api_array_sub_value($array, 'a/b/c') returns $array['a']['b']['c'].
7478
 *
7479
 * @param array  $array     the recursive array that contains the value to be returned (or not)
7480
 * @param string $path      the successive array keys, separated by the separator
7481
 * @param mixed  $default   the value to be returned if not found
7482
 * @param string $separator the separator substring
7483
 *
7484
 * @return mixed the found value or $default
7485
 */
7486
function api_array_sub_value($array, $path, $default = null, $separator = '/')
7487
{
7488
    $pos = strpos($path, $separator);
7489
    if (false === $pos) {
7490
        if (is_array($array) && array_key_exists($path, $array)) {
7491
            return $array[$path];
7492
        }
7493
7494
        return $default;
7495
    }
7496
    $key = substr($path, 0, $pos);
7497
    if (is_array($array) && array_key_exists($key, $array)) {
7498
        $newArray = $array[$key];
7499
    } else {
7500
        return $default;
7501
    }
7502
    if (is_array($newArray)) {
7503
        $newPath = substr($path, $pos + 1);
7504
7505
        return api_array_sub_value($newArray, $newPath, $default);
7506
    }
7507
7508
    return $default;
7509
}
7510
7511
/**
7512
 * Returns supported image extensions in the portal.
7513
 *
7514
 * @param bool $supportVectors Whether vector images should also be accepted or not
7515
 *
7516
 * @return array Supported image extensions in the portal
7517
 */
7518
function api_get_supported_image_extensions($supportVectors = true)
7519
{
7520
    // jpg can also be called jpeg, jpe, jfif and jif. See https://en.wikipedia.org/wiki/JPEG#JPEG_filename_extensions
7521
    $supportedImageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'jpe', 'jfif', 'jif'];
7522
    if ($supportVectors) {
7523
        array_push($supportedImageExtensions, 'svg');
7524
    }
7525
    if (version_compare(PHP_VERSION, '5.5.0', '>=')) {
7526
        array_push($supportedImageExtensions, 'webp');
7527
    }
7528
7529
    return $supportedImageExtensions;
7530
}
7531
7532
/**
7533
 * This setting changes the registration status for the campus.
7534
 *
7535
 * @author Patrick Cool <[email protected]>, Ghent University
7536
 *
7537
 * @version August 2006
7538
 *
7539
 * @param bool $listCampus Whether we authorize
7540
 *
7541
 * @todo the $_settings should be reloaded here. => write api function for this and use this in global.inc.php also.
7542
 */
7543
function api_register_campus($listCampus = true)
7544
{
7545
    $tbl_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
7546
7547
    $sql = "UPDATE $tbl_settings SET selected_value='true' WHERE variable='registered'";
7548
    Database::query($sql);
7549
7550
    if (!$listCampus) {
7551
        $sql = "UPDATE $tbl_settings SET selected_value='true' WHERE variable='donotlistcampus'";
7552
        Database::query($sql);
7553
    }
7554
}
7555
7556
/**
7557
 * Checks whether current user is a student boss.
7558
 *
7559
 * @global array $_user
7560
 *
7561
 * @return bool
7562
 */
7563
function api_is_student_boss()
7564
{
7565
    $_user = api_get_user_info();
7566
7567
    return isset($_user['status']) && STUDENT_BOSS == $_user['status'];
7568
}
7569
7570
/**
7571
 * Check whether the user type should be exclude.
7572
 * Such as invited or anonymous users.
7573
 *
7574
 * @param bool $checkDB Optional. Whether check the user status
7575
 * @param int  $userId  Options. The user id
7576
 *
7577
 * @return bool
7578
 */
7579
function api_is_excluded_user_type($checkDB = false, $userId = 0)
7580
{
7581
    if ($checkDB) {
7582
        $userId = empty($userId) ? api_get_user_id() : (int) $userId;
7583
7584
        if (0 == $userId) {
7585
            return true;
7586
        }
7587
7588
        $userInfo = api_get_user_info($userId);
7589
7590
        switch ($userInfo['status']) {
7591
            case INVITEE:
7592
            case ANONYMOUS:
7593
                return true;
7594
            default:
7595
                return false;
7596
        }
7597
    }
7598
7599
    $isInvited = api_is_invitee();
7600
    $isAnonymous = api_is_anonymous();
7601
7602
    if ($isInvited || $isAnonymous) {
7603
        return true;
7604
    }
7605
7606
    return false;
7607
}
7608
7609
/**
7610
 * Get the user status to ignore in reports.
7611
 *
7612
 * @param string $format Optional. The result type (array or string)
7613
 *
7614
 * @return array|string
7615
 */
7616
function api_get_users_status_ignored_in_reports($format = 'array')
7617
{
7618
    $excludedTypes = [
7619
        INVITEE,
7620
        ANONYMOUS,
7621
    ];
7622
7623
    if ('string' == $format) {
7624
        return implode(', ', $excludedTypes);
7625
    }
7626
7627
    return $excludedTypes;
7628
}
7629
7630
/**
7631
 * Set the Site Use Cookie Warning for 1 year.
7632
 */
7633
function api_set_site_use_cookie_warning_cookie()
7634
{
7635
    setcookie('ChamiloUsesCookies', 'ok', time() + 31556926);
7636
}
7637
7638
/**
7639
 * Return true if the Site Use Cookie Warning Cookie warning exists.
7640
 *
7641
 * @return bool
7642
 */
7643
function api_site_use_cookie_warning_cookie_exist()
7644
{
7645
    return isset($_COOKIE['ChamiloUsesCookies']);
7646
}
7647
7648
/**
7649
 * Given a number of seconds, format the time to show hours, minutes and seconds.
7650
 *
7651
 * @param int    $time         The time in seconds
7652
 * @param string $originFormat Optional. PHP o JS
7653
 *
7654
 * @return string (00h00'00")
7655
 */
7656
function api_format_time($time, $originFormat = 'php')
7657
{
7658
    $h = get_lang('h');
7659
    $hours = $time / 3600;
7660
    $mins = ($time % 3600) / 60;
7661
    $secs = ($time % 60);
7662
7663
    if ($time < 0) {
7664
        $hours = 0;
7665
        $mins = 0;
7666
        $secs = 0;
7667
    }
7668
7669
    if ('js' === $originFormat) {
7670
        $formattedTime = trim(sprintf("%02d : %02d : %02d", $hours, $mins, $secs));
7671
    } else {
7672
        $formattedTime = trim(sprintf("%02d$h%02d'%02d\"", $hours, $mins, $secs));
7673
    }
7674
7675
    return $formattedTime;
7676
}
7677
7678
/**
7679
 * Sends an email
7680
 * Sender name and email can be specified, if not specified
7681
 * name and email of the platform admin are used.
7682
 *
7683
 * @param string    name of recipient
7684
 * @param string    email of recipient
7685
 * @param string    email subject
7686
 * @param string    email body
7687
 * @param string    sender name
7688
 * @param string    sender e-mail
7689
 * @param array     extra headers in form $headers = array($name => $value) to allow parsing
7690
 * @param array     data file (path and filename)
7691
 * @param bool      True for attaching a embedded file inside content html (optional)
7692
 * @param array     Additional parameters
7693
 *
7694
 * @return bool true if mail was sent
7695
 */
7696
function api_mail_html(
7697
    $recipientName,
7698
    $recipientEmail,
7699
    $subject,
7700
    $body,
7701
    $senderName = '',
7702
    $senderEmail = '',
7703
    $extra_headers = [],
7704
    $data_file = [],
7705
    $embeddedImage = false,
7706
    $additionalParameters = []
7707
) {
7708
    if (!api_valid_email($recipientEmail)) {
7709
        return false;
7710
    }
7711
7712
    // Default values
7713
    $notification = new Notification();
7714
    $defaultEmail = $notification->getDefaultPlatformSenderEmail();
7715
    $defaultName = $notification->getDefaultPlatformSenderName();
7716
7717
    // If the parameter is set don't use the admin.
7718
    $senderName = !empty($senderName) ? $senderName : $defaultName;
7719
    $senderEmail = !empty($senderEmail) ? $senderEmail : $defaultEmail;
7720
7721
    // Reply to first
7722
    $replyToName = '';
7723
    $replyToEmail = '';
7724
    if (isset($extra_headers['reply_to'])) {
7725
        $replyToEmail = $extra_headers['reply_to']['mail'];
7726
        $replyToName = $extra_headers['reply_to']['name'];
7727
    }
7728
7729
    try {
7730
        $message = new TemplatedEmail();
7731
        $message->subject($subject);
7732
7733
        $list = api_get_configuration_value('send_all_emails_to');
7734
        if (!empty($list) && isset($list['emails'])) {
7735
            foreach ($list['emails'] as $email) {
7736
                $message->cc($email);
7737
            }
7738
        }
7739
7740
        // Attachment
7741
        if (!empty($data_file)) {
7742
            foreach ($data_file as $file_attach) {
7743
                if (!empty($file_attach['path']) && !empty($file_attach['filename'])) {
7744
                    $message->attachFromPath($file_attach['path'], $file_attach['filename']);
7745
                }
7746
            }
7747
        }
7748
7749
        $noReply = api_get_setting('noreply_email_address');
7750
        $automaticEmailText = '';
7751
        if (!empty($noReply)) {
7752
            $automaticEmailText = '<br />'.get_lang('This is an automatic email message. Please do not reply to it.');
7753
        }
7754
7755
        $params = [
7756
            'mail_header_style' => api_get_configuration_value('mail_header_style'),
7757
            'mail_content_style' => api_get_configuration_value('mail_content_style'),
7758
            'link' => $additionalParameters['link'] ?? '',
7759
            'automatic_email_text' => $automaticEmailText,
7760
            'content' => $body,
7761
            'theme' => api_get_visual_theme(),
7762
        ];
7763
7764
        if (!empty($senderEmail)) {
7765
            $message->from(new Address($senderEmail, $senderName));
7766
        }
7767
7768
        if (!empty($recipientEmail)) {
7769
            $message->to(new Address($recipientEmail, $recipientName));
7770
        }
7771
7772
        if (!empty($replyToEmail)) {
7773
            $message->replyTo(new Address($replyToEmail, $replyToName));
7774
        }
7775
7776
        $message
7777
            ->htmlTemplate('ChamiloCoreBundle:Mailer:Default/default.html.twig')
7778
            ->textTemplate('ChamiloCoreBundle:Mailer:Default/default.text.twig')
7779
        ;
7780
        $message->context($params);
7781
        Container::getMailer()->send($message);
7782
7783
        return true;
7784
    } catch (Exception $e) {
7785
        error_log($e->getMessage());
7786
    }
7787
7788
    if (!empty($additionalParameters)) {
7789
        $plugin = new AppPlugin();
7790
        $smsPlugin = $plugin->getSMSPluginLibrary();
7791
        if ($smsPlugin) {
0 ignored issues
show
introduced by
$smsPlugin is of type SmsPluginLibraryInterface, thus it always evaluated to true.
Loading history...
7792
            $smsPlugin->send($additionalParameters);
7793
        }
7794
    }
7795
7796
    return 1;
7797
}
7798
7799
/**
7800
 * @param int  $tool Possible values: GroupManager::GROUP_TOOL_*
7801
 * @param bool $showHeader
7802
 */
7803
function api_protect_course_group($tool, $showHeader = true)
7804
{
7805
    $groupId = api_get_group_id();
7806
    if (!empty($groupId)) {
7807
        if (api_is_platform_admin()) {
7808
            return true;
7809
        }
7810
7811
        if (api_is_allowed_to_edit(false, true, true)) {
7812
            return true;
7813
        }
7814
7815
        $userId = api_get_user_id();
7816
        $sessionId = api_get_session_id();
7817
        if (!empty($sessionId)) {
7818
            if (api_is_coach($sessionId, api_get_course_int_id())) {
7819
                return true;
7820
            }
7821
7822
            if (api_is_drh()) {
7823
                if (SessionManager::isUserSubscribedAsHRM($sessionId, $userId)) {
7824
                    return true;
7825
                }
7826
            }
7827
        }
7828
7829
        $group = api_get_group_entity($groupId);
7830
7831
        // Group doesn't exists
7832
        if (null === $group) {
7833
            api_not_allowed($showHeader);
7834
        }
7835
7836
        // Check group access
7837
        $allow = GroupManager::userHasAccess(
7838
            $userId,
7839
            $group,
7840
            $tool
7841
        );
7842
7843
        if (!$allow) {
7844
            api_not_allowed($showHeader);
7845
        }
7846
    }
7847
7848
    return false;
7849
}
7850
7851
/**
7852
 * Check if a date is in a date range.
7853
 *
7854
 * @param datetime $startDate
7855
 * @param datetime $endDate
7856
 * @param datetime $currentDate
7857
 *
7858
 * @return bool true if date is in rage, false otherwise
7859
 */
7860
function api_is_date_in_date_range($startDate, $endDate, $currentDate = null)
7861
{
7862
    $startDate = strtotime(api_get_local_time($startDate));
7863
    $endDate = strtotime(api_get_local_time($endDate));
7864
    $currentDate = strtotime(api_get_local_time($currentDate));
7865
7866
    if ($currentDate >= $startDate && $currentDate <= $endDate) {
7867
        return true;
7868
    }
7869
7870
    return false;
7871
}
7872
7873
/**
7874
 * Eliminate the duplicates of a multidimensional array by sending the key.
7875
 *
7876
 * @param array $array multidimensional array
7877
 * @param int   $key   key to find to compare
7878
 *
7879
 * @return array
7880
 */
7881
function api_unique_multidim_array($array, $key)
7882
{
7883
    $temp_array = [];
7884
    $i = 0;
7885
    $key_array = [];
7886
7887
    foreach ($array as $val) {
7888
        if (!in_array($val[$key], $key_array)) {
7889
            $key_array[$i] = $val[$key];
7890
            $temp_array[$i] = $val;
7891
        }
7892
        $i++;
7893
    }
7894
7895
    return $temp_array;
7896
}
7897
7898
/**
7899
 * Limit the access to Session Admins when the limit_session_admin_role
7900
 * configuration variable is set to true.
7901
 */
7902
function api_protect_limit_for_session_admin()
7903
{
7904
    $limitAdmin = api_get_setting('limit_session_admin_role');
7905
    if (api_is_session_admin() && 'true' === $limitAdmin) {
7906
        api_not_allowed(true);
7907
    }
7908
}
7909
7910
/**
7911
 * Limits that a session admin has access to list users.
7912
 * When limit_session_admin_list_users configuration variable is set to true.
7913
 */
7914
function api_protect_session_admin_list_users()
7915
{
7916
    $limitAdmin = api_get_configuration_value('limit_session_admin_list_users');
7917
7918
    if (api_is_session_admin() && true === $limitAdmin) {
7919
        api_not_allowed(true);
7920
    }
7921
}
7922
7923
/**
7924
 * @return bool
7925
 */
7926
function api_is_student_view_active()
7927
{
7928
    $studentView = Session::read('studentview');
7929
7930
    return 'studentview' === $studentView;
7931
}
7932
7933
/**
7934
 * Converts string value to float value.
7935
 *
7936
 * 3.141516 => 3.141516
7937
 * 3,141516 => 3.141516
7938
 *
7939
 * @todo WIP
7940
 *
7941
 * @param string $number
7942
 *
7943
 * @return float
7944
 */
7945
function api_float_val($number)
7946
{
7947
    return (float) str_replace(',', '.', trim($number));
7948
}
7949
7950
/**
7951
 * Converts float values
7952
 * Example if $decimals = 2.
7953
 *
7954
 * 3.141516 => 3.14
7955
 * 3,141516 => 3,14
7956
 *
7957
 * @param string $number            number in iso code
7958
 * @param int    $decimals
7959
 * @param string $decimalSeparator
7960
 * @param string $thousandSeparator
7961
 *
7962
 * @return bool|string
7963
 */
7964
function api_number_format($number, $decimals = 0, $decimalSeparator = '.', $thousandSeparator = ',')
7965
{
7966
    $number = api_float_val($number);
7967
7968
    return number_format($number, $decimals, $decimalSeparator, $thousandSeparator);
7969
}
7970
7971
/**
7972
 * Set location url with a exit break by default.
7973
 *
7974
 * @param string $url
7975
 * @param bool   $exit
7976
 */
7977
function api_location($url, $exit = true)
7978
{
7979
    header('Location: '.$url);
7980
7981
    if ($exit) {
7982
        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...
7983
    }
7984
}
7985
7986
/**
7987
 * @param string $from
7988
 * @param string $to
7989
 *
7990
 * @return string
7991
 */
7992
function api_get_relative_path($from, $to)
7993
{
7994
    // some compatibility fixes for Windows paths
7995
    $from = is_dir($from) ? rtrim($from, '\/').'/' : $from;
7996
    $to = is_dir($to) ? rtrim($to, '\/').'/' : $to;
7997
    $from = str_replace('\\', '/', $from);
7998
    $to = str_replace('\\', '/', $to);
7999
8000
    $from = explode('/', $from);
8001
    $to = explode('/', $to);
8002
    $relPath = $to;
8003
8004
    foreach ($from as $depth => $dir) {
8005
        // find first non-matching dir
8006
        if ($dir === $to[$depth]) {
8007
            // ignore this directory
8008
            array_shift($relPath);
8009
        } else {
8010
            // get number of remaining dirs to $from
8011
            $remaining = count($from) - $depth;
8012
            if ($remaining > 1) {
8013
                // add traversals up to first matching dir
8014
                $padLength = (count($relPath) + $remaining - 1) * -1;
8015
                $relPath = array_pad($relPath, $padLength, '..');
8016
                break;
8017
            } else {
8018
                $relPath[0] = './'.$relPath[0];
8019
            }
8020
        }
8021
    }
8022
8023
    return implode('/', $relPath);
8024
}
8025
8026
/**
8027
 * Unserialize content using Brummann\Polyfill\Unserialize.
8028
 *
8029
 * @param string $type
8030
 * @param string $serialized
8031
 *
8032
 * @return mixed
8033
 */
8034
function api_unserialize_content($type, $serialized, $ignoreErrors = false)
8035
{
8036
    switch ($type) {
8037
        case 'career':
8038
        case 'sequence_graph':
8039
            $allowedClasses = [
8040
                \Fhaculty\Graph\Graph::class,
8041
                \Fhaculty\Graph\Set\VerticesMap::class,
8042
                \Fhaculty\Graph\Set\Vertices::class,
8043
                \Fhaculty\Graph\Set\Edges::class,
8044
            ];
8045
            break;
8046
        case 'lp':
8047
            $allowedClasses = [
8048
                learnpath::class,
8049
                learnpathItem::class,
8050
                aicc::class,
8051
                aiccBlock::class,
8052
                aiccItem::class,
8053
                aiccObjective::class,
8054
                aiccResource::class,
8055
                scorm::class,
8056
                scormItem::class,
8057
                scormMetadata::class,
8058
                scormOrganization::class,
8059
                scormResource::class,
8060
                Link::class,
8061
                LpItem::class,
8062
            ];
8063
            break;
8064
        case 'course':
8065
            $allowedClasses = [
8066
                \Chamilo\CourseBundle\Component\CourseCopy\Course::class,
8067
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Announcement::class,
8068
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Attendance::class,
8069
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\CalendarEvent::class,
8070
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\CourseCopyLearnpath::class,
8071
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\CourseCopyTestCategory::class,
8072
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\CourseDescription::class,
8073
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\CourseSession::class,
8074
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Document::class,
8075
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Forum::class,
8076
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\ForumCategory::class,
8077
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\ForumPost::class,
8078
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\ForumTopic::class,
8079
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Glossary::class,
8080
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\GradeBookBackup::class,
8081
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Link::class,
8082
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\LinkCategory::class,
8083
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Quiz::class,
8084
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\QuizQuestion::class,
8085
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\QuizQuestionOption::class,
8086
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\ScormDocument::class,
8087
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Survey::class,
8088
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\SurveyInvitation::class,
8089
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\SurveyQuestion::class,
8090
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Thematic::class,
8091
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\ToolIntro::class,
8092
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Wiki::class,
8093
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Work::class,
8094
                stdClass::class,
8095
            ];
8096
            break;
8097
        case 'not_allowed_classes':
8098
        default:
8099
            $allowedClasses = false;
8100
    }
8101
8102
    if ($ignoreErrors) {
8103
        return @UnserializeApi::unserialize(
8104
            $serialized,
8105
            ['allowed_classes' => $allowedClasses]
8106
        );
8107
    }
8108
8109
    return UnserializeApi::unserialize(
8110
        $serialized,
8111
        ['allowed_classes' => $allowedClasses]
8112
    );
8113
}
8114
8115
/**
8116
 * @param string $template
8117
 *
8118
 * @return string
8119
 */
8120
function api_find_template($template)
8121
{
8122
    return Template::findTemplateFilePath($template);
8123
}
8124
8125
/**
8126
 * @return array
8127
 */
8128
function api_get_language_list_for_flag()
8129
{
8130
    $table = Database::get_main_table(TABLE_MAIN_LANGUAGE);
8131
    $sql = "SELECT english_name, isocode FROM $table
8132
            ORDER BY original_name ASC";
8133
    static $languages = [];
8134
    if (empty($languages)) {
8135
        $result = Database::query($sql);
8136
        while ($row = Database::fetch_array($result)) {
8137
            $languages[$row['english_name']] = $row['isocode'];
8138
        }
8139
        $languages['english'] = 'gb';
8140
    }
8141
8142
    return $languages;
8143
}
8144
8145
/**
8146
 * @param string $name
8147
 *
8148
 * @return ZipStream
8149
 */
8150
function api_create_zip($name)
8151
{
8152
    $zipStreamOptions = new Archive();
8153
    $zipStreamOptions->setSendHttpHeaders(true);
8154
    $zipStreamOptions->setContentDisposition('attachment');
8155
    $zipStreamOptions->setContentType('application/x-zip');
8156
8157
    return new ZipStream($name, $zipStreamOptions);
8158
}
8159
8160
/**
8161
 * @return string
8162
 */
8163
function api_get_language_translate_html()
8164
{
8165
    $translate = api_get_configuration_value('translate_html');
8166
8167
    if (!$translate) {
8168
        return '';
8169
    }
8170
8171
    $languageList = api_get_languages();
8172
    $hideAll = '';
8173
    foreach ($languageList['all'] as $language) {
8174
        $hideAll .= '
8175
        $("span:lang('.$language['isocode'].')").filter(
8176
            function(e, val) {
8177
                // Only find the spans if they have set the lang
8178
                if ($(this).attr("lang") == null) {
8179
                    return false;
8180
                }
8181
8182
                // Ignore ckeditor classes
8183
                return !this.className.match(/cke(.*)/);
8184
        }).hide();'."\n";
8185
    }
8186
8187
    $userInfo = api_get_user_info();
8188
    $languageId = api_get_language_id($userInfo['language']);
8189
    $languageInfo = api_get_language_info($languageId);
8190
    $isoCode = 'en';
8191
8192
    if (!empty($languageInfo)) {
8193
        $isoCode = $languageInfo['isocode'];
8194
    }
8195
8196
    return '
8197
            $(function() {
8198
                '.$hideAll.'
8199
                var defaultLanguageFromUser = "'.$isoCode.'";
8200
8201
                $("span:lang('.$isoCode.')").filter(
8202
                    function() {
8203
                        // Ignore ckeditor classes
8204
                        return !this.className.match(/cke(.*)/);
8205
                }).show();
8206
8207
                var defaultLanguage = "";
8208
                var langFromUserFound = false;
8209
8210
                $(this).find("span").filter(
8211
                    function() {
8212
                        // Ignore ckeditor classes
8213
                        return !this.className.match(/cke(.*)/);
8214
                }).each(function() {
8215
                    defaultLanguage = $(this).attr("lang");
8216
                    if (defaultLanguage) {
8217
                        $(this).before().next("br").remove();
8218
                        if (defaultLanguageFromUser == defaultLanguage) {
8219
                            langFromUserFound = true;
8220
                        }
8221
                    }
8222
                });
8223
8224
                // Show default language
8225
                if (langFromUserFound == false && defaultLanguage) {
8226
                    $("span:lang("+defaultLanguage+")").filter(
8227
                    function() {
8228
                            // Ignore ckeditor classes
8229
                            return !this.className.match(/cke(.*)/);
8230
                    }).show();
8231
                }
8232
            });
8233
    ';
8234
}
8235
8236
/**
8237
 * Filter a multi-language HTML string (for the multi-language HTML
8238
 * feature) into the given language (strip the rest).
8239
 *
8240
 * @param string $htmlString The HTML string to "translate". Usually <p><span lang="en">Some string</span></p><p><span lang="fr">Une chaîne</span></p>
8241
 * @param string $language   The language in which we want to get the
8242
 *
8243
 * @throws Exception
8244
 *
8245
 * @return string The filtered string in the given language, or the full string if no translated string was identified
8246
 */
8247
function api_get_filtered_multilingual_HTML_string($htmlString, $language = null)
8248
{
8249
    if (true != api_get_configuration_value('translate_html')) {
8250
        return $htmlString;
8251
    }
8252
    $userInfo = api_get_user_info();
8253
    $languageId = 0;
8254
    if (!empty($language)) {
8255
        $languageId = api_get_language_id($language);
8256
    } elseif (!empty($userInfo['language'])) {
8257
        $languageId = api_get_language_id($userInfo['language']);
8258
    }
8259
    $languageInfo = api_get_language_info($languageId);
8260
    $isoCode = 'en';
8261
8262
    if (!empty($languageInfo)) {
8263
        $isoCode = $languageInfo['isocode'];
8264
    }
8265
8266
    // Split HTML in the separate language strings
8267
    // Note: some strings might look like <p><span ..>...</span></p> but others might be like combine 2 <span> in 1 <p>
8268
    if (!preg_match('/<span.*?lang="(\w\w)">/is', $htmlString)) {
8269
        return $htmlString;
8270
    }
8271
    $matches = [];
8272
    preg_match_all('/<span.*?lang="(\w\w)">(.*?)<\/span>/is', $htmlString, $matches);
8273
    if (!empty($matches)) {
8274
        // matches[0] are the full string
8275
        // matches[1] are the languages
8276
        // matches[2] are the strings
8277
        foreach ($matches[1] as $id => $match) {
8278
            if ($match == $isoCode) {
8279
                return $matches[2][$id];
8280
            }
8281
        }
8282
        // Could find the pattern but could not find our language. Return the first language found.
8283
        return $matches[2][0];
8284
    }
8285
    // Could not find pattern. Just return the whole string. We shouldn't get here.
8286
    return $htmlString;
8287
}
8288