Passed
Push — master ( bb15d1...ce9f14 )
by Julito
09:50
created

api_detect_user_roles()   C

Complexity

Conditions 12
Paths 84

Size

Total Lines 56
Code Lines 28

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 12
eloc 28
nc 84
nop 3
dl 0
loc 56
rs 6.9666
c 0
b 0
f 0

3 Methods

Rating   Name   Duplication   Size   Complexity  
A api_set_more_memory_and_time_limits() 0 5 2
A api_get_js_simple() 0 3 1
A api_set_memory_limit() 0 15 5

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
use Chamilo\CoreBundle\Entity\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::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::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::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::OPEN_WORLD:
1027
                //Open - access allowed for the whole world - 3
1028
                $is_visible = true;
1029
                break;
1030
            case Course::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
    return $repo->find($userId);
1943
}
1944
1945
function api_get_current_user(): ?User
1946
{
1947
    $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

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

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