Passed
Push — master ( 3fcb32...49d6fc )
by Julito
09:27
created

api_get_tools_lists()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 45
Code Lines 40

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 40
nc 3
nop 1
dl 0
loc 45
rs 9.28
c 0
b 0
f 0
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
155
// CONSTANTS defining Chamilo interface sections
156
define('SECTION_CAMPUS', 'mycampus');
157
define('SECTION_COURSES', 'mycourses');
158
define('SECTION_CATALOG', 'catalog');
159
define('SECTION_MYPROFILE', 'myprofile');
160
define('SECTION_MYAGENDA', 'myagenda');
161
define('SECTION_COURSE_ADMIN', 'course_admin');
162
define('SECTION_PLATFORM_ADMIN', 'platform_admin');
163
define('SECTION_MYGRADEBOOK', 'mygradebook');
164
define('SECTION_TRACKING', 'session_my_space');
165
define('SECTION_SOCIAL', 'social-network');
166
define('SECTION_DASHBOARD', 'dashboard');
167
define('SECTION_REPORTS', 'reports');
168
define('SECTION_GLOBAL', 'global');
169
define('SECTION_INCLUDE', 'include');
170
define('SECTION_CUSTOMPAGE', 'custompage');
171
172
// CONSTANT name for local authentication source
173
define('PLATFORM_AUTH_SOURCE', 'platform');
174
define('CAS_AUTH_SOURCE', 'cas');
175
define('LDAP_AUTH_SOURCE', 'extldap');
176
177
// CONSTANT defining the default HotPotatoes files directory
178
define('DIR_HOTPOTATOES', '/HotPotatoes_files');
179
180
// event logs types
181
define('LOG_COURSE_DELETE', 'course_deleted');
182
define('LOG_COURSE_CREATE', 'course_created');
183
define('LOG_COURSE_SETTINGS_CHANGED', 'course_settings_changed');
184
185
// @todo replace 'soc_gr' with social_group
186
define('LOG_GROUP_PORTAL_CREATED', 'soc_gr_created');
187
define('LOG_GROUP_PORTAL_UPDATED', 'soc_gr_updated');
188
define('LOG_GROUP_PORTAL_DELETED', 'soc_gr_deleted');
189
define('LOG_GROUP_PORTAL_USER_DELETE_ALL', 'soc_gr_delete_users');
190
191
define('LOG_GROUP_PORTAL_ID', 'soc_gr_portal_id');
192
define('LOG_GROUP_PORTAL_REL_USER_ARRAY', 'soc_gr_user_array');
193
194
define('LOG_GROUP_PORTAL_USER_SUBSCRIBED', 'soc_gr_u_subs');
195
define('LOG_GROUP_PORTAL_USER_UNSUBSCRIBED', 'soc_gr_u_unsubs');
196
define('LOG_GROUP_PORTAL_USER_UPDATE_ROLE', 'soc_gr_update_role');
197
198
define('LOG_USER_DELETE', 'user_deleted');
199
define('LOG_USER_CREATE', 'user_created');
200
define('LOG_USER_UPDATE', 'user_updated');
201
define('LOG_USER_PASSWORD_UPDATE', 'user_password_updated');
202
define('LOG_USER_ENABLE', 'user_enable');
203
define('LOG_USER_DISABLE', 'user_disable');
204
define('LOG_USER_ANONYMIZE', 'user_anonymized');
205
define('LOG_USER_FIELD_CREATE', 'user_field_created');
206
define('LOG_USER_FIELD_DELETE', 'user_field_deleted');
207
define('LOG_SESSION_CREATE', 'session_created');
208
define('LOG_SESSION_DELETE', 'session_deleted');
209
define('LOG_SESSION_ADD_USER_COURSE', 'session_add_user_course');
210
define('LOG_SESSION_DELETE_USER_COURSE', 'session_delete_user_course');
211
define('LOG_SESSION_ADD_USER', 'session_add_user');
212
define('LOG_SESSION_DELETE_USER', 'session_delete_user');
213
define('LOG_SESSION_ADD_COURSE', 'session_add_course');
214
define('LOG_SESSION_DELETE_COURSE', 'session_delete_course');
215
define('LOG_SESSION_CATEGORY_CREATE', 'session_cat_created'); //changed in 1.9.8
216
define('LOG_SESSION_CATEGORY_DELETE', 'session_cat_deleted'); //changed in 1.9.8
217
define('LOG_CONFIGURATION_SETTINGS_CHANGE', 'settings_changed');
218
define('LOG_PLATFORM_LANGUAGE_CHANGE', 'platform_lng_changed'); //changed in 1.9.8
219
define('LOG_SUBSCRIBE_USER_TO_COURSE', 'user_subscribed');
220
define('LOG_UNSUBSCRIBE_USER_FROM_COURSE', 'user_unsubscribed');
221
define('LOG_ATTEMPTED_FORCED_LOGIN', 'attempted_forced_login');
222
define('LOG_PLUGIN_CHANGE', 'plugin_changed');
223
define('LOG_HOMEPAGE_CHANGED', 'homepage_changed');
224
define('LOG_PROMOTION_CREATE', 'promotion_created');
225
define('LOG_PROMOTION_DELETE', 'promotion_deleted');
226
define('LOG_CAREER_CREATE', 'career_created');
227
define('LOG_CAREER_DELETE', 'career_deleted');
228
define('LOG_USER_PERSONAL_DOC_DELETED', 'user_doc_deleted');
229
define('LOG_WIKI_ACCESS', 'wiki_page_view');
230
// All results from an exercise
231
define('LOG_EXERCISE_RESULT_DELETE', 'exe_result_deleted');
232
// Logs only the one attempt
233
define('LOG_EXERCISE_ATTEMPT_DELETE', 'exe_attempt_deleted');
234
define('LOG_LP_ATTEMPT_DELETE', 'lp_attempt_deleted');
235
define('LOG_QUESTION_RESULT_DELETE', 'qst_attempt_deleted');
236
define('LOG_QUESTION_SCORE_UPDATE', 'score_attempt_updated');
237
238
define('LOG_MY_FOLDER_CREATE', 'my_folder_created');
239
define('LOG_MY_FOLDER_CHANGE', 'my_folder_changed');
240
define('LOG_MY_FOLDER_DELETE', 'my_folder_deleted');
241
define('LOG_MY_FOLDER_COPY', 'my_folder_copied');
242
define('LOG_MY_FOLDER_CUT', 'my_folder_cut');
243
define('LOG_MY_FOLDER_PASTE', 'my_folder_pasted');
244
define('LOG_MY_FOLDER_UPLOAD', 'my_folder_uploaded');
245
246
// Event logs data types (max 20 chars)
247
define('LOG_COURSE_CODE', 'course_code');
248
define('LOG_COURSE_ID', 'course_id');
249
define('LOG_USER_ID', 'user_id');
250
define('LOG_USER_OBJECT', 'user_object');
251
define('LOG_USER_FIELD_VARIABLE', 'user_field_variable');
252
define('LOG_SESSION_ID', 'session_id');
253
254
define('LOG_QUESTION_ID', 'question_id');
255
define('LOG_SESSION_CATEGORY_ID', 'session_category_id');
256
define('LOG_CONFIGURATION_SETTINGS_CATEGORY', 'settings_category');
257
define('LOG_CONFIGURATION_SETTINGS_VARIABLE', 'settings_variable');
258
define('LOG_PLATFORM_LANGUAGE', 'default_platform_language');
259
define('LOG_PLUGIN_UPLOAD', 'plugin_upload');
260
define('LOG_PLUGIN_ENABLE', 'plugin_enable');
261
define('LOG_PLUGIN_SETTINGS_CHANGE', 'plugin_settings_change');
262
define('LOG_CAREER_ID', 'career_id');
263
define('LOG_PROMOTION_ID', 'promotion_id');
264
define('LOG_GRADEBOOK_LOCKED', 'gradebook_locked');
265
define('LOG_GRADEBOOK_UNLOCKED', 'gradebook_unlocked');
266
define('LOG_GRADEBOOK_ID', 'gradebook_id');
267
define('LOG_WIKI_PAGE_ID', 'wiki_page_id');
268
define('LOG_EXERCISE_ID', 'exercise_id');
269
define('LOG_EXERCISE_AND_USER_ID', 'exercise_and_user_id');
270
define('LOG_LP_ID', 'lp_id');
271
define('LOG_EXERCISE_ATTEMPT_QUESTION_ID', 'exercise_a_q_id');
272
define('LOG_EXERCISE_ATTEMPT', 'exe_id');
273
274
define('LOG_WORK_DIR_DELETE', 'work_dir_delete');
275
define('LOG_WORK_FILE_DELETE', 'work_file_delete');
276
define('LOG_WORK_DATA', 'work_data_array');
277
278
define('LOG_MY_FOLDER_PATH', 'path');
279
define('LOG_MY_FOLDER_NEW_PATH', 'new_path');
280
281
define('LOG_TERM_CONDITION_ACCEPTED', 'term_condition_accepted');
282
define('LOG_USER_CONFIRMED_EMAIL', 'user_confirmed_email');
283
define('LOG_USER_REMOVED_LEGAL_ACCEPT', 'user_removed_legal_accept');
284
285
define('LOG_USER_DELETE_ACCOUNT_REQUEST', 'user_delete_account_request');
286
287
define('LOG_QUESTION_CREATED', 'question_created');
288
define('LOG_QUESTION_UPDATED', 'question_updated');
289
define('LOG_QUESTION_DELETED', 'question_deleted');
290
define('LOG_QUESTION_REMOVED_FROM_QUIZ', 'question_removed_from_quiz');
291
292
define('LOG_SURVEY_ID', 'survey_id');
293
define('LOG_SURVEY_CREATED', 'survey_created');
294
define('LOG_SURVEY_DELETED', 'survey_deleted');
295
define('LOG_SURVEY_CLEAN_RESULTS', 'survey_clean_results');
296
define('USERNAME_PURIFIER', '/[^0-9A-Za-z_\.-]/');
297
298
//used when login_is_email setting is true
299
define('USERNAME_PURIFIER_MAIL', '/[^0-9A-Za-z_\.@]/');
300
define('USERNAME_PURIFIER_SHALLOW', '/\s/');
301
302
// This constant is a result of Windows OS detection, it has a boolean value:
303
// true whether the server runs on Windows OS, false otherwise.
304
define('IS_WINDOWS_OS', api_is_windows_os());
305
306
// iconv extension, for PHP5 on Windows it is installed by default.
307
define('ICONV_INSTALLED', function_exists('iconv'));
308
define('MBSTRING_INSTALLED', function_exists('mb_strlen')); // mbstring extension.
309
310
// Patterns for processing paths. Examples.
311
define('REPEATED_SLASHES_PURIFIER', '/\/{2,}/'); // $path = preg_replace(REPEATED_SLASHES_PURIFIER, '/', $path);
312
define('VALID_WEB_PATH', '/https?:\/\/[^\/]*(\/.*)?/i'); // $is_valid_path = preg_match(VALID_WEB_PATH, $path);
313
// $new_path = preg_replace(VALID_WEB_SERVER_BASE, $new_base, $path);
314
define('VALID_WEB_SERVER_BASE', '/https?:\/\/[^\/]*/i');
315
// Constants for api_get_path() and api_get_path_type(), etc. - registered path types.
316
// basic (leaf elements)
317
define('REL_CODE_PATH', 'REL_CODE_PATH');
318
define('REL_COURSE_PATH', 'REL_COURSE_PATH');
319
define('REL_HOME_PATH', 'REL_HOME_PATH');
320
321
// Constants for api_get_path() and api_get_path_type(), etc. - registered path types.
322
define('WEB_PATH', 'WEB_PATH');
323
define('SYS_PATH', 'SYS_PATH');
324
define('SYMFONY_SYS_PATH', 'SYMFONY_SYS_PATH');
325
//define('SYS_UPLOAD_PATH', 'SYS_UPLOAD_PATH');
326
//define('WEB_UPLOAD_PATH', 'WEB_UPLOAD_PATH');
327
328
define('REL_PATH', 'REL_PATH');
329
define('WEB_COURSE_PATH', 'WEB_COURSE_PATH');
330
define('WEB_CODE_PATH', 'WEB_CODE_PATH');
331
define('SYS_CODE_PATH', 'SYS_CODE_PATH');
332
define('SYS_LANG_PATH', 'SYS_LANG_PATH');
333
define('WEB_IMG_PATH', 'WEB_IMG_PATH');
334
define('WEB_CSS_PATH', 'WEB_CSS_PATH');
335
define('WEB_PUBLIC_PATH', 'WEB_PUBLIC_PATH');
336
define('SYS_CSS_PATH', 'SYS_CSS_PATH');
337
define('SYS_PLUGIN_PATH', 'SYS_PLUGIN_PATH');
338
define('WEB_PLUGIN_PATH', 'WEB_PLUGIN_PATH');
339
define('WEB_PLUGIN_ASSET_PATH', 'WEB_PLUGIN_ASSET_PATH');
340
define('SYS_ARCHIVE_PATH', 'SYS_ARCHIVE_PATH');
341
define('WEB_ARCHIVE_PATH', 'WEB_ARCHIVE_PATH');
342
define('LIBRARY_PATH', 'LIBRARY_PATH');
343
define('CONFIGURATION_PATH', 'CONFIGURATION_PATH');
344
define('WEB_LIBRARY_PATH', 'WEB_LIBRARY_PATH');
345
define('WEB_LIBRARY_JS_PATH', 'WEB_LIBRARY_JS_PATH');
346
define('WEB_AJAX_PATH', 'WEB_AJAX_PATH');
347
define('SYS_TEST_PATH', 'SYS_TEST_PATH');
348
define('SYS_TEMPLATE_PATH', 'SYS_TEMPLATE_PATH');
349
define('SYS_PUBLIC_PATH', 'SYS_PUBLIC_PATH');
350
define('SYS_FONTS_PATH', 'SYS_FONTS_PATH');
351
352
// Relations type with Course manager
353
define('COURSE_RELATION_TYPE_COURSE_MANAGER', 1);
354
define('SESSION_RELATION_TYPE_COURSE_MANAGER', 1);
355
356
// Relations type with Human resources manager
357
define('COURSE_RELATION_TYPE_RRHH', 1);
358
define('SESSION_RELATION_TYPE_RRHH', 1);
359
360
//User image sizes
361
define('USER_IMAGE_SIZE_ORIGINAL', 1);
362
define('USER_IMAGE_SIZE_BIG', 2);
363
define('USER_IMAGE_SIZE_MEDIUM', 3);
364
define('USER_IMAGE_SIZE_SMALL', 4);
365
366
// Relation type between users
367
define('USER_UNKNOWN', 0);
368
define('USER_RELATION_TYPE_UNKNOWN', 1);
369
define('USER_RELATION_TYPE_PARENT', 2); // should be deprecated is useless
370
define('USER_RELATION_TYPE_FRIEND', 3);
371
define('USER_RELATION_TYPE_GOODFRIEND', 4); // should be deprecated is useless
372
define('USER_RELATION_TYPE_ENEMY', 5); // should be deprecated is useless
373
define('USER_RELATION_TYPE_DELETED', 6);
374
define('USER_RELATION_TYPE_RRHH', 7);
375
define('USER_RELATION_TYPE_BOSS', 8);
376
define('USER_RELATION_TYPE_HRM_REQUEST', 9);
377
378
// Gradebook link constants
379
// Please do not change existing values, they are used in the database !
380
define('GRADEBOOK_ITEM_LIMIT', 1000);
381
382
define('LINK_EXERCISE', 1);
383
define('LINK_DROPBOX', 2);
384
define('LINK_STUDENTPUBLICATION', 3);
385
define('LINK_LEARNPATH', 4);
386
define('LINK_FORUM_THREAD', 5);
387
//define('LINK_WORK',6);
388
define('LINK_ATTENDANCE', 7);
389
define('LINK_SURVEY', 8);
390
define('LINK_HOTPOTATOES', 9);
391
392
// Score display types constants
393
define('SCORE_DIV', 1); // X / Y
394
define('SCORE_PERCENT', 2); // XX %
395
define('SCORE_DIV_PERCENT', 3); // X / Y (XX %)
396
define('SCORE_AVERAGE', 4); // XX %
397
define('SCORE_DECIMAL', 5); // 0.50  (X/Y)
398
define('SCORE_BAR', 6); // Uses the Display::bar_progress function
399
define('SCORE_SIMPLE', 7); // X
400
define('SCORE_IGNORE_SPLIT', 8); //  ??
401
define('SCORE_DIV_PERCENT_WITH_CUSTOM', 9); // X / Y (XX %) - Good!
402
define('SCORE_CUSTOM', 10); // Good!
403
define('SCORE_DIV_SIMPLE_WITH_CUSTOM', 11); // X - Good!
404
define('SCORE_DIV_SIMPLE_WITH_CUSTOM_LETTERS', 12); // X - Good!
405
define('SCORE_ONLY_SCORE', 13); // X - Good!
406
define('SCORE_NUMERIC', 14);
407
408
define('SCORE_BOTH', 1);
409
define('SCORE_ONLY_DEFAULT', 2);
410
define('SCORE_ONLY_CUSTOM', 3);
411
412
// From display.lib.php
413
414
define('MAX_LENGTH_BREADCRUMB', 100);
415
define('ICON_SIZE_ATOM', 8);
416
define('ICON_SIZE_TINY', 16);
417
define('ICON_SIZE_SMALL', 22);
418
define('ICON_SIZE_MEDIUM', 32);
419
define('ICON_SIZE_LARGE', 48);
420
define('ICON_SIZE_BIG', 64);
421
define('ICON_SIZE_HUGE', 128);
422
define('SHOW_TEXT_NEAR_ICONS', false);
423
424
// Session catalog
425
define('CATALOG_COURSES', 0);
426
define('CATALOG_SESSIONS', 1);
427
define('CATALOG_COURSES_SESSIONS', 2);
428
429
// Hook type events, pre-process and post-process.
430
// All means to be executed for both hook event types
431
define('HOOK_EVENT_TYPE_PRE', 0);
432
define('HOOK_EVENT_TYPE_POST', 1);
433
define('HOOK_EVENT_TYPE_ALL', 10);
434
435
// Group permissions
436
define('GROUP_PERMISSION_OPEN', '1');
437
define('GROUP_PERMISSION_CLOSED', '2');
438
439
// Group user permissions
440
define('GROUP_USER_PERMISSION_ADMIN', 1); // the admin of a group
441
define('GROUP_USER_PERMISSION_READER', 2); // a normal user
442
define('GROUP_USER_PERMISSION_PENDING_INVITATION', 3); // When an admin/moderator invites a user
443
define('GROUP_USER_PERMISSION_PENDING_INVITATION_SENT_BY_USER', 4); // an user joins a group
444
define('GROUP_USER_PERMISSION_MODERATOR', 5); // a moderator
445
define('GROUP_USER_PERMISSION_ANONYMOUS', 6); // an anonymous user
446
define('GROUP_USER_PERMISSION_HRM', 7); // a human resources manager
447
448
define('GROUP_IMAGE_SIZE_ORIGINAL', 1);
449
define('GROUP_IMAGE_SIZE_BIG', 2);
450
define('GROUP_IMAGE_SIZE_MEDIUM', 3);
451
define('GROUP_IMAGE_SIZE_SMALL', 4);
452
define('GROUP_TITLE_LENGTH', 50);
453
454
// Exercise
455
// @todo move into a class
456
define('ALL_ON_ONE_PAGE', 1);
457
define('ONE_PER_PAGE', 2);
458
459
define('EXERCISE_FEEDBACK_TYPE_END', 0); //Feedback 		 - show score and expected answers
460
define('EXERCISE_FEEDBACK_TYPE_DIRECT', 1); //DirectFeedback - Do not show score nor answers
461
define('EXERCISE_FEEDBACK_TYPE_EXAM', 2); // NoFeedback 	 - Show score only
462
define('EXERCISE_FEEDBACK_TYPE_POPUP', 3); // Popup BT#15827
463
464
define('RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS', 0); //show score and expected answers
465
define('RESULT_DISABLE_NO_SCORE_AND_EXPECTED_ANSWERS', 1); //Do not show score nor answers
466
define('RESULT_DISABLE_SHOW_SCORE_ONLY', 2); //Show score only
467
define('RESULT_DISABLE_SHOW_FINAL_SCORE_ONLY_WITH_CATEGORIES', 3); //Show final score only with categories
468
define('RESULT_DISABLE_SHOW_SCORE_ATTEMPT_SHOW_ANSWERS_LAST_ATTEMPT', 4);
469
define('RESULT_DISABLE_DONT_SHOW_SCORE_ONLY_IF_USER_FINISHES_ATTEMPTS_SHOW_ALWAYS_FEEDBACK', 5);
470
define('RESULT_DISABLE_RANKING', 6);
471
define('RESULT_DISABLE_SHOW_ONLY_IN_CORRECT_ANSWER', 7);
472
define('RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS_AND_RANKING', 8);
473
define('RESULT_DISABLE_RADAR', 9);
474
define('RESULT_DISABLE_SHOW_SCORE_ATTEMPT_SHOW_ANSWERS_LAST_ATTEMPT_NO_FEEDBACK', 10);
475
476
define('EXERCISE_MAX_NAME_SIZE', 80);
477
478
// Question types (edit next array as well when adding values)
479
// @todo move into a class
480
define('UNIQUE_ANSWER', 1);
481
define('MULTIPLE_ANSWER', 2);
482
define('FILL_IN_BLANKS', 3);
483
define('MATCHING', 4);
484
define('FREE_ANSWER', 5);
485
define('HOT_SPOT', 6);
486
define('HOT_SPOT_ORDER', 7);
487
define('HOT_SPOT_DELINEATION', 8);
488
define('MULTIPLE_ANSWER_COMBINATION', 9);
489
define('UNIQUE_ANSWER_NO_OPTION', 10);
490
define('MULTIPLE_ANSWER_TRUE_FALSE', 11);
491
define('MULTIPLE_ANSWER_COMBINATION_TRUE_FALSE', 12);
492
define('ORAL_EXPRESSION', 13);
493
define('GLOBAL_MULTIPLE_ANSWER', 14);
494
define('MEDIA_QUESTION', 15);
495
define('CALCULATED_ANSWER', 16);
496
define('UNIQUE_ANSWER_IMAGE', 17);
497
define('DRAGGABLE', 18);
498
define('MATCHING_DRAGGABLE', 19);
499
define('ANNOTATION', 20);
500
define('READING_COMPREHENSION', 21);
501
define('MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY', 22);
502
503
define('EXERCISE_CATEGORY_RANDOM_SHUFFLED', 1);
504
define('EXERCISE_CATEGORY_RANDOM_ORDERED', 2);
505
define('EXERCISE_CATEGORY_RANDOM_DISABLED', 0);
506
507
// Question selection type
508
define('EX_Q_SELECTION_ORDERED', 1);
509
define('EX_Q_SELECTION_RANDOM', 2);
510
define('EX_Q_SELECTION_CATEGORIES_ORDERED_QUESTIONS_ORDERED', 3);
511
define('EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_ORDERED', 4);
512
define('EX_Q_SELECTION_CATEGORIES_ORDERED_QUESTIONS_RANDOM', 5);
513
define('EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_RANDOM', 6);
514
define('EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_ORDERED_NO_GROUPED', 7);
515
define('EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_RANDOM_NO_GROUPED', 8);
516
define('EX_Q_SELECTION_CATEGORIES_ORDERED_BY_PARENT_QUESTIONS_ORDERED', 9);
517
define('EX_Q_SELECTION_CATEGORIES_ORDERED_BY_PARENT_QUESTIONS_RANDOM', 10);
518
519
// Used to save the skill_rel_item table
520
define('ITEM_TYPE_EXERCISE', 1);
521
define('ITEM_TYPE_HOTPOTATOES', 2);
522
define('ITEM_TYPE_LINK', 3);
523
define('ITEM_TYPE_LEARNPATH', 4);
524
define('ITEM_TYPE_GRADEBOOK', 5);
525
define('ITEM_TYPE_STUDENT_PUBLICATION', 6);
526
//define('ITEM_TYPE_FORUM', 7);
527
define('ITEM_TYPE_ATTENDANCE', 8);
528
define('ITEM_TYPE_SURVEY', 9);
529
define('ITEM_TYPE_FORUM_THREAD', 10);
530
531
// Course description blocks.
532
define('ADD_BLOCK', 8);
533
534
// one big string with all question types, for the validator in pear/HTML/QuickForm/Rule/QuestionType
535
define(
536
    'QUESTION_TYPES',
537
    UNIQUE_ANSWER.':'.
538
    MULTIPLE_ANSWER.':'.
539
    FILL_IN_BLANKS.':'.
540
    MATCHING.':'.
541
    FREE_ANSWER.':'.
542
    HOT_SPOT.':'.
543
    HOT_SPOT_ORDER.':'.
544
    HOT_SPOT_DELINEATION.':'.
545
    MULTIPLE_ANSWER_COMBINATION.':'.
546
    UNIQUE_ANSWER_NO_OPTION.':'.
547
    MULTIPLE_ANSWER_TRUE_FALSE.':'.
548
    MULTIPLE_ANSWER_COMBINATION_TRUE_FALSE.':'.
549
    ORAL_EXPRESSION.':'.
550
    GLOBAL_MULTIPLE_ANSWER.':'.
551
    MEDIA_QUESTION.':'.
552
    CALCULATED_ANSWER.':'.
553
    UNIQUE_ANSWER_IMAGE.':'.
554
    DRAGGABLE.':'.
555
    MATCHING_DRAGGABLE.':'.
556
    MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY.':'.
557
    ANNOTATION
558
);
559
560
//Some alias used in the QTI exports
561
define('MCUA', 1);
562
define('TF', 1);
563
define('MCMA', 2);
564
define('FIB', 3);
565
566
// Skills
567
define('SKILL_TYPE_REQUIREMENT', 'required');
568
define('SKILL_TYPE_ACQUIRED', 'acquired');
569
define('SKILL_TYPE_BOTH', 'both');
570
571
// Message
572
define('MESSAGE_STATUS_NEW', 0);
573
define('MESSAGE_STATUS_UNREAD', 1);
574
//2 ??
575
define('MESSAGE_STATUS_DELETED', 3);
576
define('MESSAGE_STATUS_OUTBOX', 4);
577
define('MESSAGE_STATUS_INVITATION_PENDING', 5);
578
define('MESSAGE_STATUS_INVITATION_ACCEPTED', 6);
579
define('MESSAGE_STATUS_INVITATION_DENIED', 7);
580
define('MESSAGE_STATUS_WALL', 8);
581
define('MESSAGE_STATUS_WALL_DELETE', 9);
582
define('MESSAGE_STATUS_WALL_POST', 10);
583
define('MESSAGE_STATUS_CONVERSATION', 11);
584
define('MESSAGE_STATUS_FORUM', 12);
585
define('MESSAGE_STATUS_PROMOTED', 13);
586
587
// Images
588
define('IMAGE_WALL_SMALL_SIZE', 200);
589
define('IMAGE_WALL_MEDIUM_SIZE', 500);
590
define('IMAGE_WALL_BIG_SIZE', 2000);
591
define('IMAGE_WALL_SMALL', 'small');
592
define('IMAGE_WALL_MEDIUM', 'medium');
593
define('IMAGE_WALL_BIG', 'big');
594
595
// Social PLUGIN PLACES
596
define('SOCIAL_LEFT_PLUGIN', 1);
597
define('SOCIAL_CENTER_PLUGIN', 2);
598
define('SOCIAL_RIGHT_PLUGIN', 3);
599
define('CUT_GROUP_NAME', 50);
600
601
/**
602
 * FormValidator Filter.
603
 */
604
define('NO_HTML', 1);
605
define('STUDENT_HTML', 2);
606
define('TEACHER_HTML', 3);
607
define('STUDENT_HTML_FULLPAGE', 4);
608
define('TEACHER_HTML_FULLPAGE', 5);
609
610
// Timeline
611
define('TIMELINE_STATUS_ACTIVE', '1');
612
define('TIMELINE_STATUS_INACTIVE', '2');
613
614
// Event email template class
615
define('EVENT_EMAIL_TEMPLATE_ACTIVE', 1);
616
define('EVENT_EMAIL_TEMPLATE_INACTIVE', 0);
617
618
// Course home
619
define('SHORTCUTS_HORIZONTAL', 0);
620
define('SHORTCUTS_VERTICAL', 1);
621
622
// Image class
623
define('IMAGE_PROCESSOR', 'gd'); // 'imagick' or 'gd' strings
624
625
// Course copy
626
define('FILE_SKIP', 1);
627
define('FILE_RENAME', 2);
628
define('FILE_OVERWRITE', 3);
629
define('UTF8_CONVERT', false); //false by default
630
631
define('DOCUMENT', 'file');
632
define('FOLDER', 'folder');
633
634
define('RESOURCE_ASSET', 'asset');
635
define('RESOURCE_DOCUMENT', 'document');
636
define('RESOURCE_GLOSSARY', 'glossary');
637
define('RESOURCE_EVENT', 'calendar_event');
638
define('RESOURCE_LINK', 'link');
639
define('RESOURCE_COURSEDESCRIPTION', 'course_description');
640
define('RESOURCE_LEARNPATH', 'learnpath');
641
define('RESOURCE_LEARNPATH_CATEGORY', 'learnpath_category');
642
define('RESOURCE_ANNOUNCEMENT', 'announcement');
643
define('RESOURCE_FORUM', 'forum');
644
define('RESOURCE_FORUMTOPIC', 'thread');
645
define('RESOURCE_FORUMPOST', 'post');
646
define('RESOURCE_QUIZ', 'quiz');
647
define('RESOURCE_TEST_CATEGORY', 'test_category');
648
define('RESOURCE_QUIZQUESTION', 'Exercise_Question');
649
define('RESOURCE_TOOL_INTRO', 'Tool introduction');
650
define('RESOURCE_LINKCATEGORY', 'Link_Category');
651
define('RESOURCE_FORUMCATEGORY', 'Forum_Category');
652
define('RESOURCE_SCORM', 'Scorm');
653
define('RESOURCE_SURVEY', 'survey');
654
define('RESOURCE_SURVEYQUESTION', 'survey_question');
655
define('RESOURCE_SURVEYINVITATION', 'survey_invitation');
656
define('RESOURCE_WIKI', 'wiki');
657
define('RESOURCE_THEMATIC', 'thematic');
658
define('RESOURCE_ATTENDANCE', 'attendance');
659
define('RESOURCE_WORK', 'work');
660
define('RESOURCE_SESSION_COURSE', 'session_course');
661
define('RESOURCE_GRADEBOOK', 'gradebook');
662
define('ADD_THEMATIC_PLAN', 6);
663
664
// Max online users to show per page (whoisonline)
665
define('MAX_ONLINE_USERS', 12);
666
667
// Number of characters maximum to show in preview of course blog posts
668
define('BLOG_MAX_PREVIEW_CHARS', 800);
669
// HTML string to replace with a 'Read more...' link
670
define('BLOG_PAGE_BREAK', '<div style="page-break-after: always"><span style="display: none;">&nbsp;</span></div>');
671
672
// Make sure the CHAMILO_LOAD_WYSIWYG constant is defined
673
// To remove CKeditor libs from HTML, set this constant to true before loading
674
if (!defined('CHAMILO_LOAD_WYSIWYG')) {
675
    define('CHAMILO_LOAD_WYSIWYG', true);
676
}
677
678
/* Constants for course home */
679
define('TOOL_PUBLIC', 'Public');
680
define('TOOL_PUBLIC_BUT_HIDDEN', 'PublicButHide');
681
define('TOOL_COURSE_ADMIN', 'courseAdmin');
682
define('TOOL_PLATFORM_ADMIN', 'platformAdmin');
683
define('TOOL_AUTHORING', 'toolauthoring');
684
define('TOOL_INTERACTION', 'toolinteraction');
685
define('TOOL_COURSE_PLUGIN', 'toolcourseplugin'); //all plugins that can be enabled in courses
686
define('TOOL_ADMIN', 'tooladmin');
687
define('TOOL_ADMIN_PLATFORM', 'tooladminplatform');
688
define('TOOL_DRH', 'tool_drh');
689
define('TOOL_STUDENT_VIEW', 'toolstudentview');
690
define('TOOL_ADMIN_VISIBLE', 'tooladminvisible');
691
692
// Search settings (from main/inc/lib/search/IndexableChunk.class.php )
693
// some constants to avoid serialize string keys on serialized data array
694
define('SE_COURSE_ID', 0);
695
define('SE_TOOL_ID', 1);
696
define('SE_DATA', 2);
697
define('SE_USER', 3);
698
699
// in some cases we need top differenciate xapian documents of the same tool
700
define('SE_DOCTYPE_EXERCISE_EXERCISE', 0);
701
define('SE_DOCTYPE_EXERCISE_QUESTION', 1);
702
703
// xapian prefixes
704
define('XAPIAN_PREFIX_COURSEID', 'C');
705
define('XAPIAN_PREFIX_TOOLID', 'O');
706
707
/**
708
 * Returns a path to a certain resource within the Chamilo area, specifyed through a parameter.
709
 * Also, this function provides conversion between path types, in this case the input path points inside the Chamilo area too.
710
 *
711
 * See $_configuration['course_folder'] in the configuration.php to alter the WEB_COURSE_PATH and SYS_COURSE_PATH parameters.
712
713
 *
714
 * @param string $path (optional)   A path which type is to be converted. Also, it may be a defined constant for a path.
715
 *                     This parameter has meaning when $type parameter has one of the following values: TO_WEB, TO_SYS, TO_REL. Otherwise it is ignored.
716
 *
717
 * @return string the requested path or the converted path
718
 *
719
 * Notes about the current behaviour model:
720
 * 1. Windows back-slashes are converted to slashes in the result.
721
 * 2. A semi-absolute web-path is detected by its leading slash. On Linux systems, absolute system paths start with
722
 * a slash too, so an additional check about presence of leading system server base is implemented. For example, the function is
723
 * able to distinguish type difference between /var/www/chamilo/courses/ (SYS) and /chamilo/courses/ (REL).
724
 * 3. The function api_get_path() returns only these three types of paths, which in some sense are absolute. The function has
725
 * no a mechanism for processing relative web/system paths, such as: lesson01.html, ./lesson01.html, ../css/my_styles.css.
726
 * It has not been identified as needed yet.
727
 * 4. Also, resolving the meta-symbols "." and ".." within paths has not been implemented, it is to be identified as needed.
728
 *
729
 * For examples go to: *
730
 * See main/admin/system_status.php?section=paths
731
 *
732
 * Vchamilo changes : allow using an alternate configuration
733
 * to get vchamilo  instance paths
734
 */
735
function api_get_path($path = '', $configuration = [])
736
{
737
    global $paths;
738
739
    // get proper configuration data if exists
740
    global $_configuration;
741
742
    $emptyConfigurationParam = false;
743
    if (empty($configuration)) {
744
        $configuration = (array) $_configuration;
745
        $emptyConfigurationParam = true;
746
    }
747
748
    $root_sys = Container::getProjectDir();
749
750
    $root_web = '';
751
    // If no $root_web has been set so far *and* no custom config has been passed to the function
752
    // then re-use the previously-calculated (run-specific) $root_web and skip this complex calculation
753
    /*
754
    if (empty($root_web) || $emptyConfigurationParam === false || empty($configuration)) {
755
        // Resolve master hostname.
756
        if (!empty($configuration) && array_key_exists('root_web', $configuration)) {
757
            $root_web = $configuration['root_web'];
758
        } else {
759
            $root_web = '';
760
            // Try guess it from server.
761
            if (defined('SYSTEM_INSTALLATION') && SYSTEM_INSTALLATION) {
762
                if (($pos = strpos(($requested_page_rel = api_get_self()), 'main/install')) !== false) {
763
                    $root_rel = substr($requested_page_rel, 0, $pos);
764
                    // See http://www.mediawiki.org/wiki/Manual:$wgServer
765
                    $server_protocol = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https' : 'http';
766
                    $server_name =
767
                        isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME']
768
                            : (isset($_SERVER['HOSTNAME']) ? $_SERVER['HOSTNAME']
769
                            : (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST']
770
                                : (isset($_SERVER['SERVER_ADDR']) ? $_SERVER['SERVER_ADDR']
771
                                    : 'localhost')));
772
                    if (isset($_SERVER['SERVER_PORT']) && !strpos($server_name, ':')
773
                        && (($server_protocol == 'http'
774
                                && $_SERVER['SERVER_PORT'] != 80) || ($server_protocol == 'https' && $_SERVER['SERVER_PORT'] != 443))
775
                    ) {
776
                        $server_name .= ":".$_SERVER['SERVER_PORT'];
777
                    }
778
                    $root_web = $server_protocol.'://'.$server_name.$root_rel;
779
                    $root_sys = str_replace('\\', '/', realpath(__DIR__.'/../../../')).'/';
780
                }
781
                // Here we give up, so we don't touch anything.
782
            }
783
        }
784
    }*/
785
    if (isset(Container::$container)) {
786
        $root_web = Container::$container->get('router')->generate(
787
            'home',
788
            [],
789
            UrlGeneratorInterface::ABSOLUTE_URL
790
        );
791
    }
792
793
    if (isset($configuration['multiple_access_urls']) &&
794
        $configuration['multiple_access_urls']
795
    ) {
796
        // To avoid that the api_get_access_url() function fails since global.inc.php also calls the main_api.lib.php
797
        if (isset($configuration['access_url']) && !empty($configuration['access_url'])) {
798
            // We look into the DB the function api_get_access_url
799
            $urlInfo = api_get_access_url($configuration['access_url']);
800
            // Avoid default value
801
            $defaultValues = ['http://localhost/', 'https://localhost/'];
802
            if (!empty($urlInfo['url']) && !in_array($urlInfo['url'], $defaultValues)) {
803
                $root_web = 1 == $urlInfo['active'] ? $urlInfo['url'] : $configuration['root_web'];
804
            }
805
        }
806
    }
807
808
    $paths = [
809
        WEB_PATH => $root_web,
810
        SYMFONY_SYS_PATH => $root_sys,
811
        SYS_PATH => $root_sys.'public/',
812
        REL_PATH => '',
813
        CONFIGURATION_PATH => 'app/config/',
814
        LIBRARY_PATH => $root_sys.'public/main/inc/lib/',
815
816
        REL_COURSE_PATH => '',
817
        REL_CODE_PATH => '/main/',
818
819
        SYS_CODE_PATH => $root_sys.'public/main/',
820
        SYS_CSS_PATH => $root_sys.'public/build/css/',
821
        SYS_PLUGIN_PATH => $root_sys.'public/plugin/',
822
        SYS_ARCHIVE_PATH => $root_sys.'var/cache/',
823
       // SYS_UPLOAD_PATH => 'var/upload/',
824
        SYS_TEST_PATH => $root_sys.'tests/',
825
        SYS_TEMPLATE_PATH => $root_sys.'public/main/template/',
826
        SYS_PUBLIC_PATH => $root_sys.'public/',
827
        SYS_FONTS_PATH => $root_sys.'public/fonts/',
828
829
        WEB_CODE_PATH => $root_web.'main/',
830
        WEB_PLUGIN_ASSET_PATH => $root_web.'plugins/',
831
        WEB_COURSE_PATH => $root_web.'course/',
832
        WEB_IMG_PATH => $root_web.'img/',
833
        WEB_CSS_PATH => $root_web.'build/css/',
834
        WEB_AJAX_PATH => $root_web.'main/inc/ajax/',
835
        WEB_LIBRARY_PATH => $root_web.'main/inc/lib/',
836
        WEB_LIBRARY_JS_PATH => $root_web.'main/inc/lib/javascript/',
837
        WEB_PLUGIN_PATH => $root_web.'plugin/',
838
       // WEB_ARCHIVE_PATH => 'var/cache/',
839
        //WEB_UPLOAD_PATH => 'var/upload/',
840
        WEB_PUBLIC_PATH => $root_web,
841
    ];
842
843
    $root_rel = '';
844
845
    // Dealing with trailing slashes.
846
    $rootWebWithSlash = api_add_trailing_slash($root_web);
847
    $root_sys = api_add_trailing_slash($root_sys);
848
    $root_rel = api_add_trailing_slash($root_rel);
849
850
    global $virtualChamilo;
851
    if (!empty($virtualChamilo)) {
852
        $paths[SYS_ARCHIVE_PATH] = api_add_trailing_slash($virtualChamilo[SYS_ARCHIVE_PATH]);
853
        $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...
854
        //$paths[$root_web][WEB_UPLOAD_PATH] = api_add_trailing_slash($virtualChamilo[WEB_UPLOAD_PATH]);
855
        $paths[WEB_ARCHIVE_PATH] = api_add_trailing_slash($virtualChamilo[WEB_ARCHIVE_PATH]);
856
        //$paths[$root_web][WEB_COURSE_PATH] = api_add_trailing_slash($virtualChamilo[WEB_COURSE_PATH]);
857
858
        // WEB_UPLOAD_PATH should be handle by apache htaccess in the vhost
859
860
        // RewriteEngine On
861
        // RewriteRule /app/upload/(.*)$ http://localhost/other/upload/my-chamilo111-net/$1 [QSA,L]
862
863
        //$paths[$root_web][WEB_UPLOAD_PATH] = api_add_trailing_slash($virtualChamilo[WEB_UPLOAD_PATH]);
864
        //$paths[$root_web][REL_PATH] = $virtualChamilo[REL_PATH];
865
        //$paths[$root_web][REL_COURSE_PATH] = $virtualChamilo[REL_COURSE_PATH];
866
    }
867
868
    $path = trim($path);
869
870
    // Retrieving a common-purpose path.
871
    if (isset($paths[$path])) {
872
        return $paths[$path];
873
    }
874
875
    return false;
876
}
877
878
/**
879
 * Adds to a given path a trailing slash if it is necessary (adds "/" character at the end of the string).
880
 *
881
 * @param string $path the input path
882
 *
883
 * @return string returns the modified path
884
 */
885
function api_add_trailing_slash($path)
886
{
887
    return '/' == substr($path, -1) ? $path : $path.'/';
888
}
889
890
/**
891
 * Removes from a given path the trailing slash if it is necessary (removes "/" character from the end of the string).
892
 *
893
 * @param string $path the input path
894
 *
895
 * @return string returns the modified path
896
 */
897
function api_remove_trailing_slash($path)
898
{
899
    return '/' == substr($path, -1) ? substr($path, 0, -1) : $path;
900
}
901
902
/**
903
 * Checks the RFC 3986 syntax of a given URL.
904
 *
905
 * @param string $url      the URL to be checked
906
 * @param bool   $absolute whether the URL is absolute (beginning with a scheme such as "http:")
907
 *
908
 * @return string|false Returns the URL if it is valid, FALSE otherwise.
909
 *                      This function is an adaptation from the function valid_url(), Drupal CMS.
910
 *
911
 * @see http://drupal.org
912
 * Note: The built-in function filter_var($urs, FILTER_VALIDATE_URL) has a bug for some versions of PHP.
913
 * @see http://bugs.php.net/51192
914
 */
915
function api_valid_url($url, $absolute = false)
916
{
917
    if ($absolute) {
918
        if (preg_match("
919
            /^                                                      # Start at the beginning of the text
920
            (?:ftp|https?|feed):\/\/                                # Look for ftp, http, https or feed schemes
921
            (?:                                                     # Userinfo (optional) which is typically
922
                (?:(?:[\w\.\-\+!$&'\(\)*\+,;=]|%[0-9a-f]{2})+:)*    # a username or a username and password
923
                (?:[\w\.\-\+%!$&'\(\)*\+,;=]|%[0-9a-f]{2})+@        # combination
924
            )?
925
            (?:
926
                (?:[a-z0-9\-\.]|%[0-9a-f]{2})+                      # A domain name or a IPv4 address
927
                |(?:\[(?:[0-9a-f]{0,4}:)*(?:[0-9a-f]{0,4})\])       # or a well formed IPv6 address
928
            )
929
            (?::[0-9]+)?                                            # Server port number (optional)
930
            (?:[\/|\?]
931
                (?:[\w#!:\.\?\+=&@$'~*,;\/\(\)\[\]\-]|%[0-9a-f]{2}) # The path and query (optional)
932
            *)?
933
            $/xi", $url)) {
934
            return $url;
935
        }
936
937
        return false;
938
    } else {
939
        return preg_match("/^(?:[\w#!:\.\?\+=&@$'~*,;\/\(\)\[\]\-]|%[0-9a-f]{2})+$/i", $url) ? $url : false;
940
    }
941
}
942
943
/**
944
 * Checks whether a given string looks roughly like an email address.
945
 *
946
 * @param string $address the e-mail address to be checked
947
 *
948
 * @return mixed returns the e-mail if it is valid, FALSE otherwise
949
 */
950
function api_valid_email($address)
951
{
952
    return filter_var($address, FILTER_VALIDATE_EMAIL);
953
}
954
955
/* PROTECTION FUNCTIONS
956
   Use these functions to protect your scripts. */
957
958
/**
959
 * Function used to protect a course script.
960
 * The function blocks access when
961
 * - there is no $_SESSION["_course"] defined; or
962
 * - $is_allowed_in_course is set to false (this depends on the course
963
 * visibility and user status).
964
 *
965
 * This is only the first proposal, test and improve!
966
 *
967
 * @param bool Option to print headers when displaying error message. Default: false
968
 * @param bool whether session admins should be allowed or not
969
 * @param string $checkTool check if tool is available for users (user, group)
970
 *
971
 * @return bool True if the user has access to the current course or is out of a course context, false otherwise
972
 *
973
 * @todo replace global variable
974
 *
975
 * @author Roan Embrechts
976
 */
977
function api_protect_course_script($print_headers = false, $allow_session_admins = false, $checkTool = '')
978
{
979
    $course_info = api_get_course_info();
980
    if (empty($course_info)) {
981
        api_not_allowed($print_headers);
982
983
        return false;
984
    }
985
986
    if (api_is_drh()) {
987
        return true;
988
    }
989
990
    // Session admin has access to course
991
    $sessionAccess = api_get_configuration_value('session_admins_access_all_content');
992
    if ($sessionAccess) {
993
        $allow_session_admins = true;
994
    }
995
996
    if (api_is_platform_admin($allow_session_admins)) {
997
        return true;
998
    }
999
1000
    $isAllowedInCourse = api_is_allowed_in_course();
1001
    $is_visible = false;
1002
    if (isset($course_info) && isset($course_info['visibility'])) {
1003
        switch ($course_info['visibility']) {
1004
            default:
1005
            case COURSE_VISIBILITY_CLOSED:
1006
                // Completely closed: the course is only accessible to the teachers. - 0
1007
                if ($isAllowedInCourse && api_get_user_id() && !api_is_anonymous()) {
1008
                    $is_visible = true;
1009
                }
1010
                break;
1011
            case COURSE_VISIBILITY_REGISTERED:
1012
                // Private - access authorized to course members only - 1
1013
                if ($isAllowedInCourse && api_get_user_id() && !api_is_anonymous()) {
1014
                    $is_visible = true;
1015
                }
1016
                break;
1017
            case COURSE_VISIBILITY_OPEN_PLATFORM:
1018
                // Open - access allowed for users registered on the platform - 2
1019
                if ($isAllowedInCourse && api_get_user_id() && !api_is_anonymous()) {
1020
                    $is_visible = true;
1021
                }
1022
                break;
1023
            case COURSE_VISIBILITY_OPEN_WORLD:
1024
                //Open - access allowed for the whole world - 3
1025
                $is_visible = true;
1026
                break;
1027
            case COURSE_VISIBILITY_HIDDEN:
1028
                //Completely closed: the course is only accessible to the teachers. - 0
1029
                if (api_is_platform_admin()) {
1030
                    $is_visible = true;
1031
                }
1032
                break;
1033
        }
1034
1035
        //If password is set and user is not registered to the course then the course is not visible
1036
        if (false === $isAllowedInCourse &&
1037
            isset($course_info['registration_code']) &&
1038
            !empty($course_info['registration_code'])
1039
        ) {
1040
            $is_visible = false;
1041
        }
1042
    }
1043
1044
    if (!empty($checkTool)) {
1045
        if (!api_is_allowed_to_edit(true, true, true)) {
1046
            $toolInfo = api_get_tool_information_by_name($checkTool);
1047
            if (!empty($toolInfo) && isset($toolInfo['visibility']) && 0 == $toolInfo['visibility']) {
1048
                api_not_allowed(true);
1049
1050
                return false;
1051
            }
1052
        }
1053
    }
1054
1055
    // Check session visibility
1056
    $session_id = api_get_session_id();
1057
1058
    if (!empty($session_id)) {
1059
        // $isAllowedInCourse was set in local.inc.php
1060
        if (!$isAllowedInCourse) {
1061
            $is_visible = false;
1062
        }
1063
    }
1064
1065
    if (!$is_visible) {
1066
        api_not_allowed($print_headers);
1067
1068
        return false;
1069
    }
1070
1071
    if ($is_visible && 'true' === api_get_plugin_setting('positioning', 'tool_enable')) {
1072
        $plugin = Positioning::create();
1073
        $block = $plugin->get('block_course_if_initial_exercise_not_attempted');
1074
        if ('true' === $block) {
1075
            $currentPath = $_SERVER['PHP_SELF'];
1076
            // Allowed only this course paths.
1077
            $paths = [
1078
                '/plugin/positioning/start.php',
1079
                '/plugin/positioning/start_student.php',
1080
                '/main/course_home/course_home.php',
1081
                '/main/exercise/overview.php',
1082
            ];
1083
1084
            if (!in_array($currentPath, $paths, true)) {
1085
                // Check if entering an exercise.
1086
                // @todo remove global $current_course_tool
1087
                /*global $current_course_tool;
1088
                if ('quiz' !== $current_course_tool) {
1089
                    $initialData = $plugin->getInitialExercise($course_info['real_id'], $session_id);
1090
                    if ($initialData && isset($initialData['exercise_id'])) {
1091
                        $results = Event::getExerciseResultsByUser(
1092
                            api_get_user_id(),
1093
                            $initialData['exercise_id'],
1094
                            $course_info['real_id'],
1095
                            $session_id
1096
                        );
1097
                        if (empty($results)) {
1098
                            api_not_allowed($print_headers);
1099
1100
                            return false;
1101
                        }
1102
                    }
1103
                }*/
1104
            }
1105
        }
1106
    }
1107
1108
    api_block_inactive_user();
1109
1110
    return true;
1111
}
1112
1113
/**
1114
 * Function used to protect an admin script.
1115
 *
1116
 * The function blocks access when the user has no platform admin rights
1117
 * with an error message printed on default output
1118
 *
1119
 * @param bool Whether to allow session admins as well
1120
 * @param bool Whether to allow HR directors as well
1121
 * @param string An optional message (already passed through get_lang)
1122
 *
1123
 * @return bool True if user is allowed, false otherwise.
1124
 *              The function also outputs an error message in case not allowed
1125
 *
1126
 * @author Roan Embrechts (original author)
1127
 */
1128
function api_protect_admin_script($allow_sessions_admins = false, $allow_drh = false, $message = null)
1129
{
1130
    if (!api_is_platform_admin($allow_sessions_admins, $allow_drh)) {
1131
        api_not_allowed(true, $message);
1132
1133
        return false;
1134
    }
1135
    api_block_inactive_user();
1136
1137
    return true;
1138
}
1139
1140
/**
1141
 * Blocks inactive users with a currently active session from accessing more pages "live".
1142
 *
1143
 * @return bool Returns true if the feature is disabled or the user account is still enabled.
1144
 *              Returns false (and shows a message) if the feature is enabled *and* the user is disabled.
1145
 */
1146
function api_block_inactive_user()
1147
{
1148
    $data = true;
1149
    if (1 != api_get_configuration_value('security_block_inactive_users_immediately')) {
1150
        return $data;
1151
    }
1152
1153
    $userId = api_get_user_id();
1154
    $homeUrl = api_get_path(WEB_PATH);
1155
    if (0 == $userId) {
1156
        return $data;
1157
    }
1158
1159
    $sql = "SELECT active FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1160
            WHERE id = $userId";
1161
1162
    $result = Database::query($sql);
1163
    if (Database::num_rows($result) > 0) {
1164
        $result_array = Database::fetch_array($result);
1165
        $data = (bool) $result_array['active'];
1166
    }
1167
    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...
1168
        $tpl = new Template(null, true, true, false, true, false, true, 0);
1169
        $tpl->assign('hide_login_link', 1);
1170
1171
        //api_not_allowed(true, get_lang('AccountInactive'));
1172
        // we were not in a course, return to home page
1173
        $msg = Display::return_message(
1174
            get_lang('AccountInactive'),
1175
            'error',
1176
            false
1177
        );
1178
1179
        $msg .= '<p class="text-center">
1180
                 <a class="btn btn-default" href="'.$homeUrl.'">'.get_lang('BackHome').'</a></p>';
1181
1182
        if (api_is_anonymous()) {
1183
            /*$form = api_get_not_allowed_login_form();
1184
            $msg .= '<div class="well">';
1185
            $msg .= $form->returnForm();
1186
            $msg .= '</div>';*/
1187
        }
1188
1189
        $tpl->assign('content', $msg);
1190
        $tpl->display_one_col_template();
1191
        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...
1192
    }
1193
1194
    return $data;
1195
}
1196
1197
/**
1198
 * Function used to protect a teacher script.
1199
 * The function blocks access when the user has no teacher rights.
1200
 *
1201
 * @return bool True if the current user can access the script, false otherwise
1202
 *
1203
 * @author Yoselyn Castillo
1204
 */
1205
function api_protect_teacher_script()
1206
{
1207
    if (!api_is_allowed_to_edit()) {
1208
        api_not_allowed(true);
1209
1210
        return false;
1211
    }
1212
1213
    return true;
1214
}
1215
1216
/**
1217
 * Function used to prevent anonymous users from accessing a script.
1218
 *
1219
 * @param bool $printHeaders
1220
 *
1221
 * @return bool
1222
 */
1223
function api_block_anonymous_users($printHeaders = true)
1224
{
1225
    $isAuth = Container::getAuthorizationChecker()->isGranted('IS_AUTHENTICATED_FULLY');
1226
1227
    if (false === $isAuth) {
1228
        api_not_allowed($printHeaders);
1229
1230
        return false;
1231
    }
1232
1233
    api_block_inactive_user();
1234
1235
    return true;
1236
1237
    /*$user = api_get_user_info();
1238
    if (!(isset($user['user_id']) && $user['user_id']) || api_is_anonymous($user['user_id'], true)) {
1239
        api_not_allowed($printHeaders);
1240
1241
        return false;
1242
    }
1243
    api_block_inactive_user();
1244
1245
    return true;*/
1246
}
1247
1248
/**
1249
 * Returns a rough evaluation of the browser's name and version based on very
1250
 * simple regexp.
1251
 *
1252
 * @return array with the navigator name and version ['name' => '...', 'version' => '...']
1253
 */
1254
function api_get_navigator()
1255
{
1256
    $navigator = 'Unknown';
1257
    $version = 0;
1258
1259
    if (!isset($_SERVER['HTTP_USER_AGENT'])) {
1260
        return ['name' => 'Unknown', 'version' => '0.0.0'];
1261
    }
1262
1263
    if (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Opera')) {
1264
        $navigator = 'Opera';
1265
        [, $version] = explode('Opera', $_SERVER['HTTP_USER_AGENT']);
1266
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Edge')) {
1267
        $navigator = 'Edge';
1268
        [, $version] = explode('Edge', $_SERVER['HTTP_USER_AGENT']);
1269
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE')) {
1270
        $navigator = 'Internet Explorer';
1271
        [, $version] = explode('MSIE ', $_SERVER['HTTP_USER_AGENT']);
1272
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Chrome')) {
1273
        $navigator = 'Chrome';
1274
        [, $version] = explode('Chrome', $_SERVER['HTTP_USER_AGENT']);
1275
    } elseif (false !== stripos($_SERVER['HTTP_USER_AGENT'], 'Safari')) {
1276
        $navigator = 'Safari';
1277
        if (false !== stripos($_SERVER['HTTP_USER_AGENT'], 'Version/')) {
1278
            // If this Safari does have the "Version/" string in its user agent
1279
            // then use that as a version indicator rather than what's after
1280
            // "Safari/" which is rather a "build number" or something
1281
            [, $version] = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1282
        } else {
1283
            [, $version] = explode('Safari/', $_SERVER['HTTP_USER_AGENT']);
1284
        }
1285
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Firefox')) {
1286
        $navigator = 'Firefox';
1287
        [, $version] = explode('Firefox', $_SERVER['HTTP_USER_AGENT']);
1288
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Netscape')) {
1289
        $navigator = 'Netscape';
1290
        if (false !== stripos($_SERVER['HTTP_USER_AGENT'], 'Netscape/')) {
1291
            [, $version] = explode('Netscape', $_SERVER['HTTP_USER_AGENT']);
1292
        } else {
1293
            [, $version] = explode('Navigator', $_SERVER['HTTP_USER_AGENT']);
1294
        }
1295
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Konqueror')) {
1296
        $navigator = 'Konqueror';
1297
        [, $version] = explode('Konqueror', $_SERVER['HTTP_USER_AGENT']);
1298
    } elseif (false !== stripos($_SERVER['HTTP_USER_AGENT'], 'applewebkit')) {
1299
        $navigator = 'AppleWebKit';
1300
        [, $version] = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1301
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Gecko')) {
1302
        $navigator = 'Mozilla';
1303
        [, $version] = explode('; rv:', $_SERVER['HTTP_USER_AGENT']);
1304
    }
1305
1306
    // Now cut extra stuff around (mostly *after*) the version number
1307
    $version = preg_replace('/^([\/\s])?([\d\.]+)?.*/', '\2', $version);
1308
1309
    if (false === strpos($version, '.')) {
1310
        $version = number_format(doubleval($version), 1);
1311
    }
1312
1313
    return ['name' => $navigator, 'version' => $version];
1314
}
1315
1316
/**
1317
 * @return true if user self registration is allowed, false otherwise
1318
 */
1319
function api_is_self_registration_allowed()
1320
{
1321
    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...
1322
}
1323
1324
/**
1325
 * This function returns the id of the user which is stored in the $_user array.
1326
 *
1327
 * example: The function can be used to check if a user is logged in
1328
 *          if (api_get_user_id())
1329
 *
1330
 * @return int the id of the current user, 0 if is empty
1331
 */
1332
function api_get_user_id()
1333
{
1334
    $userInfo = Session::read('_user');
1335
    if ($userInfo && isset($userInfo['user_id'])) {
1336
        return (int) $userInfo['user_id'];
1337
    }
1338
1339
    return 0;
1340
}
1341
1342
/**
1343
 * Gets the list of courses a specific user is subscribed to.
1344
 *
1345
 * @param int       User ID
1346
 * @param bool $fetch_session Whether to get session courses or not - NOT YET IMPLEMENTED
1347
 *
1348
 * @return array Array of courses in the form [0]=>('code'=>xxx,'db'=>xxx,'dir'=>xxx,'status'=>d)
1349
 *
1350
 * @deprecated use CourseManager::get_courses_list_by_user_id()
1351
 */
1352
function api_get_user_courses($userId, $fetch_session = true)
1353
{
1354
    // Get out if not integer
1355
    if ($userId != strval(intval($userId))) {
1356
        return [];
1357
    }
1358
1359
    $t_course = Database::get_main_table(TABLE_MAIN_COURSE);
1360
    $t_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
1361
1362
    $sql = "SELECT cc.id as real_id, cc.code code, cc.directory dir, cu.status status
1363
            FROM $t_course cc, $t_course_user cu
1364
            WHERE
1365
                cc.id = cu.c_id AND
1366
                cu.user_id = $userId AND
1367
                cu.relation_type <> ".COURSE_RELATION_TYPE_RRHH;
1368
    $result = Database::query($sql);
1369
    if (false === $result) {
1370
        return [];
1371
    }
1372
1373
    $courses = [];
1374
    while ($row = Database::fetch_array($result)) {
1375
        // we only need the database name of the course
1376
        $courses[] = $row;
1377
    }
1378
1379
    return $courses;
1380
}
1381
1382
/**
1383
 * Formats user information into a standard array
1384
 * This function should be only used inside api_get_user_info().
1385
 *
1386
 * @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...
1387
 * @param bool $add_password
1388
 * @param bool $loadAvatars  turn off to improve performance
1389
 *
1390
 * @return array Standard user array
1391
 */
1392
function _api_format_user($user, $add_password = false, $loadAvatars = true)
1393
{
1394
    $result = [];
1395
1396
    if (!isset($user['id'])) {
1397
        return [];
1398
    }
1399
1400
    $result['firstname'] = null;
1401
    $result['lastname'] = null;
1402
1403
    if (isset($user['firstname']) && isset($user['lastname'])) {
1404
        // with only lowercase
1405
        $result['firstname'] = $user['firstname'];
1406
        $result['lastname'] = $user['lastname'];
1407
    } elseif (isset($user['firstName']) && isset($user['lastName'])) {
1408
        // with uppercase letters
1409
        $result['firstname'] = isset($user['firstName']) ? $user['firstName'] : null;
1410
        $result['lastname'] = isset($user['lastName']) ? $user['lastName'] : null;
1411
    }
1412
1413
    if (isset($user['email'])) {
1414
        $result['mail'] = isset($user['email']) ? $user['email'] : null;
1415
        $result['email'] = isset($user['email']) ? $user['email'] : null;
1416
    } else {
1417
        $result['mail'] = isset($user['mail']) ? $user['mail'] : null;
1418
        $result['email'] = isset($user['mail']) ? $user['mail'] : null;
1419
    }
1420
1421
    $result['complete_name'] = api_get_person_name($result['firstname'], $result['lastname']);
1422
    $result['complete_name_with_username'] = $result['complete_name'];
1423
1424
    if (!empty($user['username']) && 'false' === api_get_setting('profile.hide_username_with_complete_name')) {
1425
        $result['complete_name_with_username'] = $result['complete_name'].' ('.$user['username'].')';
1426
    }
1427
1428
    $showEmail = 'true' === api_get_setting('show_email_addresses');
1429
    if (!empty($user['email'])) {
1430
        $result['complete_name_with_email_forced'] = $result['complete_name'].' ('.$user['email'].')';
1431
        if ($showEmail) {
1432
            $result['complete_name_with_email'] = $result['complete_name'].' ('.$user['email'].')';
1433
        }
1434
    } else {
1435
        $result['complete_name_with_email'] = $result['complete_name'];
1436
        $result['complete_name_with_email_forced'] = $result['complete_name'];
1437
    }
1438
1439
    // Kept for historical reasons
1440
    $result['firstName'] = $result['firstname'];
1441
    $result['lastName'] = $result['lastname'];
1442
1443
    $attributes = [
1444
        'phone',
1445
        'address',
1446
        'picture_uri',
1447
        'official_code',
1448
        'status',
1449
        'active',
1450
        'auth_source',
1451
        'username',
1452
        'theme',
1453
        'language',
1454
        'creator_id',
1455
        'registration_date',
1456
        'hr_dept_id',
1457
        'expiration_date',
1458
        'last_login',
1459
        'user_is_online',
1460
    ];
1461
1462
    if ('true' === api_get_setting('extended_profile')) {
1463
        $attributes[] = 'competences';
1464
        $attributes[] = 'diplomas';
1465
        $attributes[] = 'teach';
1466
        $attributes[] = 'openarea';
1467
    }
1468
1469
    foreach ($attributes as $attribute) {
1470
        $result[$attribute] = isset($user[$attribute]) ? $user[$attribute] : null;
1471
    }
1472
1473
    $user_id = (int) $user['id'];
1474
    // Maintain the user_id index for backwards compatibility
1475
    $result['user_id'] = $result['id'] = $user_id;
1476
1477
    $hasCertificates = Certificate::getCertificateByUser($user_id);
1478
    $result['has_certificates'] = 0;
1479
    if (!empty($hasCertificates)) {
1480
        $result['has_certificates'] = 1;
1481
    }
1482
1483
    $result['icon_status'] = '';
1484
    $result['icon_status_medium'] = '';
1485
    $result['is_admin'] = UserManager::is_admin($user_id);
1486
1487
    // Getting user avatar.
1488
    if ($loadAvatars) {
1489
        $result['avatar'] = '';
1490
        $result['avatar_no_query'] = '';
1491
        $result['avatar_small'] = '';
1492
        $result['avatar_medium'] = '';
1493
1494
        /*if (!isset($user['avatar'])) {
1495
            $originalFile = UserManager::getUserPicture(
1496
                $user_id,
1497
                USER_IMAGE_SIZE_ORIGINAL,
1498
                null,
1499
                $result
1500
            );
1501
            $result['avatar'] = $originalFile;
1502
            $avatarString = explode('?', $result['avatar']);
1503
            $result['avatar_no_query'] = reset($avatarString);
1504
        } else {
1505
            $result['avatar'] = $user['avatar'];
1506
            $avatarString = explode('?', $user['avatar']);
1507
            $result['avatar_no_query'] = reset($avatarString);
1508
        }
1509
1510
        if (!isset($user['avatar_small'])) {
1511
            $smallFile = UserManager::getUserPicture(
1512
                $user_id,
1513
                USER_IMAGE_SIZE_SMALL,
1514
                null,
1515
                $result
1516
            );
1517
            $result['avatar_small'] = $smallFile;
1518
        } else {
1519
            $result['avatar_small'] = $user['avatar_small'];
1520
        }
1521
1522
        if (!isset($user['avatar_medium'])) {
1523
            $mediumFile = UserManager::getUserPicture(
1524
                $user_id,
1525
                USER_IMAGE_SIZE_MEDIUM,
1526
                null,
1527
                $result
1528
            );
1529
            $result['avatar_medium'] = $mediumFile;
1530
        } else {
1531
            $result['avatar_medium'] = $user['avatar_medium'];
1532
        }*/
1533
1534
        $urlImg = api_get_path(WEB_IMG_PATH);
1535
        $iconStatus = '';
1536
        $iconStatusMedium = '';
1537
        $label = '';
1538
        switch ($result['status']) {
1539
            case STUDENT:
1540
                if ($result['has_certificates']) {
1541
                    $iconStatus = $urlImg.'icons/svg/identifier_graduated.svg';
1542
                    $label = get_lang('Graduated');
1543
                } else {
1544
                    $iconStatus = $urlImg.'icons/svg/identifier_student.svg';
1545
                    $label = get_lang('Student');
1546
                }
1547
                break;
1548
            case COURSEMANAGER:
1549
                if ($result['is_admin']) {
1550
                    $iconStatus = $urlImg.'icons/svg/identifier_admin.svg';
1551
                    $label = get_lang('Admin');
1552
                } else {
1553
                    $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1554
                    $label = get_lang('Teacher');
1555
                }
1556
                break;
1557
            case STUDENT_BOSS:
1558
                $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1559
                $label = get_lang('StudentBoss');
1560
                break;
1561
        }
1562
1563
        if (!empty($iconStatus)) {
1564
            $iconStatusMedium = '<img src="'.$iconStatus.'" width="32px" height="32px">';
1565
            $iconStatus = '<img src="'.$iconStatus.'" width="22px" height="22px">';
1566
        }
1567
1568
        $result['icon_status'] = $iconStatus;
1569
        $result['icon_status_label'] = $label;
1570
        $result['icon_status_medium'] = $iconStatusMedium;
1571
    }
1572
1573
    if (isset($user['user_is_online'])) {
1574
        $result['user_is_online'] = true == $user['user_is_online'] ? 1 : 0;
1575
    }
1576
    if (isset($user['user_is_online_in_chat'])) {
1577
        $result['user_is_online_in_chat'] = (int) $user['user_is_online_in_chat'];
1578
    }
1579
1580
    if ($add_password) {
1581
        $result['password'] = $user['password'];
1582
    }
1583
1584
    if (isset($result['profile_completed'])) {
1585
        $result['profile_completed'] = $user['profile_completed'];
1586
    }
1587
1588
    $result['profile_url'] = api_get_path(WEB_CODE_PATH).'social/profile.php?u='.$user_id;
1589
1590
    // Send message link
1591
    $sendMessage = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&user_id='.$user_id;
1592
    $result['complete_name_with_message_link'] = Display::url(
1593
        $result['complete_name_with_username'],
1594
        $sendMessage,
1595
        ['class' => 'ajax']
1596
    );
1597
1598
    if (isset($user['extra'])) {
1599
        $result['extra'] = $user['extra'];
1600
    }
1601
1602
    return $result;
1603
}
1604
1605
/**
1606
 * Finds all the information about a user.
1607
 * If no parameter is passed you find all the information about the current user.
1608
 *
1609
 * @param int  $user_id
1610
 * @param bool $checkIfUserOnline
1611
 * @param bool $showPassword
1612
 * @param bool $loadExtraData
1613
 * @param bool $loadOnlyVisibleExtraData Get the user extra fields that are visible
1614
 * @param bool $loadAvatars              turn off to improve performance and if avatars are not needed
1615
 * @param bool $updateCache              update apc cache if exists
1616
 *
1617
 * @return mixed $user_info user_id, lastname, firstname, username, email, etc or false on error
1618
 *
1619
 * @author Patrick Cool <[email protected]>
1620
 * @author Julio Montoya
1621
 *
1622
 * @version 21 September 2004
1623
 */
1624
function api_get_user_info(
1625
    $user_id = 0,
1626
    $checkIfUserOnline = false,
1627
    $showPassword = false,
1628
    $loadExtraData = false,
1629
    $loadOnlyVisibleExtraData = false,
1630
    $loadAvatars = true,
1631
    $updateCache = false
1632
) {
1633
    // Make sure user_id is safe
1634
    $user_id = (int) $user_id;
1635
    $user = false;
1636
    if (empty($user_id)) {
1637
        $userFromSession = Session::read('_user');
1638
        if (isset($userFromSession) && !empty($userFromSession)) {
1639
            return $userFromSession;
1640
            /*
1641
            return _api_format_user(
1642
                $userFromSession,
1643
                $showPassword,
1644
                $loadAvatars
1645
            );*/
1646
        }
1647
1648
        return false;
1649
    }
1650
1651
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1652
            WHERE id = $user_id";
1653
    $result = Database::query($sql);
1654
    if (Database::num_rows($result) > 0) {
1655
        $result_array = Database::fetch_array($result);
1656
        $result_array['user_is_online_in_chat'] = 0;
1657
        if ($checkIfUserOnline) {
1658
            $use_status_in_platform = user_is_online($user_id);
1659
            $result_array['user_is_online'] = $use_status_in_platform;
1660
            $user_online_in_chat = 0;
1661
            if ($use_status_in_platform) {
1662
                $user_status = UserManager::get_extra_user_data_by_field(
1663
                    $user_id,
1664
                    'user_chat_status',
1665
                    false,
1666
                    true
1667
                );
1668
                if (1 == (int) $user_status['user_chat_status']) {
1669
                    $user_online_in_chat = 1;
1670
                }
1671
            }
1672
            $result_array['user_is_online_in_chat'] = $user_online_in_chat;
1673
        }
1674
1675
        if ($loadExtraData) {
1676
            $fieldValue = new ExtraFieldValue('user');
1677
            $result_array['extra'] = $fieldValue->getAllValuesForAnItem(
1678
                $user_id,
1679
                $loadOnlyVisibleExtraData
1680
            );
1681
        }
1682
        $user = _api_format_user($result_array, $showPassword, $loadAvatars);
1683
    }
1684
1685
    return $user;
1686
}
1687
1688
function api_get_user_info_from_entity(
1689
    User $user,
1690
    $checkIfUserOnline = false,
1691
    $showPassword = false,
1692
    $loadExtraData = false,
1693
    $loadOnlyVisibleExtraData = false,
1694
    $loadAvatars = true,
1695
    $loadCertificate = false
1696
) {
1697
    if (!$user instanceof UserInterface) {
1698
        return false;
1699
    }
1700
1701
    // Make sure user_id is safe
1702
    $user_id = (int) $user->getId();
1703
1704
    if (empty($user_id)) {
1705
        $userFromSession = Session::read('_user');
1706
1707
        if (isset($userFromSession) && !empty($userFromSession)) {
1708
            return $userFromSession;
1709
        }
1710
1711
        return false;
1712
    }
1713
1714
    $result = [];
1715
    $result['user_is_online_in_chat'] = 0;
1716
    if ($checkIfUserOnline) {
1717
        $use_status_in_platform = user_is_online($user_id);
1718
        $result['user_is_online'] = $use_status_in_platform;
1719
        $user_online_in_chat = 0;
1720
        if ($use_status_in_platform) {
1721
            $user_status = UserManager::get_extra_user_data_by_field(
1722
                $user_id,
1723
                'user_chat_status',
1724
                false,
1725
                true
1726
            );
1727
            if (1 == (int) $user_status['user_chat_status']) {
1728
                $user_online_in_chat = 1;
1729
            }
1730
        }
1731
        $result['user_is_online_in_chat'] = $user_online_in_chat;
1732
    }
1733
1734
    if ($loadExtraData) {
1735
        $fieldValue = new ExtraFieldValue('user');
1736
        $result['extra'] = $fieldValue->getAllValuesForAnItem(
1737
            $user_id,
1738
            $loadOnlyVisibleExtraData
1739
        );
1740
    }
1741
1742
    $result['username'] = $user->getUsername();
1743
    $result['status'] = $user->getStatus();
1744
    $result['firstname'] = $user->getFirstname();
1745
    $result['lastname'] = $user->getLastname();
1746
    $result['email'] = $result['mail'] = $user->getEmail();
1747
    $result['complete_name'] = api_get_person_name($result['firstname'], $result['lastname']);
1748
    $result['complete_name_with_username'] = $result['complete_name'];
1749
1750
    if (!empty($result['username']) && 'false' === api_get_setting('profile.hide_username_with_complete_name')) {
1751
        $result['complete_name_with_username'] = $result['complete_name'].' ('.$result['username'].')';
1752
    }
1753
1754
    $showEmail = 'true' === api_get_setting('show_email_addresses');
1755
    if (!empty($result['email'])) {
1756
        $result['complete_name_with_email_forced'] = $result['complete_name'].' ('.$result['email'].')';
1757
        if ($showEmail) {
1758
            $result['complete_name_with_email'] = $result['complete_name'].' ('.$result['email'].')';
1759
        }
1760
    } else {
1761
        $result['complete_name_with_email'] = $result['complete_name'];
1762
        $result['complete_name_with_email_forced'] = $result['complete_name'];
1763
    }
1764
1765
    // Kept for historical reasons
1766
    $result['firstName'] = $result['firstname'];
1767
    $result['lastName'] = $result['lastname'];
1768
1769
    $attributes = [
1770
        'picture_uri',
1771
        'last_login',
1772
        'user_is_online',
1773
    ];
1774
1775
    $result['phone'] = $user->getPhone();
1776
    $result['address'] = $user->getAddress();
1777
    $result['official_code'] = $user->getOfficialCode();
1778
    $result['active'] = $user->getActive();
1779
    $result['auth_source'] = $user->getAuthSource();
1780
    $result['language'] = $user->getLocale();
1781
    $result['creator_id'] = $user->getCreatorId();
1782
    $result['registration_date'] = $user->getRegistrationDate()->format('Y-m-d H:i:s');
1783
    $result['hr_dept_id'] = $user->getHrDeptId();
1784
    $result['expiration_date'] = '';
1785
    if ($user->getExpirationDate()) {
1786
        $result['expiration_date'] = $user->getExpirationDate()->format('Y-m-d H:i:s');
1787
    }
1788
1789
    $result['last_login'] = null;
1790
    if ($user->getLastLogin()) {
1791
        $result['last_login'] = $user->getLastLogin()->format('Y-m-d H:i:s');
1792
    }
1793
1794
    $result['competences'] = $user->getCompetences();
1795
    $result['diplomas'] = $user->getDiplomas();
1796
    $result['teach'] = $user->getTeach();
1797
    $result['openarea'] = $user->getOpenarea();
1798
    $user_id = (int) $user->getId();
1799
1800
    // Maintain the user_id index for backwards compatibility
1801
    $result['user_id'] = $result['id'] = $user_id;
1802
1803
    if ($loadCertificate) {
1804
        $hasCertificates = Certificate::getCertificateByUser($user_id);
1805
        $result['has_certificates'] = 0;
1806
        if (!empty($hasCertificates)) {
1807
            $result['has_certificates'] = 1;
1808
        }
1809
    }
1810
1811
    $result['icon_status'] = '';
1812
    $result['icon_status_medium'] = '';
1813
    $result['is_admin'] = UserManager::is_admin($user_id);
1814
1815
    // Getting user avatar.
1816
    if ($loadAvatars) {
1817
        $result['avatar'] = '';
1818
        $result['avatar_no_query'] = '';
1819
        $result['avatar_small'] = '';
1820
        $result['avatar_medium'] = '';
1821
1822
        /*if (!isset($user['avatar'])) {
1823
            $originalFile = UserManager::getUserPicture(
1824
                $user_id,
1825
                USER_IMAGE_SIZE_ORIGINAL,
1826
                null,
1827
                $result
1828
            );
1829
            $result['avatar'] = $originalFile;
1830
            $avatarString = explode('?', $result['avatar']);
1831
            $result['avatar_no_query'] = reset($avatarString);
1832
        } else {
1833
            $result['avatar'] = $user['avatar'];
1834
            $avatarString = explode('?', $user['avatar']);
1835
            $result['avatar_no_query'] = reset($avatarString);
1836
        }
1837
1838
        if (!isset($user['avatar_small'])) {
1839
            $smallFile = UserManager::getUserPicture(
1840
                $user_id,
1841
                USER_IMAGE_SIZE_SMALL,
1842
                null,
1843
                $result
1844
            );
1845
            $result['avatar_small'] = $smallFile;
1846
        } else {
1847
            $result['avatar_small'] = $user['avatar_small'];
1848
        }
1849
1850
        if (!isset($user['avatar_medium'])) {
1851
            $mediumFile = UserManager::getUserPicture(
1852
                $user_id,
1853
                USER_IMAGE_SIZE_MEDIUM,
1854
                null,
1855
                $result
1856
            );
1857
            $result['avatar_medium'] = $mediumFile;
1858
        } else {
1859
            $result['avatar_medium'] = $user['avatar_medium'];
1860
        }*/
1861
1862
        //$urlImg = api_get_path(WEB_IMG_PATH);
1863
        $urlImg = '/';
1864
        $iconStatus = '';
1865
        $iconStatusMedium = '';
1866
1867
        switch ($user->getStatus()) {
1868
            case STUDENT:
1869
                if (isset($result['has_certificates']) && $result['has_certificates']) {
1870
                    $iconStatus = $urlImg.'icons/svg/identifier_graduated.svg';
1871
                } else {
1872
                    $iconStatus = $urlImg.'icons/svg/identifier_student.svg';
1873
                }
1874
                break;
1875
            case COURSEMANAGER:
1876
                if ($result['is_admin']) {
1877
                    $iconStatus = $urlImg.'icons/svg/identifier_admin.svg';
1878
                } else {
1879
                    $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1880
                }
1881
                break;
1882
            case STUDENT_BOSS:
1883
                $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1884
                break;
1885
        }
1886
1887
        if (!empty($iconStatus)) {
1888
            $iconStatusMedium = '<img src="'.$iconStatus.'" width="32px" height="32px">';
1889
            $iconStatus = '<img src="'.$iconStatus.'" width="22px" height="22px">';
1890
        }
1891
1892
        $result['icon_status'] = $iconStatus;
1893
        $result['icon_status_medium'] = $iconStatusMedium;
1894
    }
1895
1896
    if (isset($result['user_is_online'])) {
1897
        $result['user_is_online'] = true == $result['user_is_online'] ? 1 : 0;
1898
    }
1899
    if (isset($result['user_is_online_in_chat'])) {
1900
        $result['user_is_online_in_chat'] = $result['user_is_online_in_chat'];
1901
    }
1902
1903
    $result['password'] = '';
1904
    if ($showPassword) {
1905
        $result['password'] = $user->getPassword();
1906
    }
1907
1908
    if (isset($result['profile_completed'])) {
1909
        $result['profile_completed'] = $result['profile_completed'];
1910
    }
1911
1912
    $result['profile_url'] = api_get_path(WEB_CODE_PATH).'social/profile.php?u='.$user_id;
1913
1914
    // Send message link
1915
    $sendMessage = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&user_id='.$user_id;
1916
    $result['complete_name_with_message_link'] = Display::url(
1917
        $result['complete_name_with_username'],
1918
        $sendMessage,
1919
        ['class' => 'ajax']
1920
    );
1921
1922
    if (isset($result['extra'])) {
1923
        $result['extra'] = $result['extra'];
1924
    }
1925
1926
    return $result;
1927
}
1928
1929
function api_get_lp_entity(int $id): ?CLp
1930
{
1931
    return Database::getManager()->getRepository(CLp::class)->find($id);
1932
}
1933
1934
function api_get_user_entity(int $userId = 0): ?User
1935
{
1936
    $userId = $userId ?: api_get_user_id();
1937
    $repo = UserManager::getRepository();
1938
1939
    /** @var User $user */
1940
    $user = $repo->find($userId);
1941
1942
    return $user;
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
 * Returns the current course directory.
2051
 *
2052
 * This function relies on api_get_course_info()
2053
 *
2054
 * @param string    The course code - optional (takes it from session if not given)
2055
 *
2056
 * @return string The directory where the course is located inside the Chamilo "courses" directory
2057
 *
2058
 * @author Yannick Warnier <[email protected]>
2059
 */
2060
function api_get_course_path($course_code = null)
2061
{
2062
    $info = !empty($course_code) ? api_get_course_info($course_code) : api_get_course_info();
2063
2064
    return $info['path'];
2065
}
2066
2067
/**
2068
 * Gets a course setting from the current course_setting table. Try always using integer values.
2069
 *
2070
 * @param string $settingName The name of the setting we want from the table
2071
 * @param array  $courseInfo
2072
 * @param bool   $force       force checking the value in the database
2073
 *
2074
 * @return mixed The value of that setting in that table. Return -1 if not found.
2075
 */
2076
function api_get_course_setting($settingName, $courseInfo = [], $force = false)
2077
{
2078
    if (empty($courseInfo)) {
2079
        $courseInfo = api_get_course_info();
2080
    }
2081
2082
    if (empty($courseInfo) || empty($settingName)) {
2083
        return -1;
2084
    }
2085
2086
    $courseId = isset($courseInfo['real_id']) && !empty($courseInfo['real_id']) ? $courseInfo['real_id'] : 0;
2087
2088
    if (empty($courseId)) {
2089
        return -1;
2090
    }
2091
2092
    static $courseSettingInfo = [];
2093
2094
    if ($force) {
2095
        $courseSettingInfo = [];
2096
    }
2097
2098
    if (!isset($courseSettingInfo[$courseId])) {
2099
        $table = Database::get_course_table(TABLE_COURSE_SETTING);
2100
        $settingName = Database::escape_string($settingName);
2101
2102
        $sql = "SELECT variable, value FROM $table
2103
                WHERE c_id = $courseId ";
2104
        $res = Database::query($sql);
2105
        if (Database::num_rows($res) > 0) {
2106
            $result = Database::store_result($res, 'ASSOC');
2107
            $courseSettingInfo[$courseId] = array_column($result, 'value', 'variable');
2108
2109
            if (isset($courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'])) {
2110
                $value = $courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'];
2111
                if (!is_null($value)) {
2112
                    $result = explode(',', $value);
2113
                    $courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'] = $result;
2114
                }
2115
            }
2116
        }
2117
    }
2118
2119
    if (isset($courseSettingInfo[$courseId]) && isset($courseSettingInfo[$courseId][$settingName])) {
2120
        return $courseSettingInfo[$courseId][$settingName];
2121
    }
2122
2123
    return -1;
2124
}
2125
2126
function api_get_course_plugin_setting($plugin, $settingName, $courseInfo = [])
2127
{
2128
    $value = api_get_course_setting($settingName, $courseInfo, true);
2129
2130
    if (-1 === $value) {
2131
        // Check global settings
2132
        $value = api_get_plugin_setting($plugin, $settingName);
2133
        if ('true' === $value) {
2134
            return 1;
2135
        }
2136
        if ('false' === $value) {
2137
            return 0;
2138
        }
2139
        if (null === $value) {
2140
            return -1;
2141
        }
2142
    }
2143
2144
    return $value;
2145
}
2146
2147
/**
2148
 * Gets an anonymous user ID.
2149
 *
2150
 * For some tools that need tracking, like the learnpath tool, it is necessary
2151
 * to have a usable user-id to enable some kind of tracking, even if not
2152
 * perfect. An anonymous ID is taken from the users table by looking for a
2153
 * status of "6" (anonymous).
2154
 *
2155
 * @return int User ID of the anonymous user, or O if no anonymous user found
2156
 */
2157
function api_get_anonymous_id()
2158
{
2159
    // Find if another anon is connected now
2160
    $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
2161
    $tableU = Database::get_main_table(TABLE_MAIN_USER);
2162
    $ip = Database::escape_string(api_get_real_ip());
2163
    $max = (int) api_get_configuration_value('max_anonymous_users');
2164
    if ($max >= 2) {
2165
        $sql = "SELECT * FROM $table as TEL
2166
                JOIN $tableU as U
2167
                ON U.id = TEL.login_user_id
2168
                WHERE TEL.user_ip = '$ip'
2169
                    AND U.status = ".ANONYMOUS."
2170
                    AND U.id != 2 ";
2171
2172
        $result = Database::query($sql);
2173
        if (empty(Database::num_rows($result))) {
2174
            $login = uniqid('anon_');
2175
            $anonList = UserManager::get_user_list(['status' => ANONYMOUS], ['registration_date ASC']);
2176
            if (count($anonList) >= $max) {
2177
                foreach ($anonList as $userToDelete) {
2178
                    UserManager::delete_user($userToDelete['user_id']);
2179
                    break;
2180
                }
2181
            }
2182
2183
            return UserManager::create_user(
2184
                $login,
2185
                'anon',
2186
                ANONYMOUS,
2187
                ' anonymous@localhost',
2188
                $login,
2189
                $login
2190
            );
2191
        } else {
2192
            $row = Database::fetch_array($result, 'ASSOC');
2193
2194
            return $row['id'];
2195
        }
2196
    }
2197
2198
    $table = Database::get_main_table(TABLE_MAIN_USER);
2199
    $sql = "SELECT id
2200
            FROM $table
2201
            WHERE status = ".ANONYMOUS." ";
2202
    $res = Database::query($sql);
2203
    if (Database::num_rows($res) > 0) {
2204
        $row = Database::fetch_array($res, 'ASSOC');
2205
2206
        return $row['id'];
2207
    }
2208
2209
    // No anonymous user was found.
2210
    return 0;
2211
}
2212
2213
/**
2214
 * @param int $courseId
2215
 * @param int $sessionId
2216
 * @param int $groupId
2217
 *
2218
 * @return string
2219
 */
2220
function api_get_cidreq_params($courseId, $sessionId = 0, $groupId = 0)
2221
{
2222
    $courseId = !empty($courseId) ? (int) $courseId : 0;
2223
    $sessionId = !empty($sessionId) ? (int) $sessionId : 0;
2224
    $groupId = !empty($groupId) ? (int) $groupId : 0;
2225
2226
    $url = 'cid='.$courseId;
2227
    $url .= '&sid='.$sessionId;
2228
    $url .= '&gid='.$groupId;
2229
2230
    return $url;
2231
}
2232
2233
/**
2234
 * Returns the current course url part including session, group, and gradebook params.
2235
 *
2236
 * @param bool   $addSessionId
2237
 * @param bool   $addGroupId
2238
 * @param string $origin
2239
 *
2240
 * @return string Course & session references to add to a URL
2241
 */
2242
function api_get_cidreq($addSessionId = true, $addGroupId = true, $origin = '')
2243
{
2244
    $courseId = api_get_course_int_id();
2245
    $url = empty($courseId) ? '' : 'cid='.$courseId;
2246
    $origin = empty($origin) ? api_get_origin() : Security::remove_XSS($origin);
2247
2248
    if ($addSessionId) {
2249
        if (!empty($url)) {
2250
            $url .= 0 == api_get_session_id() ? '&sid=0' : '&sid='.api_get_session_id();
2251
        }
2252
    }
2253
2254
    if ($addGroupId) {
2255
        if (!empty($url)) {
2256
            $url .= 0 == api_get_group_id() ? '&gid=0' : '&gid='.api_get_group_id();
2257
        }
2258
    }
2259
2260
    if (!empty($url)) {
2261
        $url .= '&gradebook='.(int) api_is_in_gradebook();
2262
        $url .= '&origin='.$origin;
2263
    }
2264
2265
    return $url;
2266
}
2267
2268
/**
2269
 * Get if we visited a gradebook page.
2270
 *
2271
 * @return bool
2272
 */
2273
function api_is_in_gradebook()
2274
{
2275
    return Session::read('in_gradebook', false);
2276
}
2277
2278
/**
2279
 * Set that we are in a page inside a gradebook.
2280
 */
2281
function api_set_in_gradebook()
2282
{
2283
    Session::write('in_gradebook', true);
2284
}
2285
2286
/**
2287
 * Remove gradebook session.
2288
 */
2289
function api_remove_in_gradebook()
2290
{
2291
    Session::erase('in_gradebook');
2292
}
2293
2294
/**
2295
 * Returns the current course info array see api_format_course_array()
2296
 * If the course_code is given, the returned array gives info about that
2297
 * particular course, if none given it gets the course info from the session.
2298
 *
2299
 * @param string $courseCode
2300
 *
2301
 * @return array
2302
 */
2303
function api_get_course_info($courseCode = null)
2304
{
2305
    if (!empty($courseCode)) {
2306
        $course = Container::getCourseRepository()->findOneByCode($courseCode);
2307
2308
        return api_format_course_array($course);
2309
    }
2310
2311
    $course = Session::read('_course');
2312
    if ('-1' == $course) {
2313
        $course = [];
2314
    }
2315
2316
    return $course;
2317
}
2318
2319
/**
2320
 * @param int $courseId
2321
 */
2322
function api_get_course_entity($courseId = 0): ?Course
2323
{
2324
    if (empty($courseId)) {
2325
        $courseId = api_get_course_int_id();
2326
    }
2327
2328
    return Container::getCourseRepository()->find($courseId);
2329
}
2330
2331
/**
2332
 * @param int $id
2333
 */
2334
function api_get_session_entity($id = 0): ?SessionEntity
2335
{
2336
    if (empty($id)) {
2337
        $id = api_get_session_id();
2338
    }
2339
2340
    if (empty($id)) {
2341
        return null;
2342
    }
2343
2344
    return Container::getSessionRepository()->find($id);
2345
}
2346
2347
/**
2348
 * @param int $id
2349
 */
2350
function api_get_group_entity($id = 0): ?CGroup
2351
{
2352
    if (empty($id)) {
2353
        $id = api_get_group_id();
2354
    }
2355
2356
    return Container::getGroupRepository()->find($id);
2357
}
2358
2359
/**
2360
 * @param int $id
2361
 */
2362
function api_get_url_entity($id = 0): ?AccessUrl
2363
{
2364
    if (empty($id)) {
2365
        $id = api_get_current_access_url_id();
2366
    }
2367
2368
    return Container::getAccessUrlRepository()->find($id);
2369
}
2370
2371
/**
2372
 * Returns the current course info array.
2373
2374
 * Now if the course_code is given, the returned array gives info about that
2375
 * particular course, not specially the current one.
2376
 *
2377
 * @param int $id Numeric ID of the course
2378
 *
2379
 * @return array The course info as an array formatted by api_format_course_array, including category.name
2380
 */
2381
function api_get_course_info_by_id($id = 0)
2382
{
2383
    $id = (int) $id;
2384
    if (empty($id)) {
2385
        $course = Session::read('_course', []);
2386
2387
        return $course;
2388
    }
2389
2390
    $course = Container::getCourseRepository()->find($id);
2391
    if (empty($course)) {
2392
        return [];
2393
    }
2394
2395
    return api_format_course_array($course);
2396
}
2397
2398
/**
2399
 * Reformat the course array (output by api_get_course_info()) in order, mostly,
2400
 * to switch from 'code' to 'id' in the array.
2401
 *
2402
 * @return array
2403
 *
2404
 * @todo eradicate the false "id"=code field of the $_course array and use the int id
2405
 */
2406
function api_format_course_array(Course $course = null)
2407
{
2408
    if (empty($course)) {
2409
        return [];
2410
    }
2411
2412
    $courseData = [];
2413
    $courseData['id'] = $courseData['real_id'] = $course->getId();
2414
2415
    // Added
2416
    $courseData['code'] = $courseData['sysCode'] = $course->getCode();
2417
    $courseData['name'] = $courseData['title'] = $course->getTitle();
2418
    $courseData['official_code'] = $courseData['visual_code'] = $course->getVisualCode();
2419
    //$courseData['path'] = $courseData['directory'] = $course->getDirectory(); // Use as key in path.
2420
    $courseData['creation_date'] = $course->getCreationDate()->format('Y-m-d H:i:s');
2421
    $courseData['titular'] = $course->getTutorName();
2422
    $courseData['language'] = $courseData['course_language'] = $course->getCourseLanguage();
2423
    $courseData['extLink']['url'] = $courseData['department_url'] = $course->getDepartmentUrl();
2424
    $courseData['extLink']['name'] = $courseData['department_name'] = $course->getDepartmentName();
2425
2426
    $courseData['visibility'] = $course->getVisibility();
2427
    $courseData['subscribe_allowed'] = $courseData['subscribe'] = $course->getSubscribe();
2428
    $courseData['unsubscribe'] = $course->getUnsubscribe();
2429
    $courseData['activate_legal'] = $course->getActivateLegal();
2430
    $courseData['legal'] = $course->getLegal();
2431
    $courseData['show_score'] = $course->getShowScore(); //used in the work tool
2432
2433
    //$coursePath = api_get_path(WEB_COURSE_PATH);
2434
    $coursePath = '/course/';
2435
    $webCourseHome = $coursePath.$courseData['real_id'].'/home';
2436
2437
    // Course password
2438
    $courseData['registration_code'] = $course->getRegistrationCode();
2439
    $courseData['disk_quota'] = $course->getDiskQuota();
2440
    $courseData['course_public_url'] = $webCourseHome;
2441
    $courseData['about_url'] = $coursePath.$courseData['real_id'].'/about';
2442
    $courseData['add_teachers_to_sessions_courses'] = $course->isAddTeachersToSessionsCourses();
2443
    $courseData['entity'] = $course;
2444
2445
    $image = Display::return_icon(
2446
        'course.png',
2447
        null,
2448
        null,
2449
        ICON_SIZE_BIG,
2450
        null,
2451
        true,
2452
        false
2453
    );
2454
2455
    $illustration = Container::getIllustrationRepository()->getIllustrationUrl($course);
2456
    if (!empty($illustration)) {
2457
        $image = $illustration;
2458
    }
2459
2460
    $courseData['course_image'] = $image.'?filter=course_picture_small';
2461
2462
    // Course large image
2463
    /*$courseData['course_image_large_source'] = '';
2464
    if (file_exists($courseSys.'/course-pic.png')) {
2465
        $url_image = $webCourseHome.'/course-pic.png';
2466
        $courseData['course_image_large_source'] = $courseSys.'/course-pic.png';
2467
    } else {
2468
        $url_image = Display::return_icon(
2469
            'session_default.png',
2470
            null,
2471
            null,
2472
            null,
2473
            null,
2474
            true,
2475
            true
2476
        );
2477
    }*/
2478
2479
    $courseData['course_image_large'] = $image.'?filter=course_picture_medium';
2480
2481
    return $courseData;
2482
}
2483
2484
/**
2485
 * Returns a difficult to guess password.
2486
 *
2487
 * @param int $length the length of the password
2488
 *
2489
 * @return string the generated password
2490
 */
2491
function api_generate_password($length = 8)
2492
{
2493
    if ($length < 2) {
2494
        $length = 2;
2495
    }
2496
2497
    $charactersLowerCase = 'abcdefghijkmnopqrstuvwxyz';
2498
    $charactersUpperCase = 'ABCDEFGHJKLMNPQRSTUVWXYZ';
2499
    $minNumbers = 2;
2500
    $length = $length - $minNumbers;
2501
    $minLowerCase = round($length / 2);
2502
    $minUpperCase = $length - $minLowerCase;
2503
2504
    $password = '';
2505
    $passwordRequirements = api_get_configuration_value('password_requirements');
2506
2507
    $factory = new RandomLib\Factory();
2508
    $generator = $factory->getGenerator(new SecurityLib\Strength(SecurityLib\Strength::MEDIUM));
2509
2510
    if (!empty($passwordRequirements)) {
2511
        $length = $passwordRequirements['min']['length'];
2512
        $minNumbers = $passwordRequirements['min']['numeric'];
2513
        $minLowerCase = $passwordRequirements['min']['lowercase'];
2514
        $minUpperCase = $passwordRequirements['min']['uppercase'];
2515
2516
        $rest = $length - $minNumbers - $minLowerCase - $minUpperCase;
2517
        // Add the rest to fill the length requirement
2518
        if ($rest > 0) {
2519
            $password .= $generator->generateString($rest, $charactersLowerCase.$charactersUpperCase);
2520
        }
2521
    }
2522
2523
    // Min digits default 2
2524
    for ($i = 0; $i < $minNumbers; $i++) {
2525
        $password .= $generator->generateInt(2, 9);
2526
    }
2527
2528
    // Min lowercase
2529
    $password .= $generator->generateString($minLowerCase, $charactersLowerCase);
2530
2531
    // Min uppercase
2532
    $password .= $generator->generateString($minUpperCase, $charactersUpperCase);
2533
    $password = str_shuffle($password);
2534
2535
    return $password;
2536
}
2537
2538
/**
2539
 * Checks a password to see wether it is OK to use.
2540
 *
2541
 * @param string $password
2542
 *
2543
 * @return bool if the password is acceptable, false otherwise
2544
 *              Notes about what a password "OK to use" is:
2545
 *              1. The password should be at least 5 characters long.
2546
 *              2. Only English letters (uppercase or lowercase, it doesn't matter) and digits are allowed.
2547
 *              3. The password should contain at least 3 letters.
2548
 *              4. It should contain at least 2 digits.
2549
 *              Settings will change if the configuration value is set: password_requirements
2550
 */
2551
function api_check_password($password)
2552
{
2553
    $passwordRequirements = Security::getPasswordRequirements();
2554
2555
    $minLength = $passwordRequirements['min']['length'];
2556
    $minNumbers = $passwordRequirements['min']['numeric'];
2557
    // Optional
2558
    $minLowerCase = $passwordRequirements['min']['lowercase'];
2559
    $minUpperCase = $passwordRequirements['min']['uppercase'];
2560
2561
    $minLetters = $minLowerCase + $minUpperCase;
2562
    $passwordLength = api_strlen($password);
2563
2564
    $conditions = [
2565
        'min_length' => $passwordLength >= $minLength,
2566
    ];
2567
2568
    $digits = 0;
2569
    $lowerCase = 0;
2570
    $upperCase = 0;
2571
2572
    for ($i = 0; $i < $passwordLength; $i++) {
2573
        $currentCharacterCode = api_ord(api_substr($password, $i, 1));
2574
        if ($currentCharacterCode >= 65 && $currentCharacterCode <= 90) {
2575
            $upperCase++;
2576
        }
2577
2578
        if ($currentCharacterCode >= 97 && $currentCharacterCode <= 122) {
2579
            $lowerCase++;
2580
        }
2581
        if ($currentCharacterCode >= 48 && $currentCharacterCode <= 57) {
2582
            $digits++;
2583
        }
2584
    }
2585
2586
    // Min number of digits
2587
    $conditions['min_numeric'] = $digits >= $minNumbers;
2588
2589
    if (!empty($minUpperCase)) {
2590
        // Uppercase
2591
        $conditions['min_uppercase'] = $upperCase >= $minUpperCase;
2592
    }
2593
2594
    if (!empty($minLowerCase)) {
2595
        // Lowercase
2596
        $conditions['min_lowercase'] = $upperCase >= $minLowerCase;
2597
    }
2598
2599
    // Min letters
2600
    $letters = $upperCase + $lowerCase;
2601
    $conditions['min_letters'] = $letters >= $minLetters;
2602
2603
    $isPasswordOk = true;
2604
    foreach ($conditions as $condition) {
2605
        if (false === $condition) {
2606
            $isPasswordOk = false;
2607
            break;
2608
        }
2609
    }
2610
2611
    if (false === $isPasswordOk) {
2612
        $output = get_lang('The new password does not match the minimum security requirements').'<br />';
2613
        $output .= Security::getPasswordRequirementsToString($conditions);
2614
2615
        Display::addFlash(Display::return_message($output, 'warning', false));
2616
    }
2617
2618
    return $isPasswordOk;
2619
}
2620
2621
/**
2622
 * Returns the status string corresponding to the status code.
2623
 *
2624
 * @author Noel Dieschburg
2625
 *
2626
 * @param the int status code
2627
 *
2628
 * @return string
2629
 */
2630
function get_status_from_code($status_code)
2631
{
2632
    switch ($status_code) {
2633
        case STUDENT:
2634
            return get_lang('Student');
2635
        case COURSEMANAGER:
2636
            return get_lang('Teacher');
2637
        case SESSIONADMIN:
2638
            return get_lang('SessionsAdmin');
2639
        case DRH:
2640
            return get_lang('Drh');
2641
        case ANONYMOUS:
2642
            return get_lang('Anonymous');
2643
        case PLATFORM_ADMIN:
2644
            return get_lang('Administrator');
2645
        case SESSION_COURSE_COACH:
2646
            return get_lang('SessionCourseCoach');
2647
        case SESSION_GENERAL_COACH:
2648
            return get_lang('SessionGeneralCoach');
2649
        case COURSE_TUTOR:
2650
            return get_lang('CourseAssistant');
2651
        case STUDENT_BOSS:
2652
            return get_lang('StudentBoss');
2653
        case INVITEE:
2654
            return get_lang('Invitee');
2655
    }
2656
}
2657
2658
/**
2659
 * Gets the current Chamilo (not PHP/cookie) session ID.
2660
 *
2661
 * @return int O if no active session, the session ID otherwise
2662
 */
2663
function api_get_session_id()
2664
{
2665
    return (int) Session::read('sid', 0);
2666
}
2667
2668
/**
2669
 * Gets the current Chamilo (not social network) group ID.
2670
 *
2671
 * @return int O if no active session, the session ID otherwise
2672
 */
2673
function api_get_group_id()
2674
{
2675
    return Session::read('gid', 0);
2676
}
2677
2678
/**
2679
 * Gets the current or given session name.
2680
 *
2681
 * @param   int     Session ID (optional)
2682
 *
2683
 * @return string The session name, or null if not found
2684
 */
2685
function api_get_session_name($session_id = 0)
2686
{
2687
    if (empty($session_id)) {
2688
        $session_id = api_get_session_id();
2689
        if (empty($session_id)) {
2690
            return null;
2691
        }
2692
    }
2693
    $t = Database::get_main_table(TABLE_MAIN_SESSION);
2694
    $s = "SELECT name FROM $t WHERE id = ".(int) $session_id;
2695
    $r = Database::query($s);
2696
    $c = Database::num_rows($r);
2697
    if ($c > 0) {
2698
        //technically, there can be only one, but anyway we take the first
2699
        $rec = Database::fetch_array($r);
2700
2701
        return $rec['name'];
2702
    }
2703
2704
    return null;
2705
}
2706
2707
/**
2708
 * Gets the session info by id.
2709
 *
2710
 * @param int $id Session ID
2711
 *
2712
 * @return array information of the session
2713
 */
2714
function api_get_session_info($id)
2715
{
2716
    return SessionManager::fetch($id);
2717
}
2718
2719
/**
2720
 * Gets the session visibility by session id.
2721
 *
2722
 * @param int  $session_id
2723
 * @param int  $courseId
2724
 * @param bool $ignore_visibility_for_admins
2725
 *
2726
 * @return int
2727
 *             0 = session still available,
2728
 *             SESSION_VISIBLE_READ_ONLY = 1,
2729
 *             SESSION_VISIBLE = 2,
2730
 *             SESSION_INVISIBLE = 3
2731
 */
2732
function api_get_session_visibility(
2733
    $session_id,
2734
    $courseId = null,
2735
    $ignore_visibility_for_admins = true
2736
) {
2737
    if (api_is_platform_admin()) {
2738
        if ($ignore_visibility_for_admins) {
2739
            return SESSION_AVAILABLE;
2740
        }
2741
    }
2742
2743
    $now = time();
2744
    if (empty($session_id)) {
2745
        return 0; // Means that the session is still available.
2746
    }
2747
2748
    $session_id = (int) $session_id;
2749
    $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
2750
2751
    $result = Database::query("SELECT * FROM $tbl_session WHERE id = $session_id");
2752
2753
    if (Database::num_rows($result) <= 0) {
2754
        return SESSION_INVISIBLE;
2755
    }
2756
2757
    $row = Database::fetch_array($result, 'ASSOC');
2758
    $visibility = $row['visibility'];
2759
2760
    // I don't care the session visibility.
2761
    if (empty($row['access_start_date']) && empty($row['access_end_date'])) {
2762
        // Session duration per student.
2763
        if (isset($row['duration']) && !empty($row['duration'])) {
2764
            $duration = $row['duration'] * 24 * 60 * 60;
2765
            $courseAccess = CourseManager::getFirstCourseAccessPerSessionAndUser($session_id, api_get_user_id());
2766
2767
            // If there is a session duration but there is no previous
2768
            // access by the user, then the session is still available
2769
            if (0 == count($courseAccess)) {
2770
                return SESSION_AVAILABLE;
2771
            }
2772
2773
            $currentTime = time();
2774
            $firstAccess = isset($courseAccess['login_course_date'])
2775
                ? api_strtotime($courseAccess['login_course_date'], 'UTC')
2776
                : 0;
2777
            $userDurationData = SessionManager::getUserSession(
2778
                api_get_user_id(),
2779
                $session_id
2780
            );
2781
            $userDuration = isset($userDurationData['duration'])
2782
                ? (intval($userDurationData['duration']) * 24 * 60 * 60)
2783
                : 0;
2784
2785
            $totalDuration = $firstAccess + $duration + $userDuration;
2786
2787
            return $totalDuration > $currentTime ? SESSION_AVAILABLE : SESSION_VISIBLE_READ_ONLY;
2788
        }
2789
2790
        return SESSION_AVAILABLE;
2791
    }
2792
2793
    // If start date was set.
2794
    if (!empty($row['access_start_date'])) {
2795
        $visibility = $now > api_strtotime($row['access_start_date'], 'UTC') ? SESSION_AVAILABLE : SESSION_INVISIBLE;
2796
    }
2797
2798
    // If the end date was set.
2799
    if (!empty($row['access_end_date'])) {
2800
        // Only if date_start said that it was ok
2801
        if (SESSION_AVAILABLE === $visibility) {
2802
            $visibility = $now < api_strtotime($row['access_end_date'], 'UTC')
2803
                ? SESSION_AVAILABLE // Date still available
2804
                : $row['visibility']; // Session ends
2805
        }
2806
    }
2807
2808
    // If I'm a coach the visibility can change in my favor depending in the coach dates.
2809
    $isCoach = api_is_coach($session_id, $courseId);
2810
2811
    if ($isCoach) {
2812
        // Test start date.
2813
        if (!empty($row['coach_access_start_date'])) {
2814
            $start = api_strtotime($row['coach_access_start_date'], 'UTC');
2815
            $visibility = $start < $now ? SESSION_AVAILABLE : SESSION_INVISIBLE;
2816
        }
2817
2818
        // Test end date.
2819
        if (!empty($row['coach_access_end_date'])) {
2820
            if (SESSION_AVAILABLE === $visibility) {
2821
                $endDateCoach = api_strtotime($row['coach_access_end_date'], 'UTC');
2822
                $visibility = $endDateCoach >= $now ? SESSION_AVAILABLE : $row['visibility'];
2823
            }
2824
        }
2825
    }
2826
2827
    return $visibility;
2828
}
2829
2830
/**
2831
 * This function returns a (star) session icon if the session is not null and
2832
 * the user is not a student.
2833
 *
2834
 * @param int $sessionId
2835
 * @param int $statusId  User status id - if 5 (student), will return empty
2836
 *
2837
 * @return string Session icon
2838
 */
2839
function api_get_session_image($sessionId, $statusId)
2840
{
2841
    $sessionId = (int) $sessionId;
2842
    $image = '';
2843
    if (STUDENT != $statusId) {
2844
        // Check whether is not a student
2845
        if ($sessionId > 0) {
2846
            $image = '&nbsp;&nbsp;'.Display::return_icon(
2847
                'star.png',
2848
                get_lang('Session-specific resource'),
2849
                ['align' => 'absmiddle'],
2850
                ICON_SIZE_SMALL
2851
            );
2852
        }
2853
    }
2854
2855
    return $image;
2856
}
2857
2858
/**
2859
 * This function add an additional condition according to the session of the course.
2860
 *
2861
 * @param int    $session_id        session id
2862
 * @param bool   $and               optional, true if more than one condition false if the only condition in the query
2863
 * @param bool   $with_base_content optional, true to accept content with session=0 as well,
2864
 *                                  false for strict session condition
2865
 * @param string $session_field
2866
 *
2867
 * @return string condition of the session
2868
 */
2869
function api_get_session_condition(
2870
    $session_id,
2871
    $and = true,
2872
    $with_base_content = false,
2873
    $session_field = 'session_id'
2874
) {
2875
    $session_id = (int) $session_id;
2876
2877
    if (empty($session_field)) {
2878
        $session_field = 'session_id';
2879
    }
2880
    // Condition to show resources by session
2881
    $condition_add = $and ? ' AND ' : ' WHERE ';
2882
2883
    if ($with_base_content) {
2884
        $condition_session = $condition_add." ( $session_field = $session_id OR $session_field = 0 OR $session_field IS NULL) ";
2885
    } else {
2886
        if (empty($session_id)) {
2887
            $condition_session = $condition_add." ($session_field = $session_id OR $session_field IS NULL)";
2888
        } else {
2889
            $condition_session = $condition_add." $session_field = $session_id ";
2890
        }
2891
    }
2892
2893
    return $condition_session;
2894
}
2895
2896
/**
2897
 * Returns the value of a setting from the web-adjustable admin config settings.
2898
 *
2899
 * WARNING true/false are stored as string, so when comparing you need to check e.g.
2900
 * if (api_get_setting('show_navigation_menu') == 'true') //CORRECT
2901
 * instead of
2902
 * if (api_get_setting('show_navigation_menu') == true) //INCORRECT
2903
 *
2904
 * @param string $variable The variable name
2905
 *
2906
 * @return string|array
2907
 */
2908
function api_get_setting($variable)
2909
{
2910
    $settingsManager = Container::getSettingsManager();
2911
    if (empty($settingsManager)) {
2912
        return '';
2913
    }
2914
    $variable = trim($variable);
2915
2916
    switch ($variable) {
2917
        /*case 'header_extra_content':
2918
            $filename = api_get_path(SYS_PATH).api_get_home_path().'header_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 'footer_extra_content':
2928
            $filename = api_get_path(SYS_PATH).api_get_home_path().'footer_extra_content.txt';
2929
            if (file_exists($filename)) {
2930
                $value = file_get_contents($filename);
2931
2932
                return $value;
2933
            } else {
2934
                return '';
2935
            }
2936
            break;*/
2937
        case 'server_type':
2938
            $test = ['dev', 'test'];
2939
            $environment = Container::getEnvironment();
2940
            if (in_array($environment, $test)) {
2941
                return 'test';
2942
            }
2943
2944
            return 'prod';
2945
        case 'stylesheets':
2946
            $variable = 'platform.theme';
2947
        // deprecated settings
2948
        // no break
2949
        case 'openid_authentication':
2950
        case 'service_ppt2lp':
2951
        case 'formLogin_hide_unhide_label':
2952
            return false;
2953
            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...
2954
        case 'tool_visible_by_default_at_creation':
2955
            $values = $settingsManager->getSetting($variable);
2956
            $newResult = [];
2957
            foreach ($values as $parameter) {
2958
                $newResult[$parameter] = 'true';
2959
            }
2960
2961
            return $newResult;
2962
            break;
2963
        default:
2964
            return $settingsManager->getSetting($variable);
2965
            break;
2966
    }
2967
}
2968
2969
/**
2970
 * @param string $variable
2971
 * @param string $option
2972
 *
2973
 * @return bool
2974
 */
2975
function api_get_setting_in_list($variable, $option)
2976
{
2977
    $value = api_get_setting($variable);
2978
2979
    return in_array($option, $value);
2980
}
2981
2982
/**
2983
 * @param string $plugin
2984
 * @param string $variable
2985
 *
2986
 * @return string
2987
 */
2988
function api_get_plugin_setting($plugin, $variable)
2989
{
2990
    $variableName = $plugin.'_'.$variable;
2991
    //$result = api_get_setting($variableName);
2992
    $params = [
2993
        'category = ? AND subkey = ? AND variable = ?' => [
2994
            'Plugins',
2995
            $plugin,
2996
            $variableName,
2997
        ],
2998
    ];
2999
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
3000
    $result = Database::select(
3001
        'selected_value',
3002
        $table,
3003
        ['where' => $params],
3004
        'one'
3005
    );
3006
    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...
3007
        $value = $result['selected_value'];
3008
        $serializedValue = @unserialize($result['selected_value'], []);
3009
        if (false !== $serializedValue) {
3010
            $value = $serializedValue;
3011
        }
3012
3013
        return $value;
3014
    }
3015
3016
    return null;
3017
    /// Old code
3018
3019
    $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...
3020
    $result = api_get_setting($variableName);
3021
3022
    if (isset($result[$plugin])) {
3023
        $value = $result[$plugin];
3024
3025
        $unserialized = UnserializeApi::unserialize('not_allowed_classes', $value, true);
3026
3027
        if (false !== $unserialized) {
3028
            $value = $unserialized;
3029
        }
3030
3031
        return $value;
3032
    }
3033
3034
    return null;
3035
}
3036
3037
/**
3038
 * Returns the value of a setting from the web-adjustable admin config settings.
3039
 */
3040
function api_get_settings_params($params)
3041
{
3042
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
3043
    $result = Database::select('*', $table, ['where' => $params]);
3044
3045
    return $result;
3046
}
3047
3048
/**
3049
 * @param array $params example: [id = ? => '1']
3050
 *
3051
 * @return array
3052
 */
3053
function api_get_settings_params_simple($params)
3054
{
3055
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
3056
    $result = Database::select('*', $table, ['where' => $params], 'one');
3057
3058
    return $result;
3059
}
3060
3061
/**
3062
 * Returns the value of a setting from the web-adjustable admin config settings.
3063
 */
3064
function api_delete_settings_params($params)
3065
{
3066
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
3067
    $result = Database::delete($table, $params);
3068
3069
    return $result;
3070
}
3071
3072
/**
3073
 * Returns an escaped version of $_SERVER['PHP_SELF'] to avoid XSS injection.
3074
 *
3075
 * @return string Escaped version of $_SERVER['PHP_SELF']
3076
 */
3077
function api_get_self()
3078
{
3079
    return htmlentities($_SERVER['PHP_SELF']);
3080
}
3081
3082
/* USER PERMISSIONS */
3083
3084
/**
3085
 * Checks whether current user is a platform administrator.
3086
 *
3087
 * @param bool $allowSessionAdmins Whether session admins should be considered admins or not
3088
 * @param bool $allowDrh           Whether HR directors should be considered admins or not
3089
 *
3090
 * @return bool true if the user has platform admin rights,
3091
 *              false otherwise
3092
 *
3093
 * @see usermanager::is_admin(user_id) for a user-id specific function
3094
 */
3095
function api_is_platform_admin($allowSessionAdmins = false, $allowDrh = false)
3096
{
3097
    $currentUser = api_get_current_user();
3098
3099
    if (null === $currentUser) {
3100
        return false;
3101
    }
3102
3103
    $isAdmin = Session::read('is_platformAdmin');
3104
    if ($isAdmin) {
3105
        return true;
3106
    }
3107
    $user = api_get_user_info();
3108
3109
    return
3110
        isset($user['status']) &&
3111
        (
3112
            ($allowSessionAdmins && SESSIONADMIN == $user['status']) ||
3113
            ($allowDrh && DRH == $user['status'])
3114
        );
3115
}
3116
3117
/**
3118
 * Checks whether the user given as user id is in the admin table.
3119
 *
3120
 * @param int $user_id If none provided, will use current user
3121
 * @param int $url     URL ID. If provided, also check if the user is active on given URL
3122
 *
3123
 * @return bool True if the user is admin, false otherwise
3124
 */
3125
function api_is_platform_admin_by_id($user_id = null, $url = null)
3126
{
3127
    $user_id = (int) $user_id;
3128
    if (empty($user_id)) {
3129
        $user_id = api_get_user_id();
3130
    }
3131
    $admin_table = Database::get_main_table(TABLE_MAIN_ADMIN);
3132
    $sql = "SELECT * FROM $admin_table WHERE user_id = $user_id";
3133
    $res = Database::query($sql);
3134
    $is_admin = 1 === Database::num_rows($res);
3135
    if (!$is_admin || !isset($url)) {
3136
        return $is_admin;
3137
    }
3138
    // We get here only if $url is set
3139
    $url = (int) $url;
3140
    $url_user_table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
3141
    $sql = "SELECT * FROM $url_user_table
3142
            WHERE access_url_id = $url AND user_id = $user_id";
3143
    $res = Database::query($sql);
3144
    $result = 1 === Database::num_rows($res);
3145
3146
    return $result;
3147
}
3148
3149
/**
3150
 * Returns the user's numeric status ID from the users table.
3151
 *
3152
 * @param int $user_id If none provided, will use current user
3153
 *
3154
 * @return int User's status (1 for teacher, 5 for student, etc)
3155
 */
3156
function api_get_user_status($user_id = null)
3157
{
3158
    $user_id = (int) $user_id;
3159
    if (empty($user_id)) {
3160
        $user_id = api_get_user_id();
3161
    }
3162
    $table = Database::get_main_table(TABLE_MAIN_USER);
3163
    $sql = "SELECT status FROM $table WHERE id = $user_id ";
3164
    $result = Database::query($sql);
3165
    $status = null;
3166
    if (Database::num_rows($result)) {
3167
        $row = Database::fetch_array($result);
3168
        $status = $row['status'];
3169
    }
3170
3171
    return $status;
3172
}
3173
3174
/**
3175
 * Checks whether current user is allowed to create courses.
3176
 *
3177
 * @return bool true if the user has course creation rights,
3178
 *              false otherwise
3179
 */
3180
function api_is_allowed_to_create_course()
3181
{
3182
    if (api_is_platform_admin()) {
3183
        return true;
3184
    }
3185
3186
    // Teachers can only create courses
3187
    if (api_is_teacher()) {
3188
        if ('true' === api_get_setting('allow_users_to_create_courses')) {
3189
            return true;
3190
        } else {
3191
            return false;
3192
        }
3193
    }
3194
3195
    return Session::read('is_allowedCreateCourse');
3196
}
3197
3198
/**
3199
 * Checks whether the current user is a course administrator.
3200
 *
3201
 * @return bool True if current user is a course administrator
3202
 */
3203
function api_is_course_admin()
3204
{
3205
    if (api_is_platform_admin()) {
3206
        return true;
3207
    }
3208
3209
    $user = api_get_current_user();
3210
    if ($user) {
3211
        if (
3212
            $user->hasRole('ROLE_CURRENT_COURSE_SESSION_TEACHER') ||
3213
            $user->hasRole('ROLE_CURRENT_COURSE_TEACHER')
3214
        ) {
3215
            return true;
3216
        }
3217
    }
3218
3219
    return false;
3220
    //return Session::read('is_courseAdmin');
3221
}
3222
3223
/**
3224
 * Checks whether the current user is a course coach
3225
 * Based on the presence of user in session.id_coach (session general coach).
3226
 *
3227
 * @return bool True if current user is a course coach
3228
 */
3229
function api_is_session_general_coach()
3230
{
3231
    return Session::read('is_session_general_coach');
3232
}
3233
3234
/**
3235
 * Checks whether the current user is a course tutor
3236
 * Based on the presence of user in session_rel_course_rel_user.user_id with status = 2.
3237
 *
3238
 * @return bool True if current user is a course tutor
3239
 */
3240
function api_is_course_tutor()
3241
{
3242
    return Session::read('is_courseTutor');
3243
}
3244
3245
/**
3246
 * @param int $user_id
3247
 * @param int $courseId
3248
 * @param int $session_id
3249
 *
3250
 * @return bool
3251
 */
3252
function api_is_course_session_coach($user_id, $courseId, $session_id)
3253
{
3254
    $session_table = Database::get_main_table(TABLE_MAIN_SESSION);
3255
    $session_rel_course_rel_user_table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3256
3257
    $user_id = (int) $user_id;
3258
    $session_id = (int) $session_id;
3259
    $courseId = (int) $courseId;
3260
3261
    $sql = "SELECT DISTINCT session.id
3262
            FROM $session_table
3263
            INNER JOIN $session_rel_course_rel_user_table session_rc_ru
3264
            ON session.id = session_rc_ru.session_id
3265
            WHERE
3266
                session_rc_ru.user_id = '".$user_id."'  AND
3267
                session_rc_ru.c_id = '$courseId' AND
3268
                session_rc_ru.status = 2 AND
3269
                session_rc_ru.session_id = '$session_id'";
3270
    $result = Database::query($sql);
3271
3272
    return Database::num_rows($result) > 0;
3273
}
3274
3275
/**
3276
 * Checks whether the current user is a course or session coach.
3277
 *
3278
 * @param int $session_id
3279
 * @param int $courseId
3280
 * @param bool  Check whether we are in student view and, if we are, return false
3281
 *
3282
 * @return bool True if current user is a course or session coach
3283
 */
3284
function api_is_coach($session_id = 0, $courseId = null, $check_student_view = true)
3285
{
3286
    $userId = api_get_user_id();
3287
3288
    if (!empty($session_id)) {
3289
        $session_id = (int) $session_id;
3290
    } else {
3291
        $session_id = api_get_session_id();
3292
    }
3293
3294
    // The student preview was on
3295
    if ($check_student_view && api_is_student_view_active()) {
3296
        return false;
3297
    }
3298
3299
    if (!empty($courseId)) {
3300
        $courseId = (int) $courseId;
3301
    } else {
3302
        $courseId = api_get_course_int_id();
3303
    }
3304
3305
    $session_table = Database::get_main_table(TABLE_MAIN_SESSION);
3306
    $session_rel_course_rel_user_table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3307
    $sessionIsCoach = [];
3308
3309
    if (!empty($courseId)) {
3310
        $sql = "SELECT DISTINCT s.id, name, access_start_date, access_end_date
3311
                FROM $session_table s
3312
                INNER JOIN $session_rel_course_rel_user_table session_rc_ru
3313
                ON session_rc_ru.session_id = s.id AND session_rc_ru.user_id = '".$userId."'
3314
                WHERE
3315
                    session_rc_ru.c_id = '$courseId' AND
3316
                    session_rc_ru.status = 2 AND
3317
                    session_rc_ru.session_id = '$session_id'";
3318
        $result = Database::query($sql);
3319
        $sessionIsCoach = Database::store_result($result);
3320
    }
3321
3322
    if (!empty($session_id)) {
3323
        $sql = "SELECT DISTINCT id, name, access_start_date, access_end_date
3324
                FROM $session_table
3325
                WHERE session.id_coach = $userId AND id = $session_id
3326
                ORDER BY access_start_date, access_end_date, name";
3327
        $result = Database::query($sql);
3328
        if (!empty($sessionIsCoach)) {
3329
            $sessionIsCoach = array_merge(
3330
                $sessionIsCoach,
3331
                Database::store_result($result)
3332
            );
3333
        } else {
3334
            $sessionIsCoach = Database::store_result($result);
3335
        }
3336
    }
3337
3338
    return count($sessionIsCoach) > 0;
3339
}
3340
3341
/**
3342
 * Checks whether the current user is a session administrator.
3343
 *
3344
 * @return bool True if current user is a course administrator
3345
 */
3346
function api_is_session_admin()
3347
{
3348
    $user = api_get_user_info();
3349
3350
    return isset($user['status']) && SESSIONADMIN == $user['status'];
3351
}
3352
3353
/**
3354
 * Checks whether the current user is a human resources manager.
3355
 *
3356
 * @return bool True if current user is a human resources manager
3357
 */
3358
function api_is_drh()
3359
{
3360
    $user = api_get_user_info();
3361
3362
    return isset($user['status']) && DRH == $user['status'];
3363
}
3364
3365
/**
3366
 * Checks whether the current user is a student.
3367
 *
3368
 * @return bool True if current user is a human resources manager
3369
 */
3370
function api_is_student()
3371
{
3372
    $user = api_get_user_info();
3373
3374
    return isset($user['status']) && STUDENT == $user['status'];
3375
}
3376
3377
/**
3378
 * Checks whether the current user has the status 'teacher'.
3379
 *
3380
 * @return bool True if current user is a human resources manager
3381
 */
3382
function api_is_teacher()
3383
{
3384
    $user = api_get_user_info();
3385
3386
    return isset($user['status']) && COURSEMANAGER == $user['status'];
3387
}
3388
3389
/**
3390
 * Checks whether the current user is a invited user.
3391
 *
3392
 * @return bool
3393
 */
3394
function api_is_invitee()
3395
{
3396
    $user = api_get_user_info();
3397
3398
    return isset($user['status']) && INVITEE == $user['status'];
3399
}
3400
3401
/**
3402
 * Displays the title of a tool.
3403
 * Normal use: parameter is a string:
3404
 * api_display_tool_title("My Tool").
3405
 *
3406
 * Optionally, there can be a subtitle below
3407
 * the normal title, and / or a supra title above the normal title.
3408
 *
3409
 * e.g. supra title:
3410
 * group
3411
 * GROUP PROPERTIES
3412
 *
3413
 * e.g. subtitle:
3414
 * AGENDA
3415
 * calender & events tool
3416
 *
3417
 * @author Hugues Peeters <[email protected]>
3418
 *
3419
 * @param mixed $title_element - it could either be a string or an array
3420
 *                             containing 'supraTitle', 'mainTitle',
3421
 *                             'subTitle'
3422
 */
3423
function api_display_tool_title($title_element)
3424
{
3425
    if (is_string($title_element)) {
3426
        $tit = $title_element;
3427
        unset($title_element);
3428
        $title_element = [];
3429
        $title_element['mainTitle'] = $tit;
3430
    }
3431
    echo '<h3>';
3432
    if (!empty($title_element['supraTitle'])) {
3433
        echo '<small>'.$title_element['supraTitle'].'</small><br />';
3434
    }
3435
    if (!empty($title_element['mainTitle'])) {
3436
        echo $title_element['mainTitle'];
3437
    }
3438
    if (!empty($title_element['subTitle'])) {
3439
        echo '<br /><small>'.$title_element['subTitle'].'</small>';
3440
    }
3441
    echo '</h3>';
3442
}
3443
3444
/**
3445
 * Displays options for switching between student view and course manager view.
3446
 *
3447
 * Changes in version 1.2 (Patrick Cool)
3448
 * Student view switch now behaves as a real switch. It maintains its current state until the state
3449
 * is changed explicitly
3450
 *
3451
 * Changes in version 1.1 (Patrick Cool)
3452
 * student view now works correctly in subfolders of the document tool
3453
 * student view works correctly in the new links tool
3454
 *
3455
 * Example code for using this in your tools:
3456
 * //if ($is_courseAdmin && api_get_setting('student_view_enabled') == 'true') {
3457
 * //   display_tool_view_option($isStudentView);
3458
 * //}
3459
 * //and in later sections, use api_is_allowed_to_edit()
3460
 *
3461
 * @author Roan Embrechts
3462
 * @author Patrick Cool
3463
 * @author Julio Montoya, changes added in Chamilo
3464
 *
3465
 * @version 1.2
3466
 *
3467
 * @todo rewrite code so it is easier to understand
3468
 */
3469
function api_display_tool_view_option()
3470
{
3471
    if ('true' != api_get_setting('student_view_enabled')) {
3472
        return '';
3473
    }
3474
3475
    $sourceurl = '';
3476
    $is_framed = false;
3477
    // Exceptions apply for all multi-frames pages
3478
    if (false !== strpos($_SERVER['REQUEST_URI'], 'chat/chat_banner.php')) {
3479
        // The chat is a multiframe bit that doesn't work too well with the student_view, so do not show the link
3480
        return '';
3481
    }
3482
3483
    // Uncomment to remove student view link from document view page
3484
    if (false !== strpos($_SERVER['REQUEST_URI'], 'lp/lp_header.php')) {
3485
        if (empty($_GET['lp_id'])) {
3486
            return '';
3487
        }
3488
        $sourceurl = substr($_SERVER['REQUEST_URI'], 0, strpos($_SERVER['REQUEST_URI'], '?'));
3489
        $sourceurl = str_replace(
3490
            'lp/lp_header.php',
3491
            'lp/lp_controller.php?'.api_get_cidreq().'&action=view&lp_id='.intval($_GET['lp_id']).'&isStudentView='.('studentview' == $_SESSION['studentview'] ? 'false' : 'true'),
3492
            $sourceurl
3493
        );
3494
        //showinframes doesn't handle student view anyway...
3495
        //return '';
3496
        $is_framed = true;
3497
    }
3498
3499
    // Check whether the $_SERVER['REQUEST_URI'] contains already url parameters (thus a questionmark)
3500
    if (!$is_framed) {
3501
        if (false === strpos($_SERVER['REQUEST_URI'], '?')) {
3502
            $sourceurl = api_get_self().'?'.api_get_cidreq();
3503
        } else {
3504
            $sourceurl = $_SERVER['REQUEST_URI'];
3505
        }
3506
    }
3507
3508
    $output_string = '';
3509
    if (!empty($_SESSION['studentview'])) {
3510
        if ('studentview' == $_SESSION['studentview']) {
3511
            // We have to remove the isStudentView=true from the $sourceurl
3512
            $sourceurl = str_replace('&isStudentView=true', '', $sourceurl);
3513
            $sourceurl = str_replace('&isStudentView=false', '', $sourceurl);
3514
            $output_string .= '<a class="btn btn-primary btn-sm" href="'.$sourceurl.'&isStudentView=false" target="_self">'.
3515
                Display::returnFontAwesomeIcon('eye').' '.get_lang('Switch to teacher view').'</a>';
3516
        } elseif ('teacherview' == $_SESSION['studentview']) {
3517
            // Switching to teacherview
3518
            $sourceurl = str_replace('&isStudentView=true', '', $sourceurl);
3519
            $sourceurl = str_replace('&isStudentView=false', '', $sourceurl);
3520
            $output_string .= '<a class="btn btn-default btn-sm" href="'.$sourceurl.'&isStudentView=true" target="_self">'.
3521
                Display::returnFontAwesomeIcon('eye').' '.get_lang('Switch to student view').'</a>';
3522
        }
3523
    } else {
3524
        $output_string .= '<a class="btn btn-default btn-sm" href="'.$sourceurl.'&isStudentView=true" target="_self">'.
3525
            Display::returnFontAwesomeIcon('eye').' '.get_lang('Switch to student view').'</a>';
3526
    }
3527
    $output_string = Security::remove_XSS($output_string);
3528
    $html = Display::tag('div', $output_string, ['class' => 'view-options']);
3529
3530
    return $html;
3531
}
3532
3533
// TODO: This is for the permission section.
3534
/**
3535
 * Function that removes the need to directly use is_courseAdmin global in
3536
 * tool scripts. It returns true or false depending on the user's rights in
3537
 * this particular course.
3538
 * Optionally checking for tutor and coach roles here allows us to use the
3539
 * student_view feature altogether with these roles as well.
3540
 *
3541
 * @param bool  Whether to check if the user has the tutor role
3542
 * @param bool  Whether to check if the user has the coach role
3543
 * @param bool  Whether to check if the user has the session coach role
3544
 * @param bool  check the student view or not
3545
 *
3546
 * @author Roan Embrechts
3547
 * @author Patrick Cool
3548
 * @author Julio Montoya
3549
 *
3550
 * @version 1.1, February 2004
3551
 *
3552
 * @return bool true: the user has the rights to edit, false: he does not
3553
 */
3554
function api_is_allowed_to_edit(
3555
    $tutor = false,
3556
    $coach = false,
3557
    $session_coach = false,
3558
    $check_student_view = true
3559
) {
3560
    $allowSessionAdminEdit = true === api_get_setting('session.session_admins_edit_courses_content');
3561
    // Admins can edit anything.
3562
    if (api_is_platform_admin($allowSessionAdminEdit)) {
3563
        //The student preview was on
3564
        if ($check_student_view && api_is_student_view_active()) {
3565
            return false;
3566
        }
3567
3568
        return true;
3569
    }
3570
3571
    $sessionId = api_get_session_id();
3572
3573
    if ($sessionId && api_get_configuration_value('session_courses_read_only_mode')) {
3574
        $efv = new ExtraFieldValue('course');
3575
        $lockExrafieldField = $efv->get_values_by_handler_and_field_variable(
3576
            api_get_course_int_id(),
3577
            'session_courses_read_only_mode'
3578
        );
3579
3580
        if (!empty($lockExrafieldField['value'])) {
3581
            return false;
3582
        }
3583
    }
3584
3585
    $is_allowed_coach_to_edit = api_is_coach(null, null, $check_student_view);
3586
    $session_visibility = api_get_session_visibility($sessionId);
3587
    $is_courseAdmin = api_is_course_admin();
3588
3589
    if (!$is_courseAdmin && $tutor) {
3590
        // If we also want to check if the user is a tutor...
3591
        $is_courseAdmin = $is_courseAdmin || api_is_course_tutor();
3592
    }
3593
3594
    if (!$is_courseAdmin && $coach) {
3595
        // If we also want to check if the user is a coach...';
3596
        // Check if session visibility is read only for coaches.
3597
        if (SESSION_VISIBLE_READ_ONLY == $session_visibility) {
3598
            $is_allowed_coach_to_edit = false;
3599
        }
3600
3601
        if ('true' === api_get_setting('allow_coach_to_edit_course_session')) {
3602
            // Check if coach is allowed to edit a course.
3603
            $is_courseAdmin = $is_courseAdmin || $is_allowed_coach_to_edit;
3604
        }
3605
    }
3606
3607
    if (!$is_courseAdmin && $session_coach) {
3608
        $is_courseAdmin = $is_courseAdmin || $is_allowed_coach_to_edit;
3609
    }
3610
3611
    // Check if the student_view is enabled, and if so, if it is activated.
3612
    if ('true' === api_get_setting('student_view_enabled')) {
3613
        $studentView = api_is_student_view_active();
3614
        if (!empty($sessionId)) {
3615
            // Check if session visibility is read only for coaches.
3616
            if (SESSION_VISIBLE_READ_ONLY == $session_visibility) {
3617
                $is_allowed_coach_to_edit = false;
3618
            }
3619
3620
            $is_allowed = false;
3621
            if ('true' === api_get_setting('allow_coach_to_edit_course_session')) {
3622
                // Check if coach is allowed to edit a course.
3623
                $is_allowed = $is_allowed_coach_to_edit;
3624
            }
3625
            if ($check_student_view) {
3626
                $is_allowed = $is_allowed && false === $studentView;
3627
            }
3628
        } else {
3629
            $is_allowed = $is_courseAdmin;
3630
            if ($check_student_view) {
3631
                $is_allowed = $is_courseAdmin && false === $studentView;
3632
            }
3633
        }
3634
3635
        return $is_allowed;
3636
    } else {
3637
        return $is_courseAdmin;
3638
    }
3639
}
3640
3641
/**
3642
 * Returns true if user is a course coach of at least one course in session.
3643
 *
3644
 * @param int $sessionId
3645
 *
3646
 * @return bool
3647
 */
3648
function api_is_coach_of_course_in_session($sessionId)
3649
{
3650
    if (api_is_platform_admin()) {
3651
        return true;
3652
    }
3653
3654
    $userId = api_get_user_id();
3655
    $courseList = UserManager::get_courses_list_by_session(
3656
        $userId,
3657
        $sessionId
3658
    );
3659
3660
    // Session visibility.
3661
    $visibility = api_get_session_visibility(
3662
        $sessionId,
3663
        null,
3664
        false
3665
    );
3666
3667
    if (SESSION_VISIBLE != $visibility && !empty($courseList)) {
3668
        // Course Coach session visibility.
3669
        $blockedCourseCount = 0;
3670
        $closedVisibilityList = [
3671
            COURSE_VISIBILITY_CLOSED,
3672
            COURSE_VISIBILITY_HIDDEN,
3673
        ];
3674
3675
        foreach ($courseList as $course) {
3676
            // Checking session visibility
3677
            $sessionCourseVisibility = api_get_session_visibility(
3678
                $sessionId,
3679
                $course['real_id']
3680
            );
3681
3682
            $courseIsVisible = !in_array(
3683
                $course['visibility'],
3684
                $closedVisibilityList
3685
            );
3686
            if (false === $courseIsVisible || SESSION_INVISIBLE == $sessionCourseVisibility) {
3687
                $blockedCourseCount++;
3688
            }
3689
        }
3690
3691
        // If all courses are blocked then no show in the list.
3692
        if ($blockedCourseCount === count($courseList)) {
3693
            $visibility = SESSION_INVISIBLE;
3694
        } else {
3695
            $visibility = SESSION_VISIBLE;
3696
        }
3697
    }
3698
3699
    switch ($visibility) {
3700
        case SESSION_VISIBLE_READ_ONLY:
3701
        case SESSION_VISIBLE:
3702
        case SESSION_AVAILABLE:
3703
            return true;
3704
            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...
3705
        case SESSION_INVISIBLE:
3706
            return false;
3707
    }
3708
3709
    return false;
3710
}
3711
3712
/**
3713
 * Checks if a student can edit contents in a session depending
3714
 * on the session visibility.
3715
 *
3716
 * @param bool $tutor Whether to check if the user has the tutor role
3717
 * @param bool $coach Whether to check if the user has the coach role
3718
 *
3719
 * @return bool true: the user has the rights to edit, false: he does not
3720
 */
3721
function api_is_allowed_to_session_edit($tutor = false, $coach = false)
3722
{
3723
    if (api_is_allowed_to_edit($tutor, $coach)) {
3724
        // If I'm a teacher, I will return true in order to not affect the normal behaviour of Chamilo tools.
3725
        return true;
3726
    } else {
3727
        $sessionId = api_get_session_id();
3728
3729
        if (0 == $sessionId) {
3730
            // I'm not in a session so i will return true to not affect the normal behaviour of Chamilo tools.
3731
            return true;
3732
        } else {
3733
            // I'm in a session and I'm a student
3734
            // Get the session visibility
3735
            $session_visibility = api_get_session_visibility($sessionId);
3736
            // if 5 the session is still available
3737
            switch ($session_visibility) {
3738
                case SESSION_VISIBLE_READ_ONLY: // 1
3739
                    return false;
3740
                case SESSION_VISIBLE:           // 2
3741
                    return true;
3742
                case SESSION_INVISIBLE:         // 3
3743
                    return false;
3744
                case SESSION_AVAILABLE:         //5
3745
                    return true;
3746
            }
3747
        }
3748
    }
3749
3750
    return false;
3751
}
3752
3753
/**
3754
 * Checks whether the user is allowed in a specific tool for a specific action.
3755
 *
3756
 * @param string $tool   the tool we are checking if the user has a certain permission
3757
 * @param string $action the action we are checking (add, edit, delete, move, visibility)
3758
 *
3759
 * @return bool
3760
 *
3761
 * @author Patrick Cool <[email protected]>, Ghent University
3762
 * @author Julio Montoya
3763
 *
3764
 * @version 1.0
3765
 */
3766
function api_is_allowed($tool, $action, $task_id = 0)
3767
{
3768
    $_user = api_get_user_info();
3769
    $_course = api_get_course_info();
3770
3771
    if (api_is_course_admin()) {
3772
        return true;
3773
    }
3774
3775
    if (is_array($_course) and count($_course) > 0) {
3776
        require_once api_get_path(SYS_CODE_PATH).'permissions/permissions_functions.inc.php';
3777
3778
        // Getting the permissions of this user.
3779
        if (0 == $task_id) {
3780
            $user_permissions = get_permissions('user', $_user['user_id']);
3781
            $_SESSION['total_permissions'][$_course['code']] = $user_permissions;
3782
        }
3783
3784
        // Getting the permissions of the task.
3785
        if (0 != $task_id) {
3786
            $task_permissions = get_permissions('task', $task_id);
3787
            /* !!! */ $_SESSION['total_permissions'][$_course['code']] = $task_permissions;
3788
        }
3789
    }
3790
3791
    // If the permissions are limited, we have to map the extended ones to the limited ones.
3792
    if ('limited' == api_get_setting('permissions')) {
3793
        if ('Visibility' == $action) {
3794
            $action = 'Edit';
3795
        }
3796
        if ('Move' == $action) {
3797
            $action = 'Edit';
3798
        }
3799
    }
3800
3801
    // The session that contains all the permissions already exists for this course
3802
    // so there is no need to requery everything.
3803
    //my_print_r($_SESSION['total_permissions'][$_course['code']][$tool]);
3804
    if (is_array($_SESSION['total_permissions'][$_course['code']][$tool])) {
3805
        if (in_array($action, $_SESSION['total_permissions'][$_course['code']][$tool])) {
3806
            return true;
3807
        } else {
3808
            return false;
3809
        }
3810
    }
3811
3812
    return false;
3813
}
3814
3815
/**
3816
 * Tells whether this user is an anonymous user.
3817
 *
3818
 * @param int  $user_id  User ID (optional, will take session ID if not provided)
3819
 * @param bool $db_check Whether to check in the database (true) or simply in
3820
 *                       the session (false) to see if the current user is the anonymous user
3821
 *
3822
 * @return bool true if this user is anonymous, false otherwise
3823
 */
3824
function api_is_anonymous($user_id = null, $db_check = false)
3825
{
3826
    return !Container::getAuthorizationChecker()->isGranted('IS_AUTHENTICATED_FULLY');
3827
}
3828
3829
/**
3830
 * Displays message "You are not allowed here..." and exits the entire script.
3831
 *
3832
 * @param bool   $print_headers Whether or not to print headers (default = false -> does not print them)
3833
 * @param string $message
3834
 * @param int    $responseCode
3835
 */
3836
function api_not_allowed(
3837
    $print_headers = false,
3838
    $message = null,
3839
    $responseCode = 0
3840
) {
3841
    throw new Exception('You are not allowed');
3842
}
3843
3844
/**
3845
 * Gets a UNIX timestamp from a database (MySQL) datetime format string.
3846
 *
3847
 * @param $last_post_datetime standard output date in a sql query
3848
 *
3849
 * @return int timestamp
3850
 *
3851
 * @author Toon Van Hoecke <[email protected]>
3852
 *
3853
 * @version October 2003
3854
 * @desc convert sql date to unix timestamp
3855
 */
3856
function convert_sql_date($last_post_datetime)
3857
{
3858
    [$last_post_date, $last_post_time] = explode(' ', $last_post_datetime);
3859
    [$year, $month, $day] = explode('-', $last_post_date);
3860
    [$hour, $min, $sec] = explode(':', $last_post_time);
3861
3862
    return mktime((int) $hour, (int) $min, (int) $sec, (int) $month, (int) $day, (int) $year);
3863
}
3864
3865
/**
3866
 * Displays a combo box so the user can select his/her preferred language.
3867
 *
3868
 * @param string The desired name= value for the select
3869
 * @param bool Whether we use the JQuery Chozen library or not
3870
 * (in some cases, like the indexing language picker, it can alter the presentation)
3871
 *
3872
 * @deprecated
3873
 *
3874
 * @return string
3875
 */
3876
function api_get_languages_combo($name = 'language')
3877
{
3878
    $ret = '';
3879
    $platformLanguage = api_get_setting('platformLanguage');
3880
3881
    // Retrieve a complete list of all the languages.
3882
    $language_list = api_get_languages();
3883
3884
    if (count($language_list) < 2) {
3885
        return $ret;
3886
    }
3887
3888
    // The the current language of the user so that his/her language occurs as selected in the dropdown menu.
3889
    if (isset($_SESSION['user_language_choice'])) {
3890
        $default = $_SESSION['user_language_choice'];
3891
    } else {
3892
        $default = $platformLanguage;
3893
    }
3894
3895
    $ret .= '<select name="'.$name.'" id="language_chosen" class="selectpicker show-tick form-control">';
3896
    foreach ($language_list as $key => $value) {
3897
        if ($key == $default) {
3898
            $selected = ' selected="selected"';
3899
        } else {
3900
            $selected = '';
3901
        }
3902
        $ret .= sprintf('<option value=%s" %s>%s</option>', $key, $selected, $value);
3903
    }
3904
    $ret .= '</select>';
3905
3906
    return $ret;
3907
}
3908
3909
/**
3910
 * Displays a form (drop down menu) so the user can select his/her preferred language.
3911
 * The form works with or without javascript.
3912
 *
3913
 * @param  bool Hide form if only one language available (defaults to false = show the box anyway)
3914
 * @param bool $showAsButton
3915
 *
3916
 * @return string|null Display the box directly
3917
 */
3918
function api_display_language_form($hide_if_no_choice = false, $showAsButton = false)
3919
{
3920
    // Retrieve a complete list of all the languages.
3921
    $language_list = api_get_languages();
3922
    if (count($language_list['name']) <= 1 && $hide_if_no_choice) {
3923
        return; //don't show any form
3924
    }
3925
3926
    // The the current language of the user so that his/her language occurs as selected in the dropdown menu.
3927
    if (isset($_SESSION['user_language_choice'])) {
3928
        $user_selected_language = $_SESSION['user_language_choice'];
3929
    }
3930
    if (empty($user_selected_language)) {
3931
        $user_selected_language = api_get_setting('platformLanguage');
3932
    }
3933
3934
    $currentLanguageId = api_get_language_id($user_selected_language);
3935
    $currentLanguageInfo = api_get_language_info($currentLanguageId);
3936
    $countryCode = languageToCountryIsoCode($currentLanguageInfo['isocode']);
3937
    $url = api_get_self();
3938
    if ($showAsButton) {
3939
        $html = '<div class="btn-group">
3940
              <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
3941
                <span class="flag-icon flag-icon-'.$countryCode.'"></span>
3942
                '.$currentLanguageInfo['original_name'].'
3943
                <span class="caret">
3944
                </span>
3945
              </button>';
3946
    } else {
3947
        $html = '
3948
            <a href="'.$url.'" class="dropdown-toggle" data-toggle="dropdown" role="button">
3949
                <span class="flag-icon flag-icon-'.$countryCode.'"></span>
3950
                '.$currentLanguageInfo['original_name'].'
3951
                <span class="caret"></span>
3952
            </a>
3953
            ';
3954
    }
3955
3956
    $html .= '<ul class="dropdown-menu" role="menu">';
3957
    foreach ($language_list['all'] as $key => $data) {
3958
        $urlLink = $url.'?language='.$data['english_name'];
3959
        $html .= '<li><a href="'.$urlLink.'"><span class="flag-icon flag-icon-'.languageToCountryIsoCode($data['isocode']).'"></span> '.$data['original_name'].'</a></li>';
3960
    }
3961
    $html .= '</ul>';
3962
3963
    if ($showAsButton) {
3964
        $html .= '</div>';
3965
    }
3966
3967
    return $html;
3968
}
3969
3970
/**
3971
 * @param string $languageIsoCode
3972
 *
3973
 * @return string
3974
 */
3975
function languageToCountryIsoCode($languageIsoCode)
3976
{
3977
    $allow = api_get_configuration_value('language_flags_by_country');
3978
3979
    // @todo save in DB
3980
    switch ($languageIsoCode) {
3981
        case 'ar':
3982
            $country = 'ae';
3983
            break;
3984
        case 'bs':
3985
            $country = 'ba';
3986
            break;
3987
        case 'ca':
3988
            $country = 'es';
3989
            if ($allow) {
3990
                $country = 'catalan';
3991
            }
3992
            break;
3993
        case 'cs':
3994
            $country = 'cz';
3995
            break;
3996
        case 'da':
3997
            $country = 'dk';
3998
            break;
3999
        case 'el':
4000
            $country = 'ae';
4001
            break;
4002
        case 'en':
4003
            $country = 'gb';
4004
            break;
4005
        case 'eu': // Euskera
4006
            $country = 'es';
4007
            if ($allow) {
4008
                $country = 'basque';
4009
            }
4010
            break;
4011
        case 'gl': // galego
4012
            $country = 'es';
4013
            if ($allow) {
4014
                $country = 'galician';
4015
            }
4016
            break;
4017
        case 'he':
4018
            $country = 'il';
4019
            break;
4020
        case 'ja':
4021
            $country = 'jp';
4022
            break;
4023
        case 'ka':
4024
            $country = 'ge';
4025
            break;
4026
        case 'ko':
4027
            $country = 'kr';
4028
            break;
4029
        case 'ms':
4030
            $country = 'my';
4031
            break;
4032
        case 'pt-BR':
4033
            $country = 'br';
4034
            break;
4035
        case 'qu':
4036
            $country = 'pe';
4037
            break;
4038
        case 'sl':
4039
            $country = 'si';
4040
            break;
4041
        case 'sv':
4042
            $country = 'se';
4043
            break;
4044
        case 'uk': // Ukraine
4045
            $country = 'ua';
4046
            break;
4047
        case 'zh-TW':
4048
        case 'zh':
4049
            $country = 'cn';
4050
            break;
4051
        default:
4052
            $country = $languageIsoCode;
4053
            break;
4054
    }
4055
    $country = strtolower($country);
4056
4057
    return $country;
4058
}
4059
4060
/**
4061
 * Returns a list of all the languages that are made available by the admin.
4062
 *
4063
 * @return array An array with all languages. Structure of the array is
4064
 *               array['name'] = An array with the name of every language
4065
 *               array['folder'] = An array with the corresponding names of the language-folders in the filesystem
4066
 */
4067
function api_get_languages()
4068
{
4069
    $table = Database::get_main_table(TABLE_MAIN_LANGUAGE);
4070
    $sql = "SELECT * FROM $table WHERE available='1'
4071
            ORDER BY original_name ASC";
4072
    $result = Database::query($sql);
4073
    $languages = [];
4074
    while ($row = Database::fetch_array($result, 'ASSOC')) {
4075
        $languages[$row['isocode']] = $row['original_name'];
4076
    }
4077
4078
    return $languages;
4079
}
4080
4081
/**
4082
 * Returns a list of all the languages that are made available by the admin.
4083
 *
4084
 * @return array
4085
 */
4086
function api_get_languages_to_array()
4087
{
4088
    $tbl_language = Database::get_main_table(TABLE_MAIN_LANGUAGE);
4089
    $sql = "SELECT * FROM $tbl_language WHERE available='1' ORDER BY original_name ASC";
4090
    $result = Database::query($sql);
4091
    $languages = [];
4092
    while ($row = Database::fetch_array($result)) {
4093
        $languages[$row['english_name']] = $row['original_name'];
4094
    }
4095
4096
    return $languages;
4097
}
4098
4099
/**
4100
 * Returns the id (the database id) of a language.
4101
 *
4102
 * @param   string  language name (the corresponding name of the language-folder in the filesystem)
4103
 *
4104
 * @return int id of the language
4105
 */
4106
function api_get_language_id($language)
4107
{
4108
    $tbl_language = Database::get_main_table(TABLE_MAIN_LANGUAGE);
4109
    if (empty($language)) {
4110
        return null;
4111
    }
4112
    $language = Database::escape_string($language);
4113
    $sql = "SELECT id FROM $tbl_language
4114
            WHERE english_name = '$language' LIMIT 1";
4115
    $result = Database::query($sql);
4116
    $row = Database::fetch_array($result);
4117
4118
    return $row['id'];
4119
}
4120
4121
/**
4122
 * Get the language information by its id.
4123
 *
4124
 * @param int $languageId
4125
 *
4126
 * @throws Exception
4127
 *
4128
 * @return array
4129
 */
4130
function api_get_language_info($languageId)
4131
{
4132
    if (empty($languageId)) {
4133
        return [];
4134
    }
4135
4136
    $language = Database::getManager()->find(Language::class, $languageId);
4137
4138
    if (!$language) {
4139
        return [];
4140
    }
4141
4142
    return [
4143
        'id' => $language->getId(),
4144
        'original_name' => $language->getOriginalName(),
4145
        'english_name' => $language->getEnglishName(),
4146
        'isocode' => $language->getIsocode(),
4147
        'available' => $language->getAvailable(),
4148
        'parent_id' => $language->getParent() ? $language->getParent()->getId() : null,
4149
    ];
4150
}
4151
4152
/**
4153
 * @param string $code
4154
 *
4155
 * @return Language
4156
 */
4157
function api_get_language_from_iso($code)
4158
{
4159
    $em = Database::getManager();
4160
4161
    return $em->getRepository(Language::class)->findOneBy(['isocode' => $code]);
4162
}
4163
4164
/**
4165
 * Returns the name of the visual (CSS) theme to be applied on the current page.
4166
 * The returned name depends on the platform, course or user -wide settings.
4167
 *
4168
 * @return string The visual theme's name, it is the name of a folder inside web/css/themes
4169
 */
4170
function api_get_visual_theme()
4171
{
4172
    static $visual_theme;
4173
    if (!isset($visual_theme)) {
4174
        // Get style directly from DB
4175
        /*$styleFromDatabase = api_get_settings_params_simple(
4176
            [
4177
                'variable = ? AND access_url = ?' => [
4178
                    'stylesheets',
4179
                    api_get_current_access_url_id(),
4180
                ],
4181
            ]
4182
        );
4183
4184
        if ($styleFromDatabase) {
4185
            $platform_theme = $styleFromDatabase['selected_value'];
4186
        } else {
4187
            $platform_theme = api_get_setting('stylesheets');
4188
        }*/
4189
        $platform_theme = api_get_setting('stylesheets');
4190
4191
        // Platform's theme.
4192
        $visual_theme = $platform_theme;
4193
        if ('true' == api_get_setting('user_selected_theme')) {
4194
            $user_info = api_get_user_info();
4195
            if (isset($user_info['theme'])) {
4196
                $user_theme = $user_info['theme'];
4197
4198
                if (!empty($user_theme)) {
4199
                    $visual_theme = $user_theme;
4200
                    // User's theme.
4201
                }
4202
            }
4203
        }
4204
4205
        $course_id = api_get_course_id();
4206
        if (!empty($course_id)) {
4207
            if ('true' == api_get_setting('allow_course_theme')) {
4208
                $course_theme = api_get_course_setting('course_theme', $course_id);
4209
4210
                if (!empty($course_theme) && -1 != $course_theme) {
4211
                    if (!empty($course_theme)) {
4212
                        // Course's theme.
4213
                        $visual_theme = $course_theme;
4214
                    }
4215
                }
4216
4217
                $allow_lp_theme = api_get_course_setting('allow_learning_path_theme');
4218
                if (1 == $allow_lp_theme) {
4219
                    /*global $lp_theme_css, $lp_theme_config;
4220
                    // These variables come from the file lp_controller.php.
4221
                    if (!$lp_theme_config) {
4222
                        if (!empty($lp_theme_css)) {
4223
                            // LP's theme.
4224
                            $visual_theme = $lp_theme_css;
4225
                        }
4226
                    }*/
4227
                }
4228
            }
4229
        }
4230
4231
        if (empty($visual_theme)) {
4232
            $visual_theme = 'chamilo';
4233
        }
4234
4235
        /*global $lp_theme_log;
4236
        if ($lp_theme_log) {
4237
            $visual_theme = $platform_theme;
4238
        }*/
4239
    }
4240
4241
    return $visual_theme;
4242
}
4243
4244
/**
4245
 * Returns a list of CSS themes currently available in the CSS folder
4246
 * The folder must have a default.css file.
4247
 *
4248
 * @param bool $getOnlyThemeFromVirtualInstance Used by the vchamilo plugin
4249
 *
4250
 * @return array list of themes directories from the css folder
4251
 *               Note: Directory names (names of themes) in the file system should contain ASCII-characters only
4252
 */
4253
function api_get_themes($getOnlyThemeFromVirtualInstance = false)
4254
{
4255
    // This configuration value is set by the vchamilo plugin
4256
    $virtualTheme = api_get_configuration_value('virtual_css_theme_folder');
4257
4258
    $readCssFolder = function ($dir) use ($virtualTheme) {
4259
        $finder = new Finder();
4260
        $themes = $finder->directories()->in($dir)->depth(0)->sortByName();
4261
        $list = [];
4262
        /** @var Symfony\Component\Finder\SplFileInfo $theme */
4263
        foreach ($themes as $theme) {
4264
            $folder = $theme->getFilename();
4265
            // A theme folder is consider if there's a default.css file
4266
            if (!file_exists($theme->getPathname().'/default.css')) {
4267
                continue;
4268
            }
4269
            $name = ucwords(str_replace('_', ' ', $folder));
4270
            if ($folder == $virtualTheme) {
4271
                continue;
4272
            }
4273
            $list[$folder] = $name;
4274
        }
4275
4276
        return $list;
4277
    };
4278
4279
    $dir = api_get_path(SYS_CSS_PATH).'themes/';
4280
    $list = $readCssFolder($dir);
4281
4282
    if (!empty($virtualTheme)) {
4283
        $newList = $readCssFolder($dir.'/'.$virtualTheme);
4284
        if ($getOnlyThemeFromVirtualInstance) {
4285
            return $newList;
4286
        }
4287
        $list = $list + $newList;
4288
        asort($list);
4289
    }
4290
4291
    return $list;
4292
}
4293
4294
/**
4295
 * Find the largest sort value in a given user_course_category
4296
 * This function is used when we are moving a course to a different category
4297
 * and also when a user subscribes to courses (the new course is added at the end of the main category.
4298
 *
4299
 * @param int $courseCategoryId the id of the user_course_category
4300
 * @param int $userId
4301
 *
4302
 * @return int the value of the highest sort of the user_course_category
4303
 */
4304
function api_max_sort_value($courseCategoryId, $userId)
4305
{
4306
    $user = api_get_user_entity($userId);
4307
    $userCourseCategory = Database::getManager()->getRepository(UserCourseCategory::class)->find($courseCategoryId);
4308
4309
    return null === $user ? 0 : $user->getMaxSortValue($userCourseCategory);
4310
}
4311
4312
/**
4313
 * Transforms a number of seconds in hh:mm:ss format.
4314
 *
4315
 * @author Julian Prud'homme
4316
 *
4317
 * @param int    $seconds      number of seconds
4318
 * @param string $space
4319
 * @param bool   $showSeconds
4320
 * @param bool   $roundMinutes
4321
 *
4322
 * @return string the formatted time
4323
 */
4324
function api_time_to_hms($seconds, $space = ':', $showSeconds = true, $roundMinutes = false)
4325
{
4326
    // $seconds = -1 means that we have wrong data in the db.
4327
    if (-1 == $seconds) {
4328
        return
4329
            get_lang('Unknown').
4330
            Display::return_icon(
4331
                'info2.gif',
4332
                get_lang('The datas about this user were registered when the calculation of time spent on the platform wasn\'t possible.'),
4333
                ['align' => 'absmiddle', 'hspace' => '3px']
4334
            );
4335
    }
4336
4337
    // How many hours ?
4338
    $hours = floor($seconds / 3600);
4339
4340
    // How many minutes ?
4341
    $min = floor(($seconds - ($hours * 3600)) / 60);
4342
4343
    if ($roundMinutes) {
4344
        if ($min >= 45) {
4345
            $min = 45;
4346
        }
4347
4348
        if ($min >= 30 && $min <= 44) {
4349
            $min = 30;
4350
        }
4351
4352
        if ($min >= 15 && $min <= 29) {
4353
            $min = 15;
4354
        }
4355
4356
        if ($min >= 0 && $min <= 14) {
4357
            $min = 0;
4358
        }
4359
    }
4360
4361
    // How many seconds
4362
    $sec = floor($seconds - ($hours * 3600) - ($min * 60));
4363
4364
    if ($hours < 10) {
4365
        $hours = "0$hours";
4366
    }
4367
4368
    if ($sec < 10) {
4369
        $sec = "0$sec";
4370
    }
4371
4372
    if ($min < 10) {
4373
        $min = "0$min";
4374
    }
4375
4376
    $seconds = '';
4377
    if ($showSeconds) {
4378
        $seconds = $space.$sec;
4379
    }
4380
4381
    return $hours.$space.$min.$seconds;
4382
}
4383
4384
/* FILE SYSTEM RELATED FUNCTIONS */
4385
4386
/**
4387
 * Returns the permissions to be assigned to every newly created directory by the web-server.
4388
 * The return value is based on the platform administrator's setting
4389
 * "Administration > Configuration settings > Security > Permissions for new directories".
4390
 *
4391
 * @return int returns the permissions in the format "Owner-Group-Others, Read-Write-Execute", as an integer value
4392
 */
4393
function api_get_permissions_for_new_directories()
4394
{
4395
    static $permissions;
4396
    if (!isset($permissions)) {
4397
        $permissions = trim(api_get_setting('permissions_for_new_directories'));
4398
        // The default value 0777 is according to that in the platform administration panel after fresh system installation.
4399
        $permissions = octdec(!empty($permissions) ? $permissions : '0777');
4400
    }
4401
4402
    return $permissions;
4403
}
4404
4405
/**
4406
 * Returns the permissions to be assigned to every newly created directory by the web-server.
4407
 * The return value is based on the platform administrator's setting
4408
 * "Administration > Configuration settings > Security > Permissions for new files".
4409
 *
4410
 * @return int returns the permissions in the format
4411
 *             "Owner-Group-Others, Read-Write-Execute", as an integer value
4412
 */
4413
function api_get_permissions_for_new_files()
4414
{
4415
    static $permissions;
4416
    if (!isset($permissions)) {
4417
        $permissions = trim(api_get_setting('permissions_for_new_files'));
4418
        // The default value 0666 is according to that in the platform
4419
        // administration panel after fresh system installation.
4420
        $permissions = octdec(!empty($permissions) ? $permissions : '0666');
4421
    }
4422
4423
    return $permissions;
4424
}
4425
4426
/**
4427
 * Deletes a file, or a folder and its contents.
4428
 *
4429
 * @author      Aidan Lister <[email protected]>
4430
 *
4431
 * @version     1.0.3
4432
 *
4433
 * @param string $dirname Directory to delete
4434
 * @param       bool     Deletes only the content or not
4435
 * @param bool $strict if one folder/file fails stop the loop
4436
 *
4437
 * @return bool Returns TRUE on success, FALSE on failure
4438
 *
4439
 * @see http://aidanlister.com/2004/04/recursively-deleting-a-folder-in-php/
4440
 *
4441
 * @author      Yannick Warnier, adaptation for the Chamilo LMS, April, 2008
4442
 * @author      Ivan Tcholakov, a sanity check about Directory class creation has been added, September, 2009
4443
 */
4444
function rmdirr($dirname, $delete_only_content_in_folder = false, $strict = false)
4445
{
4446
    $res = true;
4447
    // A sanity check.
4448
    if (!file_exists($dirname)) {
4449
        return false;
4450
    }
4451
    $php_errormsg = '';
4452
    // Simple delete for a file.
4453
    if (is_file($dirname) || is_link($dirname)) {
4454
        $res = unlink($dirname);
4455
        if (false === $res) {
4456
            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);
4457
        }
4458
4459
        return $res;
4460
    }
4461
4462
    // Loop through the folder.
4463
    $dir = dir($dirname);
4464
    // A sanity check.
4465
    $is_object_dir = is_object($dir);
4466
    if ($is_object_dir) {
4467
        while (false !== $entry = $dir->read()) {
4468
            // Skip pointers.
4469
            if ('.' == $entry || '..' == $entry) {
4470
                continue;
4471
            }
4472
4473
            // Recurse.
4474
            if ($strict) {
4475
                $result = rmdirr("$dirname/$entry");
4476
                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...
4477
                    $res = false;
4478
                    break;
4479
                }
4480
            } else {
4481
                rmdirr("$dirname/$entry");
4482
            }
4483
        }
4484
    }
4485
4486
    // Clean up.
4487
    if ($is_object_dir) {
4488
        $dir->close();
4489
    }
4490
4491
    if (false == $delete_only_content_in_folder) {
4492
        $res = rmdir($dirname);
4493
        if (false === $res) {
4494
            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);
4495
        }
4496
    }
4497
4498
    return $res;
4499
}
4500
4501
// TODO: This function is to be simplified. File access modes to be implemented.
4502
/**
4503
 * function adapted from a php.net comment
4504
 * copy recursively a folder.
4505
 *
4506
 * @param the source folder
4507
 * @param the dest folder
4508
 * @param an array of excluded file_name (without extension)
4509
 * @param copied_files the returned array of copied files
4510
 * @param string $source
4511
 * @param string $dest
4512
 */
4513
function copyr($source, $dest, $exclude = [], $copied_files = [])
4514
{
4515
    if (empty($dest)) {
4516
        return false;
4517
    }
4518
    // Simple copy for a file
4519
    if (is_file($source)) {
4520
        $path_info = pathinfo($source);
4521
        if (!in_array($path_info['filename'], $exclude)) {
4522
            copy($source, $dest);
4523
        }
4524
4525
        return true;
4526
    } elseif (!is_dir($source)) {
4527
        //then source is not a dir nor a file, return
4528
        return false;
4529
    }
4530
4531
    // Make destination directory.
4532
    if (!is_dir($dest)) {
4533
        mkdir($dest, api_get_permissions_for_new_directories());
4534
    }
4535
4536
    // Loop through the folder.
4537
    $dir = dir($source);
4538
    while (false !== $entry = $dir->read()) {
4539
        // Skip pointers
4540
        if ('.' == $entry || '..' == $entry) {
4541
            continue;
4542
        }
4543
4544
        // Deep copy directories.
4545
        if ($dest !== "$source/$entry") {
4546
            $files = copyr("$source/$entry", "$dest/$entry", $exclude, $copied_files);
4547
        }
4548
    }
4549
    // Clean up.
4550
    $dir->close();
4551
4552
    return true;
4553
}
4554
4555
/**
4556
 * @todo: Using DIRECTORY_SEPARATOR is not recommended, this is an obsolete approach.
4557
 * Documentation header to be added here.
4558
 *
4559
 * @param string $pathname
4560
 * @param string $base_path_document
4561
 * @param int    $session_id
4562
 *
4563
 * @return mixed True if directory already exists, false if a file already exists at
4564
 *               the destination and null if everything goes according to plan
4565
 */
4566
function copy_folder_course_session(
4567
    $pathname,
4568
    $base_path_document,
4569
    $session_id,
4570
    $course_info,
4571
    $document,
4572
    $source_course_id
4573
) {
4574
    $table = Database::get_course_table(TABLE_DOCUMENT);
4575
    $session_id = intval($session_id);
4576
    $source_course_id = intval($source_course_id);
4577
4578
    // Check whether directory already exists.
4579
    if (is_dir($pathname) || empty($pathname)) {
4580
        return true;
4581
    }
4582
4583
    // Ensure that a file with the same name does not already exist.
4584
    if (is_file($pathname)) {
4585
        trigger_error('copy_folder_course_session(): File exists', E_USER_WARNING);
4586
4587
        return false;
4588
    }
4589
4590
    $course_id = $course_info['real_id'];
4591
    $folders = explode(DIRECTORY_SEPARATOR, str_replace($base_path_document.DIRECTORY_SEPARATOR, '', $pathname));
4592
    $new_pathname = $base_path_document;
4593
    $path = '';
4594
4595
    foreach ($folders as $folder) {
4596
        $new_pathname .= DIRECTORY_SEPARATOR.$folder;
4597
        $path .= DIRECTORY_SEPARATOR.$folder;
4598
4599
        if (!file_exists($new_pathname)) {
4600
            $path = Database::escape_string($path);
4601
4602
            $sql = "SELECT * FROM $table
4603
                    WHERE
4604
                        c_id = $source_course_id AND
4605
                        path = '$path' AND
4606
                        filetype = 'folder' AND
4607
                        session_id = '$session_id'";
4608
            $rs1 = Database::query($sql);
4609
            $num_rows = Database::num_rows($rs1);
4610
4611
            if (0 == $num_rows) {
4612
                mkdir($new_pathname, api_get_permissions_for_new_directories());
4613
4614
                // Insert new folder with destination session_id.
4615
                $params = [
4616
                    'c_id' => $course_id,
4617
                    'path' => $path,
4618
                    'comment' => $document->comment,
4619
                    'title' => basename($new_pathname),
4620
                    'filetype' => 'folder',
4621
                    'size' => '0',
4622
                    'session_id' => $session_id,
4623
                ];
4624
                Database::insert($table, $params);
4625
            }
4626
        }
4627
    } // en foreach
4628
}
4629
4630
// TODO: chmodr() is a better name. Some corrections are needed. Documentation header to be added here.
4631
/**
4632
 * @param string $path
4633
 */
4634
function api_chmod_R($path, $filemode)
4635
{
4636
    if (!is_dir($path)) {
4637
        return chmod($path, $filemode);
4638
    }
4639
4640
    $handler = opendir($path);
4641
    while ($file = readdir($handler)) {
4642
        if ('.' != $file && '..' != $file) {
4643
            $fullpath = "$path/$file";
4644
            if (!is_dir($fullpath)) {
4645
                if (!chmod($fullpath, $filemode)) {
4646
                    return false;
4647
                }
4648
            } else {
4649
                if (!api_chmod_R($fullpath, $filemode)) {
4650
                    return false;
4651
                }
4652
            }
4653
        }
4654
    }
4655
4656
    closedir($handler);
4657
4658
    return chmod($path, $filemode);
4659
}
4660
4661
// TODO: Where the following function has been copy/pased from? There is no information about author and license. Style, coding conventions...
4662
/**
4663
 * Parse info file format. (e.g: file.info).
4664
 *
4665
 * Files should use an ini-like format to specify values.
4666
 * White-space generally doesn't matter, except inside values.
4667
 * e.g.
4668
 *
4669
 * @verbatim
4670
 *   key = value
4671
 *   key = "value"
4672
 *   key = 'value'
4673
 *   key = "multi-line
4674
 *
4675
 *   value"
4676
 *   key = 'multi-line
4677
 *
4678
 *   value'
4679
 *   key
4680
 *   =
4681
 *   'value'
4682
 * @endverbatim
4683
 *
4684
 * Arrays are created using a GET-like syntax:
4685
 *
4686
 * @verbatim
4687
 *   key[] = "numeric array"
4688
 *   key[index] = "associative array"
4689
 *   key[index][] = "nested numeric array"
4690
 *   key[index][index] = "nested associative array"
4691
 * @endverbatim
4692
 *
4693
 * PHP constants are substituted in, but only when used as the entire value:
4694
 *
4695
 * Comments should start with a semi-colon at the beginning of a line.
4696
 *
4697
 * This function is NOT for placing arbitrary module-specific settings. Use
4698
 * variable_get() and variable_set() for that.
4699
 *
4700
 * Information stored in the module.info file:
4701
 * - name: The real name of the module for display purposes.
4702
 * - description: A brief description of the module.
4703
 * - dependencies: An array of shortnames of other modules this module depends on.
4704
 * - package: The name of the package of modules this module belongs to.
4705
 *
4706
 * Example of .info file:
4707
 * <code>
4708
 * @verbatim
4709
 *   name = Forum
4710
 *   description = Enables threaded discussions about general topics.
4711
 *   dependencies[] = taxonomy
4712
 *   dependencies[] = comment
4713
 *   package = Core - optional
4714
 *   version = VERSION
4715
 * @endverbatim
4716
 * </code>
4717
 *
4718
 * @param string $filename
4719
 *                         The file we are parsing. Accepts file with relative or absolute path.
4720
 *
4721
 * @return
4722
 *   The info array
4723
 */
4724
function api_parse_info_file($filename)
4725
{
4726
    $info = [];
4727
4728
    if (!file_exists($filename)) {
4729
        return $info;
4730
    }
4731
4732
    $data = file_get_contents($filename);
4733
    if (preg_match_all('
4734
        @^\s*                           # Start at the beginning of a line, ignoring leading whitespace
4735
        ((?:
4736
          [^=;\[\]]|                    # Key names cannot contain equal signs, semi-colons or square brackets,
4737
          \[[^\[\]]*\]                  # unless they are balanced and not nested
4738
        )+?)
4739
        \s*=\s*                         # Key/value pairs are separated by equal signs (ignoring white-space)
4740
        (?:
4741
          ("(?:[^"]|(?<=\\\\)")*")|     # Double-quoted string, which may contain slash-escaped quotes/slashes
4742
          (\'(?:[^\']|(?<=\\\\)\')*\')| # Single-quoted string, which may contain slash-escaped quotes/slashes
4743
          ([^\r\n]*?)                   # Non-quoted string
4744
        )\s*$                           # Stop at the next end of a line, ignoring trailing whitespace
4745
        @msx', $data, $matches, PREG_SET_ORDER)) {
4746
        $key = $value1 = $value2 = $value3 = '';
4747
        foreach ($matches as $match) {
4748
            // Fetch the key and value string.
4749
            $i = 0;
4750
            foreach (['key', 'value1', 'value2', 'value3'] as $var) {
4751
                $$var = isset($match[++$i]) ? $match[$i] : '';
4752
            }
4753
            $value = stripslashes(substr($value1, 1, -1)).stripslashes(substr($value2, 1, -1)).$value3;
4754
4755
            // Parse array syntax.
4756
            $keys = preg_split('/\]?\[/', rtrim($key, ']'));
4757
            $last = array_pop($keys);
4758
            $parent = &$info;
4759
4760
            // Create nested arrays.
4761
            foreach ($keys as $key) {
4762
                if ('' == $key) {
4763
                    $key = count($parent);
4764
                }
4765
                if (!isset($parent[$key]) || !is_array($parent[$key])) {
4766
                    $parent[$key] = [];
4767
                }
4768
                $parent = &$parent[$key];
4769
            }
4770
4771
            // Handle PHP constants.
4772
            if (defined($value)) {
4773
                $value = constant($value);
4774
            }
4775
4776
            // Insert actual value.
4777
            if ('' == $last) {
4778
                $last = count($parent);
4779
            }
4780
            $parent[$last] = $value;
4781
        }
4782
    }
4783
4784
    return $info;
4785
}
4786
4787
/**
4788
 * Gets Chamilo version from the configuration files.
4789
 *
4790
 * @return string A string of type "1.8.4", or an empty string if the version could not be found
4791
 */
4792
function api_get_version()
4793
{
4794
    return (string) api_get_configuration_value('system_version');
4795
}
4796
4797
/**
4798
 * Gets the software name (the name/brand of the Chamilo-based customized system).
4799
 *
4800
 * @return string
4801
 */
4802
function api_get_software_name()
4803
{
4804
    $name = api_get_configuration_value('software_name');
4805
    if (!empty($name)) {
4806
        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...
4807
    } else {
4808
        return 'Chamilo';
4809
    }
4810
}
4811
4812
function api_get_status_list()
4813
{
4814
    $list = [];
4815
    // Table of status
4816
    $list[COURSEMANAGER] = 'teacher'; // 1
4817
    $list[SESSIONADMIN] = 'session_admin'; // 3
4818
    $list[DRH] = 'drh'; // 4
4819
    $list[STUDENT] = 'user'; // 5
4820
    $list[ANONYMOUS] = 'anonymous'; // 6
4821
    $list[INVITEE] = 'invited'; // 20
4822
4823
    return $list;
4824
}
4825
4826
/**
4827
 * Checks whether status given in parameter exists in the platform.
4828
 *
4829
 * @param mixed the status (can be either int either string)
4830
 *
4831
 * @return bool if the status exists, else returns false
4832
 */
4833
function api_status_exists($status_asked)
4834
{
4835
    $list = api_get_status_list();
4836
4837
    return in_array($status_asked, $list) ? true : isset($list[$status_asked]);
4838
}
4839
4840
/**
4841
 * Checks whether status given in parameter exists in the platform. The function
4842
 * returns the status ID or false if it does not exist, but given the fact there
4843
 * is no "0" status, the return value can be checked against
4844
 * if(api_status_key()) to know if it exists.
4845
 *
4846
 * @param   mixed   The status (can be either int or string)
4847
 *
4848
 * @return mixed Status ID if exists, false otherwise
4849
 */
4850
function api_status_key($status)
4851
{
4852
    $list = api_get_status_list();
4853
4854
    return isset($list[$status]) ? $status : array_search($status, $list);
4855
}
4856
4857
/**
4858
 * Gets the status langvars list.
4859
 *
4860
 * @return string[] the list of status with their translations
4861
 */
4862
function api_get_status_langvars()
4863
{
4864
    return [
4865
        COURSEMANAGER => get_lang('Teacher'),
4866
        SESSIONADMIN => get_lang('SessionsAdmin'),
4867
        DRH => get_lang('Human Resources Manager'),
4868
        STUDENT => get_lang('Learner'),
4869
        ANONYMOUS => get_lang('Anonymous'),
4870
        STUDENT_BOSS => get_lang('RoleStudentBoss'),
4871
        INVITEE => get_lang('Invited'),
4872
    ];
4873
}
4874
4875
/**
4876
 * The function that retrieves all the possible settings for a certain config setting.
4877
 *
4878
 * @author Patrick Cool <[email protected]>, Ghent University
4879
 */
4880
function api_get_settings_options($var)
4881
{
4882
    $table_settings_options = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
4883
    $var = Database::escape_string($var);
4884
    $sql = "SELECT * FROM $table_settings_options
4885
            WHERE variable = '$var'
4886
            ORDER BY id";
4887
    $result = Database::query($sql);
4888
    $settings_options_array = [];
4889
    while ($row = Database::fetch_array($result, 'ASSOC')) {
4890
        $settings_options_array[] = $row;
4891
    }
4892
4893
    return $settings_options_array;
4894
}
4895
4896
/**
4897
 * @param array $params
4898
 */
4899
function api_set_setting_option($params)
4900
{
4901
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
4902
    if (empty($params['id'])) {
4903
        Database::insert($table, $params);
4904
    } else {
4905
        Database::update($table, $params, ['id = ? ' => $params['id']]);
4906
    }
4907
}
4908
4909
/**
4910
 * @param array $params
4911
 */
4912
function api_set_setting_simple($params)
4913
{
4914
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
4915
    $url_id = api_get_current_access_url_id();
4916
4917
    if (empty($params['id'])) {
4918
        $params['access_url'] = $url_id;
4919
        Database::insert($table, $params);
4920
    } else {
4921
        Database::update($table, $params, ['id = ? ' => [$params['id']]]);
4922
    }
4923
}
4924
4925
/**
4926
 * @param int $id
4927
 */
4928
function api_delete_setting_option($id)
4929
{
4930
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
4931
    if (!empty($id)) {
4932
        Database::delete($table, ['id = ? ' => $id]);
4933
    }
4934
}
4935
4936
/**
4937
 * Sets a platform configuration setting to a given value.
4938
 *
4939
 * @param string    The variable we want to update
4940
 * @param string    The value we want to record
4941
 * @param string    The sub-variable if any (in most cases, this will remain null)
4942
 * @param string    The category if any (in most cases, this will remain null)
4943
 * @param int       The access_url for which this parameter is valid
4944
 * @param string $cat
4945
 *
4946
 * @return bool|null
4947
 */
4948
function api_set_setting($var, $value, $subvar = null, $cat = null, $access_url = 1)
4949
{
4950
    if (empty($var)) {
4951
        return false;
4952
    }
4953
    $t_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
4954
    $var = Database::escape_string($var);
4955
    $value = Database::escape_string($value);
4956
    $access_url = (int) $access_url;
4957
    if (empty($access_url)) {
4958
        $access_url = 1;
4959
    }
4960
    $select = "SELECT id FROM $t_settings WHERE variable = '$var' ";
4961
    if (!empty($subvar)) {
4962
        $subvar = Database::escape_string($subvar);
4963
        $select .= " AND subkey = '$subvar'";
4964
    }
4965
    if (!empty($cat)) {
4966
        $cat = Database::escape_string($cat);
4967
        $select .= " AND category = '$cat'";
4968
    }
4969
    if ($access_url > 1) {
4970
        $select .= " AND access_url = $access_url";
4971
    } else {
4972
        $select .= " AND access_url = 1 ";
4973
    }
4974
4975
    $res = Database::query($select);
4976
    if (Database::num_rows($res) > 0) {
4977
        // Found item for this access_url.
4978
        $row = Database::fetch_array($res);
4979
        $sql = "UPDATE $t_settings SET selected_value = '$value'
4980
                WHERE id = ".$row['id'];
4981
        Database::query($sql);
4982
    } else {
4983
        // Item not found for this access_url, we have to check if it exist with access_url = 1
4984
        $select = "SELECT * FROM $t_settings
4985
                   WHERE variable = '$var' AND access_url = 1 ";
4986
        // Just in case
4987
        if (1 == $access_url) {
4988
            if (!empty($subvar)) {
4989
                $select .= " AND subkey = '$subvar'";
4990
            }
4991
            if (!empty($cat)) {
4992
                $select .= " AND category = '$cat'";
4993
            }
4994
            $res = Database::query($select);
4995
            if (Database::num_rows($res) > 0) {
4996
                // We have a setting for access_url 1, but none for the current one, so create one.
4997
                $row = Database::fetch_array($res);
4998
                $insert = "INSERT INTO $t_settings (variable, subkey, type,category, selected_value, title, comment, scope, subkeytext, access_url)
4999
                        VALUES
5000
                        ('".$row['variable']."',".(!empty($row['subkey']) ? "'".$row['subkey']."'" : "NULL").",".
5001
                    "'".$row['type']."','".$row['category']."',".
5002
                    "'$value','".$row['title']."',".
5003
                    "".(!empty($row['comment']) ? "'".$row['comment']."'" : "NULL").",".(!empty($row['scope']) ? "'".$row['scope']."'" : "NULL").",".
5004
                    "".(!empty($row['subkeytext']) ? "'".$row['subkeytext']."'" : "NULL").",$access_url)";
5005
                Database::query($insert);
5006
            } else {
5007
                // Such a setting does not exist.
5008
                //error_log(__FILE__.':'.__LINE__.': Attempting to update setting '.$var.' ('.$subvar.') which does not exist at all', 0);
5009
            }
5010
        } else {
5011
            // Other access url.
5012
            if (!empty($subvar)) {
5013
                $select .= " AND subkey = '$subvar'";
5014
            }
5015
            if (!empty($cat)) {
5016
                $select .= " AND category = '$cat'";
5017
            }
5018
            $res = Database::query($select);
5019
5020
            if (Database::num_rows($res) > 0) {
5021
                // We have a setting for access_url 1, but none for the current one, so create one.
5022
                $row = Database::fetch_array($res);
5023
                if (1 == $row['access_url_changeable']) {
5024
                    $insert = "INSERT INTO $t_settings (variable,subkey, type,category, selected_value,title, comment,scope, subkeytext,access_url, access_url_changeable) VALUES
5025
                            ('".$row['variable']."',".
5026
                        (!empty($row['subkey']) ? "'".$row['subkey']."'" : "NULL").",".
5027
                        "'".$row['type']."','".$row['category']."',".
5028
                        "'$value','".$row['title']."',".
5029
                        "".(!empty($row['comment']) ? "'".$row['comment']."'" : "NULL").",".
5030
                        (!empty($row['scope']) ? "'".$row['scope']."'" : "NULL").",".
5031
                        "".(!empty($row['subkeytext']) ? "'".$row['subkeytext']."'" : "NULL").",$access_url,".$row['access_url_changeable'].")";
5032
                    Database::query($insert);
5033
                }
5034
            } else { // Such a setting does not exist.
5035
                //error_log(__FILE__.':'.__LINE__.': Attempting to update setting '.$var.' ('.$subvar.') which does not exist at all. The access_url is: '.$access_url.' ',0);
5036
            }
5037
        }
5038
    }
5039
}
5040
5041
/**
5042
 * Sets a whole category of settings to one specific value.
5043
 *
5044
 * @param string    Category
5045
 * @param string    Value
5046
 * @param int       Access URL. Optional. Defaults to 1
5047
 * @param array     Optional array of filters on field type
5048
 * @param string $category
5049
 * @param string $value
5050
 *
5051
 * @return bool
5052
 */
5053
function api_set_settings_category($category, $value = null, $access_url = 1, $fieldtype = [])
5054
{
5055
    if (empty($category)) {
5056
        return false;
5057
    }
5058
    $category = Database::escape_string($category);
5059
    $t_s = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5060
    $access_url = (int) $access_url;
5061
    if (empty($access_url)) {
5062
        $access_url = 1;
5063
    }
5064
    if (isset($value)) {
5065
        $value = Database::escape_string($value);
5066
        $sql = "UPDATE $t_s SET selected_value = '$value'
5067
                WHERE category = '$category' AND access_url = $access_url";
5068
        if (is_array($fieldtype) && count($fieldtype) > 0) {
5069
            $sql .= " AND ( ";
5070
            $i = 0;
5071
            foreach ($fieldtype as $type) {
5072
                if ($i > 0) {
5073
                    $sql .= ' OR ';
5074
                }
5075
                $type = Database::escape_string($type);
5076
                $sql .= " type='".$type."' ";
5077
                $i++;
5078
            }
5079
            $sql .= ")";
5080
        }
5081
        $res = Database::query($sql);
5082
5083
        return false !== $res;
5084
    } else {
5085
        $sql = "UPDATE $t_s SET selected_value = NULL
5086
                WHERE category = '$category' AND access_url = $access_url";
5087
        if (is_array($fieldtype) && count($fieldtype) > 0) {
5088
            $sql .= " AND ( ";
5089
            $i = 0;
5090
            foreach ($fieldtype as $type) {
5091
                if ($i > 0) {
5092
                    $sql .= ' OR ';
5093
                }
5094
                $type = Database::escape_string($type);
5095
                $sql .= " type='".$type."' ";
5096
                $i++;
5097
            }
5098
            $sql .= ")";
5099
        }
5100
        $res = Database::query($sql);
5101
5102
        return false !== $res;
5103
    }
5104
}
5105
5106
/**
5107
 * Gets all available access urls in an array (as in the database).
5108
 *
5109
 * @return array An array of database records
5110
 */
5111
function api_get_access_urls($from = 0, $to = 1000000, $order = 'url', $direction = 'ASC')
5112
{
5113
    $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5114
    $from = (int) $from;
5115
    $to = (int) $to;
5116
    $order = Database::escape_string($order, null, false);
5117
    $direction = Database::escape_string($direction, null, false);
5118
    $sql = "SELECT id, url, description, active, created_by, tms
5119
            FROM $table
5120
            ORDER BY $order $direction
5121
            LIMIT $to OFFSET $from";
5122
    $res = Database::query($sql);
5123
5124
    return Database::store_result($res);
5125
}
5126
5127
/**
5128
 * Gets the access url info in an array.
5129
 *
5130
 * @param int  $id            Id of the access url
5131
 * @param bool $returnDefault Set to false if you want the real URL if URL 1 is still 'http://localhost/'
5132
 *
5133
 * @return array All the info (url, description, active, created_by, tms)
5134
 *               from the access_url table
5135
 *
5136
 * @author Julio Montoya
5137
 */
5138
function api_get_access_url($id, $returnDefault = true)
5139
{
5140
    static $staticResult;
5141
    $id = (int) $id;
5142
5143
    if (isset($staticResult[$id])) {
5144
        $result = $staticResult[$id];
5145
    } else {
5146
        // Calling the Database:: library dont work this is handmade.
5147
        $table_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5148
        $sql = "SELECT url, description, active, created_by, tms
5149
                FROM $table_access_url WHERE id = '$id' ";
5150
        $res = Database::query($sql);
5151
        $result = @Database::fetch_array($res);
5152
        $staticResult[$id] = $result;
5153
    }
5154
5155
    // If the result url is 'http://localhost/' (the default) and the root_web
5156
    // (=current url) is different, and the $id is = 1 (which might mean
5157
    // api_get_current_access_url_id() returned 1 by default), then return the
5158
    // root_web setting instead of the current URL
5159
    // This is provided as an option to avoid breaking the storage of URL-specific
5160
    // homepages in home/localhost/
5161
    if (1 === $id && false === $returnDefault) {
5162
        $currentUrl = api_get_current_access_url_id();
5163
        // only do this if we are on the main URL (=1), otherwise we could get
5164
        // information on another URL instead of the one asked as parameter
5165
        if (1 === $currentUrl) {
5166
            $rootWeb = api_get_path(WEB_PATH);
5167
            $default = 'http://localhost/';
5168
            if ($result['url'] === $default && $rootWeb != $default) {
5169
                $result['url'] = $rootWeb;
5170
            }
5171
        }
5172
    }
5173
5174
    return $result;
5175
}
5176
5177
/**
5178
 * Gets all the current settings for a specific access url.
5179
 *
5180
 * @param string    The category, if any, that we want to get
5181
 * @param string    Whether we want a simple list (display a category) or
5182
 * a grouped list (group by variable as in settings.php default). Values: 'list' or 'group'
5183
 * @param int       Access URL's ID. Optional. Uses 1 by default, which is the unique URL
5184
 *
5185
 * @return array Array of database results for the current settings of the current access URL
5186
 */
5187
function &api_get_settings($cat = null, $ordering = 'list', $access_url = 1, $url_changeable = 0)
5188
{
5189
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5190
    $access_url = (int) $access_url;
5191
    $where_condition = '';
5192
    if (1 == $url_changeable) {
5193
        $where_condition = " AND access_url_changeable= '1' ";
5194
    }
5195
    if (empty($access_url) || -1 == $access_url) {
5196
        $access_url = 1;
5197
    }
5198
    $sql = "SELECT * FROM $table
5199
            WHERE access_url = $access_url  $where_condition ";
5200
5201
    if (!empty($cat)) {
5202
        $cat = Database::escape_string($cat);
5203
        $sql .= " AND category='$cat' ";
5204
    }
5205
    if ('group' == $ordering) {
5206
        $sql .= " ORDER BY id ASC";
5207
    } else {
5208
        $sql .= " ORDER BY 1,2 ASC";
5209
    }
5210
    $result = Database::query($sql);
5211
    if (null === $result) {
5212
        return [];
5213
    }
5214
    $result = Database::store_result($result, 'ASSOC');
5215
5216
    return $result;
5217
}
5218
5219
/**
5220
 * @param string $value       The value we want to record
5221
 * @param string $variable    The variable name we want to insert
5222
 * @param string $subKey      The subkey for the variable we want to insert
5223
 * @param string $type        The type for the variable we want to insert
5224
 * @param string $category    The category for the variable we want to insert
5225
 * @param string $title       The title
5226
 * @param string $comment     The comment
5227
 * @param string $scope       The scope
5228
 * @param string $subKeyText  The subkey text
5229
 * @param int    $accessUrlId The access_url for which this parameter is valid
5230
 * @param int    $visibility  The changeability of this setting for non-master urls
5231
 *
5232
 * @return int The setting ID
5233
 */
5234
function api_add_setting(
5235
    $value,
5236
    $variable,
5237
    $subKey = '',
5238
    $type = 'textfield',
5239
    $category = '',
5240
    $title = '',
5241
    $comment = '',
5242
    $scope = '',
5243
    $subKeyText = '',
5244
    $accessUrlId = 1,
5245
    $visibility = 0
5246
) {
5247
    $em = Database::getManager();
5248
5249
    $settingRepo = $em->getRepository(SettingsCurrent::class);
5250
    $accessUrlId = (int) $accessUrlId ?: 1;
5251
5252
    if (is_array($value)) {
5253
        $value = serialize($value);
5254
    } else {
5255
        $value = trim($value);
5256
    }
5257
5258
    $criteria = ['variable' => $variable, 'url' => $accessUrlId];
5259
5260
    if (!empty($subKey)) {
5261
        $criteria['subkey'] = $subKey;
5262
    }
5263
5264
    // Check if this variable doesn't exist already
5265
    /** @var SettingsCurrent $setting */
5266
    $setting = $settingRepo->findOneBy($criteria);
5267
5268
    if ($setting) {
0 ignored issues
show
introduced by
$setting is of type Chamilo\CoreBundle\Entity\SettingsCurrent, thus it always evaluated to true.
Loading history...
5269
        $setting->setSelectedValue($value);
5270
5271
        $em->persist($setting);
5272
        $em->flush();
5273
5274
        return $setting->getId();
5275
    }
5276
5277
    // Item not found for this access_url, we have to check if the whole thing is missing
5278
    // (in which case we ignore the insert) or if there *is* a record but just for access_url = 1
5279
    $setting = new SettingsCurrent();
5280
    $url = api_get_url_entity();
5281
5282
    $setting
5283
        ->setVariable($variable)
5284
        ->setSelectedValue($value)
5285
        ->setType($type)
5286
        ->setCategory($category)
5287
        ->setSubkey($subKey)
5288
        ->setTitle($title)
5289
        ->setComment($comment)
5290
        ->setScope($scope)
5291
        ->setSubkeytext($subKeyText)
5292
        ->setUrl(api_get_url_entity())
5293
        ->setAccessUrlChangeable($visibility);
5294
5295
    $em->persist($setting);
5296
    $em->flush();
5297
5298
    return $setting->getId();
5299
}
5300
5301
/**
5302
 * Checks wether a user can or can't view the contents of a course.
5303
 *
5304
 * @deprecated use CourseManager::is_user_subscribed_in_course
5305
 *
5306
 * @param int $userid User id or NULL to get it from $_SESSION
5307
 * @param int $cid    course id to check whether the user is allowed
5308
 *
5309
 * @return bool
5310
 */
5311
function api_is_course_visible_for_user($userid = null, $cid = null)
5312
{
5313
    if (null === $userid) {
5314
        $userid = api_get_user_id();
5315
    }
5316
    if (empty($userid) || strval(intval($userid)) != $userid) {
5317
        if (api_is_anonymous()) {
5318
            $userid = api_get_anonymous_id();
5319
        } else {
5320
            return false;
5321
        }
5322
    }
5323
    $cid = Database::escape_string($cid);
5324
5325
    $courseInfo = api_get_course_info($cid);
5326
    $courseId = $courseInfo['real_id'];
5327
    $is_platformAdmin = api_is_platform_admin();
5328
5329
    $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
5330
    $course_cat_table = Database::get_main_table(TABLE_MAIN_CATEGORY);
5331
5332
    $sql = "SELECT
5333
                $course_cat_table.code AS category_code,
5334
                $course_table.visibility,
5335
                $course_table.code,
5336
                $course_cat_table.code
5337
            FROM $course_table
5338
            LEFT JOIN $course_cat_table
5339
                ON $course_table.category_id = $course_cat_table.id
5340
            WHERE
5341
                $course_table.code = '$cid'
5342
            LIMIT 1";
5343
5344
    $result = Database::query($sql);
5345
5346
    if (Database::num_rows($result) > 0) {
5347
        $visibility = Database::fetch_array($result);
5348
        $visibility = $visibility['visibility'];
5349
    } else {
5350
        $visibility = 0;
5351
    }
5352
    // Shortcut permissions in case the visibility is "open to the world".
5353
    if (COURSE_VISIBILITY_OPEN_WORLD === $visibility) {
5354
        return true;
5355
    }
5356
5357
    $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
5358
5359
    $sql = "SELECT
5360
                is_tutor, status
5361
            FROM $tbl_course_user
5362
            WHERE
5363
                user_id  = '$userid' AND
5364
                relation_type <> '".COURSE_RELATION_TYPE_RRHH."' AND
5365
                c_id = $courseId
5366
            LIMIT 1";
5367
5368
    $result = Database::query($sql);
5369
5370
    if (Database::num_rows($result) > 0) {
5371
        // This user has got a recorded state for this course.
5372
        $cuData = Database::fetch_array($result);
5373
        $is_courseMember = true;
5374
        $is_courseAdmin = (1 == $cuData['status']);
5375
    }
5376
5377
    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...
5378
        // This user has no status related to this course.
5379
        // Is it the session coach or the session admin?
5380
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
5381
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
5382
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
5383
5384
        $sql = "SELECT
5385
                    session.id_coach, session_admin_id, session.id
5386
                FROM
5387
                    $tbl_session as session
5388
                INNER JOIN $tbl_session_course
5389
                    ON session_rel_course.session_id = session.id
5390
                    AND session_rel_course.c_id = '$courseId'
5391
                LIMIT 1";
5392
5393
        $result = Database::query($sql);
5394
        $row = Database::store_result($result);
5395
5396
        if ($row[0]['id_coach'] == $userid) {
5397
            $is_courseMember = true;
5398
            $is_courseAdmin = false;
5399
        } elseif ($row[0]['session_admin_id'] == $userid) {
5400
            $is_courseMember = false;
5401
            $is_courseAdmin = false;
5402
        } else {
5403
            // Check if the current user is the course coach.
5404
            $sql = "SELECT 1
5405
                    FROM $tbl_session_course
5406
                    WHERE session_rel_course.c_id = '$courseId'
5407
                    AND session_rel_course.id_coach = '$userid'
5408
                    LIMIT 1";
5409
5410
            $result = Database::query($sql);
5411
5412
            //if ($row = Database::fetch_array($result)) {
5413
            if (Database::num_rows($result) > 0) {
5414
                $is_courseMember = true;
5415
                $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
5416
5417
                $sql = "SELECT status FROM $tbl_user
5418
                        WHERE id = $userid
5419
                        LIMIT 1";
5420
5421
                $result = Database::query($sql);
5422
5423
                if (1 == Database::result($result, 0, 0)) {
5424
                    $is_courseAdmin = true;
5425
                } else {
5426
                    $is_courseAdmin = false;
5427
                }
5428
            } else {
5429
                // Check if the user is a student is this session.
5430
                $sql = "SELECT  id
5431
                        FROM $tbl_session_course_user
5432
                        WHERE
5433
                            user_id  = '$userid' AND
5434
                            c_id = '$courseId'
5435
                        LIMIT 1";
5436
5437
                if (Database::num_rows($result) > 0) {
5438
                    // This user haa got a recorded state for this course.
5439
                    while ($row = Database::fetch_array($result)) {
5440
                        $is_courseMember = true;
5441
                        $is_courseAdmin = false;
5442
                    }
5443
                }
5444
            }
5445
        }
5446
    }
5447
5448
    switch ($visibility) {
5449
        case COURSE_VISIBILITY_OPEN_WORLD:
5450
            return true;
5451
        case COURSE_VISIBILITY_OPEN_PLATFORM:
5452
            return isset($userid);
5453
        case COURSE_VISIBILITY_REGISTERED:
5454
        case COURSE_VISIBILITY_CLOSED:
5455
            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...
5456
        case COURSE_VISIBILITY_HIDDEN:
5457
            return $is_platformAdmin;
5458
    }
5459
5460
    return false;
5461
}
5462
5463
/**
5464
 * Returns whether an element (forum, message, survey ...) belongs to a session or not.
5465
 *
5466
 * @param string the tool of the element
5467
 * @param int the element id in database
5468
 * @param int the session_id to compare with element session id
5469
 *
5470
 * @return bool true if the element is in the session, false else
5471
 */
5472
function api_is_element_in_the_session($tool, $element_id, $session_id = null)
5473
{
5474
    if (is_null($session_id)) {
5475
        $session_id = api_get_session_id();
5476
    }
5477
5478
    $element_id = (int) $element_id;
5479
5480
    if (empty($element_id)) {
5481
        return false;
5482
    }
5483
5484
    // Get information to build query depending of the tool.
5485
    switch ($tool) {
5486
        case TOOL_SURVEY:
5487
            $table_tool = Database::get_course_table(TABLE_SURVEY);
5488
            $key_field = 'survey_id';
5489
            break;
5490
        case TOOL_ANNOUNCEMENT:
5491
            $table_tool = Database::get_course_table(TABLE_ANNOUNCEMENT);
5492
            $key_field = 'id';
5493
            break;
5494
        case TOOL_AGENDA:
5495
            $table_tool = Database::get_course_table(TABLE_AGENDA);
5496
            $key_field = 'id';
5497
            break;
5498
        case TOOL_GROUP:
5499
            $table_tool = Database::get_course_table(TABLE_GROUP);
5500
            $key_field = 'id';
5501
            break;
5502
        default:
5503
            return false;
5504
    }
5505
    $course_id = api_get_course_int_id();
5506
5507
    $sql = "SELECT session_id FROM $table_tool
5508
            WHERE c_id = $course_id AND $key_field =  ".$element_id;
5509
    $rs = Database::query($sql);
5510
    if ($element_session_id = Database::result($rs, 0, 0)) {
5511
        if ($element_session_id == intval($session_id)) {
5512
            // The element belongs to the session.
5513
            return true;
5514
        }
5515
    }
5516
5517
    return false;
5518
}
5519
5520
/**
5521
 * Replaces "forbidden" characters in a filename string.
5522
 *
5523
 * @param string $filename
5524
 * @param bool   $treat_spaces_as_hyphens
5525
 *
5526
 * @return string
5527
 */
5528
function api_replace_dangerous_char($filename, $treat_spaces_as_hyphens = true)
5529
{
5530
    // Some non-properly encoded file names can cause the whole file to be
5531
    // skipped when uploaded. Avoid this by detecting the encoding and
5532
    // converting to UTF-8, setting the source as ASCII (a reasonably
5533
    // limited characters set) if nothing could be found (BT#
5534
    $encoding = api_detect_encoding($filename);
5535
    if (empty($encoding)) {
5536
        $encoding = 'ASCII';
5537
        if (!api_is_valid_ascii($filename)) {
5538
            // try iconv and try non standard ASCII a.k.a CP437
5539
            // see BT#15022
5540
            if (function_exists('iconv')) {
5541
                $result = iconv('CP437', 'UTF-8', $filename);
5542
                if (api_is_valid_utf8($result)) {
5543
                    $filename = $result;
5544
                    $encoding = 'UTF-8';
5545
                }
5546
            }
5547
        }
5548
    }
5549
5550
    $filename = api_to_system_encoding($filename, $encoding);
5551
5552
    $url = URLify::filter(
5553
        $filename,
5554
        250,
5555
        '',
5556
        true,
5557
        false,
5558
        false,
5559
        false
5560
    );
5561
5562
    return $url;
5563
}
5564
5565
/**
5566
 * Fixes the $_SERVER['REQUEST_URI'] that is empty in IIS6.
5567
 *
5568
 * @author Ivan Tcholakov, 28-JUN-2006.
5569
 */
5570
function api_request_uri()
5571
{
5572
    if (!empty($_SERVER['REQUEST_URI'])) {
5573
        return $_SERVER['REQUEST_URI'];
5574
    }
5575
    $uri = $_SERVER['SCRIPT_NAME'];
5576
    if (!empty($_SERVER['QUERY_STRING'])) {
5577
        $uri .= '?'.$_SERVER['QUERY_STRING'];
5578
    }
5579
    $_SERVER['REQUEST_URI'] = $uri;
5580
5581
    return $uri;
5582
}
5583
5584
/** Gets the current access_url id of the Chamilo Platform.
5585
 * @author Julio Montoya <[email protected]>
5586
 *
5587
 * @return int access_url_id of the current Chamilo Installation
5588
 */
5589
function api_get_current_access_url_id()
5590
{
5591
    if (false === api_get_multiple_access_url()) {
5592
        return 1;
5593
    }
5594
5595
    static $id;
5596
    if (!empty($id)) {
5597
        return $id;
5598
    }
5599
5600
    $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5601
    $path = Database::escape_string(api_get_path(WEB_PATH));
5602
    $sql = "SELECT id FROM $table WHERE url = '".$path."'";
5603
    $result = Database::query($sql);
5604
    if (Database::num_rows($result) > 0) {
5605
        $id = Database::result($result, 0, 0);
5606
        if (false === $id) {
5607
            return -1;
5608
        }
5609
5610
        return (int) $id;
5611
    }
5612
5613
    $id = 1;
5614
5615
    //if the url in WEB_PATH was not found, it can only mean that there is
5616
    // either a configuration problem or the first URL has not been defined yet
5617
    // (by default it is http://localhost/). Thus the more sensible thing we can
5618
    // do is return 1 (the main URL) as the user cannot hack this value anyway
5619
    return 1;
5620
}
5621
5622
/**
5623
 * Gets the registered urls from a given user id.
5624
 *
5625
 * @author Julio Montoya <[email protected]>
5626
 *
5627
 * @param int $user_id
5628
 *
5629
 * @return array
5630
 */
5631
function api_get_access_url_from_user($user_id)
5632
{
5633
    $user_id = (int) $user_id;
5634
    $table_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
5635
    $table_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5636
    $sql = "SELECT access_url_id
5637
            FROM $table_url_rel_user url_rel_user
5638
            INNER JOIN $table_url u
5639
            ON (url_rel_user.access_url_id = u.id)
5640
            WHERE user_id = ".$user_id;
5641
    $result = Database::query($sql);
5642
    $list = [];
5643
    while ($row = Database::fetch_array($result, 'ASSOC')) {
5644
        $list[] = $row['access_url_id'];
5645
    }
5646
5647
    return $list;
5648
}
5649
5650
/**
5651
 * Checks whether the curent user is in a group or not.
5652
 *
5653
 * @param string        The group id - optional (takes it from session if not given)
5654
 * @param string        The course code - optional (no additional check by course if course code is not given)
5655
 *
5656
 * @return bool
5657
 *
5658
 * @author Ivan Tcholakov
5659
 */
5660
function api_is_in_group($groupIdParam = null, $courseCodeParam = null)
5661
{
5662
    if (!empty($courseCodeParam)) {
5663
        $courseCode = api_get_course_id();
5664
        if (!empty($courseCode)) {
5665
            if ($courseCodeParam != $courseCode) {
5666
                return false;
5667
            }
5668
        } else {
5669
            return false;
5670
        }
5671
    }
5672
5673
    $groupId = api_get_group_id();
5674
5675
    if (isset($groupId) && '' != $groupId) {
5676
        if (!empty($groupIdParam)) {
5677
            return $groupIdParam == $groupId;
5678
        } else {
5679
            return true;
5680
        }
5681
    }
5682
5683
    return false;
5684
}
5685
5686
/**
5687
 * Checks whether a secret key is valid.
5688
 *
5689
 * @param string $original_key_secret - secret key from (webservice) client
5690
 * @param string $security_key        - security key from Chamilo
5691
 *
5692
 * @return bool - true if secret key is valid, false otherwise
5693
 */
5694
function api_is_valid_secret_key($original_key_secret, $security_key)
5695
{
5696
    return $original_key_secret == sha1($security_key);
5697
}
5698
5699
/**
5700
 * Checks whether the server's operating system is Windows (TM).
5701
 *
5702
 * @return bool - true if the operating system is Windows, false otherwise
5703
 */
5704
function api_is_windows_os()
5705
{
5706
    if (function_exists('php_uname')) {
5707
        // php_uname() exists as of PHP 4.0.2, according to the documentation.
5708
        // We expect that this function will always work for Chamilo 1.8.x.
5709
        $os = php_uname();
5710
    }
5711
    // The following methods are not needed, but let them stay, just in case.
5712
    elseif (isset($_ENV['OS'])) {
5713
        // Sometimes $_ENV['OS'] may not be present (bugs?)
5714
        $os = $_ENV['OS'];
5715
    } elseif (defined('PHP_OS')) {
5716
        // PHP_OS means on which OS PHP was compiled, this is why
5717
        // using PHP_OS is the last choice for detection.
5718
        $os = PHP_OS;
5719
    } else {
5720
        return false;
5721
    }
5722
5723
    return 'win' == strtolower(substr((string) $os, 0, 3));
5724
}
5725
5726
/**
5727
 * This function informs whether the sent request is XMLHttpRequest.
5728
 */
5729
function api_is_xml_http_request()
5730
{
5731
    return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && 'xmlhttprequest' == strtolower($_SERVER['HTTP_X_REQUESTED_WITH']);
5732
}
5733
5734
/**
5735
 * Returns a list of Chamilo's tools or
5736
 * checks whether a given identificator is a valid Chamilo's tool.
5737
 *
5738
 * @author Isaac flores paz
5739
 *
5740
 * @param string The tool name to filter
5741
 *
5742
 * @return mixed Filtered string or array
5743
 */
5744
function api_get_tools_lists($my_tool = null)
5745
{
5746
    $tools_list = [
5747
        TOOL_DOCUMENT,
5748
        TOOL_THUMBNAIL,
5749
        TOOL_HOTPOTATOES,
5750
        TOOL_CALENDAR_EVENT,
5751
        TOOL_LINK,
5752
        TOOL_COURSE_DESCRIPTION,
5753
        TOOL_SEARCH,
5754
        TOOL_LEARNPATH,
5755
        TOOL_ANNOUNCEMENT,
5756
        TOOL_FORUM,
5757
        TOOL_THREAD,
5758
        TOOL_POST,
5759
        TOOL_DROPBOX,
5760
        TOOL_QUIZ,
5761
        TOOL_USER,
5762
        TOOL_GROUP,
5763
        TOOL_BLOGS,
5764
        TOOL_CHAT,
5765
        TOOL_STUDENTPUBLICATION,
5766
        TOOL_TRACKING,
5767
        TOOL_HOMEPAGE_LINK,
5768
        TOOL_COURSE_SETTING,
5769
        TOOL_BACKUP,
5770
        TOOL_COPY_COURSE_CONTENT,
5771
        TOOL_RECYCLE_COURSE,
5772
        TOOL_COURSE_HOMEPAGE,
5773
        TOOL_COURSE_RIGHTS_OVERVIEW,
5774
        TOOL_UPLOAD,
5775
        TOOL_COURSE_MAINTENANCE,
5776
        TOOL_SURVEY,
5777
        TOOL_WIKI,
5778
        TOOL_GLOSSARY,
5779
        TOOL_GRADEBOOK,
5780
        TOOL_NOTEBOOK,
5781
        TOOL_ATTENDANCE,
5782
        TOOL_COURSE_PROGRESS,
5783
    ];
5784
    if (empty($my_tool)) {
5785
        return $tools_list;
5786
    }
5787
5788
    return in_array($my_tool, $tools_list) ? $my_tool : '';
5789
}
5790
5791
/**
5792
 * Checks whether we already approved the last version term and condition.
5793
 *
5794
 * @param int user id
5795
 *
5796
 * @return bool true if we pass false otherwise
5797
 */
5798
function api_check_term_condition($userId)
5799
{
5800
    if ('true' === api_get_setting('allow_terms_conditions')) {
5801
        // Check if exists terms and conditions
5802
        if (0 == LegalManager::count()) {
5803
            return true;
5804
        }
5805
5806
        $extraFieldValue = new ExtraFieldValue('user');
5807
        $data = $extraFieldValue->get_values_by_handler_and_field_variable(
5808
            $userId,
5809
            'legal_accept'
5810
        );
5811
5812
        if (!empty($data) && isset($data['value']) && !empty($data['value'])) {
5813
            $result = $data['value'];
5814
            $user_conditions = explode(':', $result);
5815
            $version = $user_conditions[0];
5816
            $langId = $user_conditions[1];
5817
            $realVersion = LegalManager::get_last_version($langId);
5818
5819
            return $version >= $realVersion;
5820
        }
5821
5822
        return false;
5823
    }
5824
5825
    return false;
5826
}
5827
5828
/**
5829
 * Gets all information of a tool into course.
5830
 *
5831
 * @param int The tool id
5832
 *
5833
 * @return array
5834
 */
5835
function api_get_tool_information_by_name($name)
5836
{
5837
    $t_tool = Database::get_course_table(TABLE_TOOL_LIST);
5838
    $course_id = api_get_course_int_id();
5839
5840
    $sql = "SELECT id FROM tool
5841
            WHERE name = '".Database::escape_string($name)."' ";
5842
    $rs = Database::query($sql);
5843
    $data = Database::fetch_array($rs);
5844
    if ($data) {
5845
        $tool = $data['id'];
5846
        $sql = "SELECT * FROM $t_tool
5847
                WHERE c_id = $course_id  AND tool_id = '".$tool."' ";
5848
        $rs = Database::query($sql);
5849
5850
        return Database::fetch_array($rs, 'ASSOC');
5851
    }
5852
5853
    return [];
5854
}
5855
5856
/**
5857
 * Function used to protect a "global" admin script.
5858
 * The function blocks access when the user has no global platform admin rights.
5859
 * Global admins are the admins that are registered in the main.admin table
5860
 * AND the users who have access to the "principal" portal.
5861
 * That means that there is a record in the main.access_url_rel_user table
5862
 * with his user id and the access_url_id=1.
5863
 *
5864
 * @author Julio Montoya
5865
 *
5866
 * @param int $user_id
5867
 *
5868
 * @return bool
5869
 */
5870
function api_is_global_platform_admin($user_id = null)
5871
{
5872
    $user_id = (int) $user_id;
5873
    if (empty($user_id)) {
5874
        $user_id = api_get_user_id();
5875
    }
5876
    if (api_is_platform_admin_by_id($user_id)) {
5877
        $urlList = api_get_access_url_from_user($user_id);
5878
        // The admin is registered in the first "main" site with access_url_id = 1
5879
        if (in_array(1, $urlList)) {
5880
            return true;
5881
        } else {
5882
            return false;
5883
        }
5884
    }
5885
5886
    return false;
5887
}
5888
5889
/**
5890
 * @param int  $admin_id_to_check
5891
 * @param int  $my_user_id
5892
 * @param bool $allow_session_admin
5893
 *
5894
 * @return bool
5895
 */
5896
function api_global_admin_can_edit_admin(
5897
    $admin_id_to_check,
5898
    $my_user_id = null,
5899
    $allow_session_admin = false
5900
) {
5901
    if (empty($my_user_id)) {
5902
        $my_user_id = api_get_user_id();
5903
    }
5904
5905
    $iam_a_global_admin = api_is_global_platform_admin($my_user_id);
5906
    $user_is_global_admin = api_is_global_platform_admin($admin_id_to_check);
5907
5908
    if ($iam_a_global_admin) {
5909
        // Global admin can edit everything
5910
        return true;
5911
    } else {
5912
        // If i'm a simple admin
5913
        $is_platform_admin = api_is_platform_admin_by_id($my_user_id);
5914
5915
        if ($allow_session_admin) {
5916
            $is_platform_admin = api_is_platform_admin_by_id($my_user_id) || (SESSIONADMIN == api_get_user_status($my_user_id));
5917
        }
5918
5919
        if ($is_platform_admin) {
5920
            if ($user_is_global_admin) {
5921
                return false;
5922
            } else {
5923
                return true;
5924
            }
5925
        } else {
5926
            return false;
5927
        }
5928
    }
5929
}
5930
5931
/**
5932
 * @param int  $admin_id_to_check
5933
 * @param int  $my_user_id
5934
 * @param bool $allow_session_admin
5935
 *
5936
 * @return bool|null
5937
 */
5938
function api_protect_super_admin($admin_id_to_check, $my_user_id = null, $allow_session_admin = false)
5939
{
5940
    if (api_global_admin_can_edit_admin($admin_id_to_check, $my_user_id, $allow_session_admin)) {
5941
        return true;
5942
    } else {
5943
        api_not_allowed();
5944
    }
5945
}
5946
5947
/**
5948
 * Function used to protect a global admin script.
5949
 * The function blocks access when the user has no global platform admin rights.
5950
 * See also the api_is_global_platform_admin() function wich defines who's a "global" admin.
5951
 *
5952
 * @author Julio Montoya
5953
 */
5954
function api_protect_global_admin_script()
5955
{
5956
    if (!api_is_global_platform_admin()) {
5957
        api_not_allowed();
5958
5959
        return false;
5960
    }
5961
5962
    return true;
5963
}
5964
5965
/**
5966
 * Check browser support for specific file types or features
5967
 * This function checks if the user's browser supports a file format or given
5968
 * feature, or returns the current browser and major version when
5969
 * $format=check_browser. Only a limited number of formats and features are
5970
 * checked by this method. Make sure you check its definition first.
5971
 *
5972
 * @param string $format Can be a file format (extension like svg, webm, ...) or a feature (like autocapitalize, ...)
5973
 *
5974
 * @deprecated
5975
 *
5976
 * @return bool or return text array if $format=check_browser
5977
 *
5978
 * @author Juan Carlos Raña Trabado
5979
 */
5980
function api_browser_support($format = '')
5981
{
5982
    return true;
5983
5984
    $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...
5985
    $current_browser = $browser->getBrowser();
5986
    $a_versiontemp = explode('.', $browser->getVersion());
5987
    $current_majorver = $a_versiontemp[0];
5988
5989
    static $result;
5990
5991
    if (isset($result[$format])) {
5992
        return $result[$format];
5993
    }
5994
5995
    // Native svg support
5996
    if ('svg' == $format) {
5997
        if (('Internet Explorer' == $current_browser && $current_majorver >= 9) ||
5998
            ('Firefox' == $current_browser && $current_majorver > 1) ||
5999
            ('Safari' == $current_browser && $current_majorver >= 4) ||
6000
            ('Chrome' == $current_browser && $current_majorver >= 1) ||
6001
            ('Opera' == $current_browser && $current_majorver >= 9)
6002
        ) {
6003
            $result[$format] = true;
6004
6005
            return true;
6006
        } else {
6007
            $result[$format] = false;
6008
6009
            return false;
6010
        }
6011
    } elseif ('pdf' == $format) {
6012
        // native pdf support
6013
        if ('Chrome' == $current_browser && $current_majorver >= 6) {
6014
            $result[$format] = true;
6015
6016
            return true;
6017
        } else {
6018
            $result[$format] = false;
6019
6020
            return false;
6021
        }
6022
    } elseif ('tif' == $format || 'tiff' == $format) {
6023
        //native tif support
6024
        if ('Safari' == $current_browser && $current_majorver >= 5) {
6025
            $result[$format] = true;
6026
6027
            return true;
6028
        } else {
6029
            $result[$format] = false;
6030
6031
            return false;
6032
        }
6033
    } elseif ('ogg' == $format || 'ogx' == $format || 'ogv' == $format || 'oga' == $format) {
6034
        //native ogg, ogv,oga support
6035
        if (('Firefox' == $current_browser && $current_majorver >= 3) ||
6036
            ('Chrome' == $current_browser && $current_majorver >= 3) ||
6037
            ('Opera' == $current_browser && $current_majorver >= 9)) {
6038
            $result[$format] = true;
6039
6040
            return true;
6041
        } else {
6042
            $result[$format] = false;
6043
6044
            return false;
6045
        }
6046
    } elseif ('mpg' == $format || 'mpeg' == $format) {
6047
        //native mpg support
6048
        if (('Safari' == $current_browser && $current_majorver >= 5)) {
6049
            $result[$format] = true;
6050
6051
            return true;
6052
        } else {
6053
            $result[$format] = false;
6054
6055
            return false;
6056
        }
6057
    } elseif ('mp4' == $format) {
6058
        //native mp4 support (TODO: Android, iPhone)
6059
        if ('Android' == $current_browser || 'iPhone' == $current_browser) {
6060
            $result[$format] = true;
6061
6062
            return true;
6063
        } else {
6064
            $result[$format] = false;
6065
6066
            return false;
6067
        }
6068
    } elseif ('mov' == $format) {
6069
        //native mov support( TODO:check iPhone)
6070
        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...
6071
            $result[$format] = true;
6072
6073
            return true;
6074
        } else {
6075
            $result[$format] = false;
6076
6077
            return false;
6078
        }
6079
    } elseif ('avi' == $format) {
6080
        //native avi support
6081
        if ('Safari' == $current_browser && $current_majorver >= 5) {
6082
            $result[$format] = true;
6083
6084
            return true;
6085
        } else {
6086
            $result[$format] = false;
6087
6088
            return false;
6089
        }
6090
    } elseif ('wmv' == $format) {
6091
        //native wmv support
6092
        if ('Firefox' == $current_browser && $current_majorver >= 4) {
6093
            $result[$format] = true;
6094
6095
            return true;
6096
        } else {
6097
            $result[$format] = false;
6098
6099
            return false;
6100
        }
6101
    } elseif ('webm' == $format) {
6102
        //native webm support (TODO:check IE9, Chrome9, Android)
6103
        if (('Firefox' == $current_browser && $current_majorver >= 4) ||
6104
            ('Opera' == $current_browser && $current_majorver >= 9) ||
6105
            ('Internet Explorer' == $current_browser && $current_majorver >= 9) ||
6106
            ('Chrome' == $current_browser && $current_majorver >= 9) ||
6107
            'Android' == $current_browser
6108
        ) {
6109
            $result[$format] = true;
6110
6111
            return true;
6112
        } else {
6113
            $result[$format] = false;
6114
6115
            return false;
6116
        }
6117
    } elseif ('wav' == $format) {
6118
        //native wav support (only some codecs !)
6119
        if (('Firefox' == $current_browser && $current_majorver >= 4) ||
6120
            ('Safari' == $current_browser && $current_majorver >= 5) ||
6121
            ('Opera' == $current_browser && $current_majorver >= 9) ||
6122
            ('Internet Explorer' == $current_browser && $current_majorver >= 9) ||
6123
            ('Chrome' == $current_browser && $current_majorver > 9) ||
6124
            'Android' == $current_browser ||
6125
            'iPhone' == $current_browser
6126
        ) {
6127
            $result[$format] = true;
6128
6129
            return true;
6130
        } else {
6131
            $result[$format] = false;
6132
6133
            return false;
6134
        }
6135
    } elseif ('mid' == $format || 'kar' == $format) {
6136
        //native midi support (TODO:check Android)
6137
        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...
6138
            $result[$format] = true;
6139
6140
            return true;
6141
        } else {
6142
            $result[$format] = false;
6143
6144
            return false;
6145
        }
6146
    } elseif ('wma' == $format) {
6147
        //native wma support
6148
        if ('Firefox' == $current_browser && $current_majorver >= 4) {
6149
            $result[$format] = true;
6150
6151
            return true;
6152
        } else {
6153
            $result[$format] = false;
6154
6155
            return false;
6156
        }
6157
    } elseif ('au' == $format) {
6158
        //native au support
6159
        if ('Safari' == $current_browser && $current_majorver >= 5) {
6160
            $result[$format] = true;
6161
6162
            return true;
6163
        } else {
6164
            $result[$format] = false;
6165
6166
            return false;
6167
        }
6168
    } elseif ('mp3' == $format) {
6169
        //native mp3 support (TODO:check Android, iPhone)
6170
        if (('Safari' == $current_browser && $current_majorver >= 5) ||
6171
            ('Chrome' == $current_browser && $current_majorver >= 6) ||
6172
            ('Internet Explorer' == $current_browser && $current_majorver >= 9) ||
6173
            'Android' == $current_browser ||
6174
            'iPhone' == $current_browser ||
6175
            'Firefox' == $current_browser
6176
        ) {
6177
            $result[$format] = true;
6178
6179
            return true;
6180
        } else {
6181
            $result[$format] = false;
6182
6183
            return false;
6184
        }
6185
    } elseif ('autocapitalize' == $format) {
6186
        // Help avoiding showing the autocapitalize option if the browser doesn't
6187
        // support it: this attribute is against the HTML5 standard
6188
        if ('Safari' == $current_browser || 'iPhone' == $current_browser) {
6189
            return true;
6190
        } else {
6191
            return false;
6192
        }
6193
    } elseif ("check_browser" == $format) {
6194
        $array_check_browser = [$current_browser, $current_majorver];
6195
6196
        return $array_check_browser;
6197
    } else {
6198
        $result[$format] = false;
6199
6200
        return false;
6201
    }
6202
}
6203
6204
/**
6205
 * This function checks if exist path and file browscap.ini
6206
 * In order for this to work, your browscap configuration setting in php.ini
6207
 * must point to the correct location of the browscap.ini file on your system
6208
 * http://php.net/manual/en/function.get-browser.php.
6209
 *
6210
 * @return bool
6211
 *
6212
 * @author Juan Carlos Raña Trabado
6213
 */
6214
function api_check_browscap()
6215
{
6216
    $setting = ini_get('browscap');
6217
    if ($setting) {
6218
        $browser = get_browser($_SERVER['HTTP_USER_AGENT'], true);
6219
        if (strpos($setting, 'browscap.ini') && !empty($browser)) {
6220
            return true;
6221
        }
6222
    }
6223
6224
    return false;
6225
}
6226
6227
/**
6228
 * Returns the <script> HTML tag.
6229
 */
6230
function api_get_js($file)
6231
{
6232
    return '<script type="text/javascript" src="'.api_get_path(WEB_LIBRARY_PATH).'javascript/'.$file.'"></script>'."\n";
6233
}
6234
6235
function api_get_build_js($file)
6236
{
6237
    return '<script type="text/javascript" src="'.api_get_path(WEB_PUBLIC_PATH).'build/'.$file.'"></script>'."\n";
6238
}
6239
6240
function api_get_build_css($file, $media = 'screen')
6241
{
6242
    return '<link
6243
        href="'.api_get_path(WEB_PUBLIC_PATH).'build/'.$file.'" rel="stylesheet" media="'.$media.'" type="text/css" />'."\n";
6244
}
6245
6246
/**
6247
 * Returns the <script> HTML tag.
6248
 *
6249
 * @return string
6250
 */
6251
function api_get_asset($file)
6252
{
6253
    return '<script type="text/javascript" src="'.api_get_path(WEB_PUBLIC_PATH).'build/libs/'.$file.'"></script>'."\n";
6254
}
6255
6256
/**
6257
 * Returns the <script> HTML tag.
6258
 *
6259
 * @param string $file
6260
 * @param string $media
6261
 *
6262
 * @return string
6263
 */
6264
function api_get_css_asset($file, $media = 'screen')
6265
{
6266
    return '<link href="'.api_get_path(WEB_PUBLIC_PATH).'build/libs/'.$file.'" rel="stylesheet" media="'.$media.'" type="text/css" />'."\n";
6267
}
6268
6269
/**
6270
 * Returns the <link> HTML tag.
6271
 *
6272
 * @param string $file
6273
 * @param string $media
6274
 */
6275
function api_get_css($file, $media = 'screen')
6276
{
6277
    return '<link href="'.$file.'" rel="stylesheet" media="'.$media.'" type="text/css" />'."\n";
6278
}
6279
6280
function api_get_bootstrap_and_font_awesome($returnOnlyPath = false)
6281
{
6282
    $url = api_get_path(WEB_PUBLIC_PATH).'build/css/bootstrap.css';
6283
    if ($returnOnlyPath) {
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 string $courseCode 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 <[email protected]>
6410
 */
6411
function api_get_course_url($courseCode = null, $sessionId = null, $groupId = null)
6412
{
6413
    $url = '';
6414
    // If courseCode not set, get context or []
6415
    if (empty($courseCode)) {
6416
        $courseInfo = api_get_course_info();
6417
    } else {
6418
        $courseInfo = api_get_course_info($courseCode);
6419
    }
6420
6421
    // If sessionId not set, get context or 0
6422
    if (empty($sessionId)) {
6423
        $sessionId = api_get_session_id();
6424
    }
6425
6426
    // If groupId not set, get context or 0
6427
    if (empty($groupId)) {
6428
        $groupId = api_get_group_id();
6429
    }
6430
6431
    // Build the URL
6432
    if (!empty($courseInfo)) {
6433
        // directory not empty, so we do have a course
6434
        $url = $courseInfo['course_public_url'].'?sid='.$sessionId.'&gid='.$groupId;
6435
    } else {
6436
        if (!empty($sessionId) && 'true' !== api_get_setting('session.remove_session_url')) {
6437
            // if the course was unset and the session was set, send directly to the session
6438
            $url = api_get_path(WEB_CODE_PATH).'session/index.php?session_id='.$sessionId;
6439
        }
6440
    }
6441
6442
    // if not valid combination was found, return an empty string
6443
    return $url;
6444
}
6445
6446
/**
6447
 * Check if the current portal has the $_configuration['multiple_access_urls'] parameter on.
6448
 */
6449
function api_get_multiple_access_url(): bool
6450
{
6451
    global $_configuration;
6452
    if (isset($_configuration['multiple_access_urls']) && $_configuration['multiple_access_urls']) {
6453
        return true;
6454
    }
6455
6456
    return false;
6457
}
6458
6459
function api_is_multiple_url_enabled(): bool
6460
{
6461
    return api_get_multiple_access_url();
6462
}
6463
6464
/**
6465
 * Returns a md5 unique id.
6466
 *
6467
 * @todo add more parameters
6468
 */
6469
function api_get_unique_id()
6470
{
6471
    return md5(time().uniqid().api_get_user_id().api_get_course_id().api_get_session_id());
6472
}
6473
6474
/**
6475
 * @param int Course id
6476
 * @param int tool id: TOOL_QUIZ, TOOL_FORUM, TOOL_STUDENTPUBLICATION, TOOL_LEARNPATH
6477
 * @param int the item id (tool id, exercise id, lp id)
6478
 *
6479
 * @return bool
6480
 */
6481
function api_resource_is_locked_by_gradebook($item_id, $link_type, $course_code = null)
6482
{
6483
    if (api_is_platform_admin()) {
6484
        return false;
6485
    }
6486
    if ('true' == api_get_setting('gradebook_locking_enabled')) {
6487
        if (empty($course_code)) {
6488
            $course_code = api_get_course_id();
6489
        }
6490
        $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_LINK);
6491
        $item_id = (int) $item_id;
6492
        $link_type = (int) $link_type;
6493
        $course_code = Database::escape_string($course_code);
6494
        $sql = "SELECT locked FROM $table
6495
                WHERE locked = 1 AND ref_id = $item_id AND type = $link_type AND course_code = '$course_code' ";
6496
        $result = Database::query($sql);
6497
        if (Database::num_rows($result)) {
6498
            return true;
6499
        }
6500
    }
6501
6502
    return false;
6503
}
6504
6505
/**
6506
 * Blocks a page if the item was added in a gradebook.
6507
 *
6508
 * @param int       exercise id, work id, thread id,
6509
 * @param int       LINK_EXERCISE, LINK_STUDENTPUBLICATION, LINK_LEARNPATH LINK_FORUM_THREAD, LINK_ATTENDANCE
6510
 * see gradebook/lib/be/linkfactory
6511
 * @param string    course code
6512
 *
6513
 * @return false|null
6514
 */
6515
function api_block_course_item_locked_by_gradebook($item_id, $link_type, $course_code = null)
6516
{
6517
    if (api_is_platform_admin()) {
6518
        return false;
6519
    }
6520
6521
    if (api_resource_is_locked_by_gradebook($item_id, $link_type, $course_code)) {
6522
        $message = Display::return_message(
6523
            get_lang(
6524
                '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.'
6525
            ),
6526
            'warning'
6527
        );
6528
        api_not_allowed(true, $message);
6529
    }
6530
}
6531
6532
/**
6533
 * Checks the PHP version installed is enough to run Chamilo.
6534
 *
6535
 * @param string Include path (used to load the error page)
6536
 */
6537
function api_check_php_version()
6538
{
6539
    if (!function_exists('version_compare') ||
6540
        version_compare(PHP_VERSION, REQUIRED_PHP_VERSION, '<')
6541
    ) {
6542
        throw new Exception('Wrong PHP version');
6543
    }
6544
}
6545
6546
/**
6547
 * Checks whether the Archive directory is present and writeable. If not,
6548
 * prints a warning message.
6549
 */
6550
function api_check_archive_dir()
6551
{
6552
    if (is_dir(api_get_path(SYS_ARCHIVE_PATH)) && !is_writable(api_get_path(SYS_ARCHIVE_PATH))) {
6553
        $message = Display::return_message(
6554
            get_lang(
6555
                'The app/cache/ directory, used by this tool, is not writeable. Please contact your platform administrator.'
6556
            ),
6557
            'warning'
6558
        );
6559
        api_not_allowed(true, $message);
6560
    }
6561
}
6562
6563
/**
6564
 * Returns an array of global configuration settings which should be ignored
6565
 * when printing the configuration settings screens.
6566
 *
6567
 * @return array Array of strings, each identifying one of the excluded settings
6568
 */
6569
function api_get_locked_settings()
6570
{
6571
    return [
6572
        'permanently_remove_deleted_files',
6573
        'account_valid_duration',
6574
        'service_ppt2lp',
6575
        'wcag_anysurfer_public_pages',
6576
        'upload_extensions_list_type',
6577
        'upload_extensions_blacklist',
6578
        'upload_extensions_whitelist',
6579
        'upload_extensions_skip',
6580
        'upload_extensions_replace_by',
6581
        'hide_dltt_markup',
6582
        'split_users_upload_directory',
6583
        'permissions_for_new_directories',
6584
        'permissions_for_new_files',
6585
        'platform_charset',
6586
        'ldap_description',
6587
        'cas_activate',
6588
        'cas_server',
6589
        'cas_server_uri',
6590
        'cas_port',
6591
        'cas_protocol',
6592
        'cas_add_user_activate',
6593
        'update_user_info_cas_with_ldap',
6594
        'languagePriority1',
6595
        'languagePriority2',
6596
        'languagePriority3',
6597
        'languagePriority4',
6598
        'login_is_email',
6599
        'chamilo_database_version',
6600
    ];
6601
}
6602
6603
/**
6604
 * Guess the real ip for register in the database, even in reverse proxy cases.
6605
 * To be recognized, the IP has to be found in either $_SERVER['REMOTE_ADDR'] or
6606
 * in $_SERVER['HTTP_X_FORWARDED_FOR'], which is in common use with rproxies.
6607
 * Note: the result of this function is not SQL-safe. Please escape it before
6608
 * inserting in a database.
6609
 *
6610
 * @return string the user's real ip (unsafe - escape it before inserting to db)
6611
 *
6612
 * @author Jorge Frisancho Jibaja <[email protected]>, USIL - Some changes to allow the use of real IP using reverse proxy
6613
 *
6614
 * @version CEV CHANGE 24APR2012
6615
 */
6616
function api_get_real_ip()
6617
{
6618
    $ip = trim($_SERVER['REMOTE_ADDR']);
6619
    if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
6620
        if (preg_match('/,/', $_SERVER['HTTP_X_FORWARDED_FOR'])) {
6621
            @list($ip1, $ip2) = @explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
6622
        } else {
6623
            $ip1 = $_SERVER['HTTP_X_FORWARDED_FOR'];
6624
        }
6625
        $ip = trim($ip1);
6626
    }
6627
6628
    return $ip;
6629
}
6630
6631
/**
6632
 * Checks whether an IP is included inside an IP range.
6633
 *
6634
 * @param string IP address
6635
 * @param string IP range
6636
 * @param string $ip
6637
 *
6638
 * @return bool True if IP is in the range, false otherwise
6639
 *
6640
 * @author claudiu at cnixs dot com  on http://www.php.net/manual/fr/ref.network.php#55230
6641
 * @author Yannick Warnier for improvements and managment of multiple ranges
6642
 *
6643
 * @todo check for IPv6 support
6644
 */
6645
function api_check_ip_in_range($ip, $range)
6646
{
6647
    if (empty($ip) or empty($range)) {
6648
        return false;
6649
    }
6650
    $ip_ip = ip2long($ip);
6651
    // divide range param into array of elements
6652
    if (false !== strpos($range, ',')) {
6653
        $ranges = explode(',', $range);
6654
    } else {
6655
        $ranges = [$range];
6656
    }
6657
    foreach ($ranges as $range) {
0 ignored issues
show
introduced by
$range is overwriting one of the parameters of this function.
Loading history...
6658
        $range = trim($range);
6659
        if (empty($range)) {
6660
            continue;
6661
        }
6662
        if (false === strpos($range, '/')) {
6663
            if (0 === strcmp($ip, $range)) {
6664
                return true; // there is a direct IP match, return OK
6665
            }
6666
            continue; //otherwise, get to the next range
6667
        }
6668
        // the range contains a "/", so analyse completely
6669
        [$net, $mask] = explode("/", $range);
6670
6671
        $ip_net = ip2long($net);
6672
        // mask binary magic
6673
        $ip_mask = ~((1 << (32 - $mask)) - 1);
6674
6675
        $ip_ip_net = $ip_ip & $ip_mask;
6676
        if ($ip_ip_net == $ip_net) {
6677
            return true;
6678
        }
6679
    }
6680
6681
    return false;
6682
}
6683
6684
function api_check_user_access_to_legal($course_visibility)
6685
{
6686
    $course_visibility_list = [COURSE_VISIBILITY_OPEN_WORLD, COURSE_VISIBILITY_OPEN_PLATFORM];
6687
6688
    return in_array($course_visibility, $course_visibility_list) || api_is_drh();
6689
}
6690
6691
/**
6692
 * Checks if the global chat is enabled or not.
6693
 *
6694
 * @return bool
6695
 */
6696
function api_is_global_chat_enabled()
6697
{
6698
    return
6699
        !api_is_anonymous() &&
6700
        'true' === api_get_setting('allow_global_chat') &&
6701
        'true' === api_get_setting('allow_social_tool');
6702
}
6703
6704
/**
6705
 * @param int   $item_id
6706
 * @param int   $tool_id
6707
 * @param int   $group_id   id
6708
 * @param array $courseInfo
6709
 * @param int   $sessionId
6710
 * @param int   $userId
6711
 *
6712
 * @deprecated
6713
 */
6714
function api_set_default_visibility(
6715
    $item_id,
6716
    $tool_id,
6717
    $group_id = 0,
6718
    $courseInfo = [],
6719
    $sessionId = 0,
6720
    $userId = 0
6721
) {
6722
    $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
6723
    $courseId = $courseInfo['real_id'];
6724
    $courseCode = $courseInfo['code'];
6725
    $sessionId = empty($sessionId) ? api_get_session_id() : $sessionId;
6726
    $userId = empty($userId) ? api_get_user_id() : $userId;
6727
6728
    // if group is null force group_id = 0, this force is needed to create a LP folder with group = 0
6729
    if (is_null($group_id)) {
6730
        $group_id = 0;
6731
    } else {
6732
        $group_id = empty($group_id) ? api_get_group_id() : $group_id;
6733
    }
6734
6735
    $groupInfo = [];
6736
    if (!empty($group_id)) {
6737
        $groupInfo = GroupManager::get_group_properties($group_id);
6738
    }
6739
    $original_tool_id = $tool_id;
6740
6741
    switch ($tool_id) {
6742
        case TOOL_LINK:
6743
        case TOOL_LINK_CATEGORY:
6744
            $tool_id = 'links';
6745
            break;
6746
        case TOOL_DOCUMENT:
6747
            $tool_id = 'documents';
6748
            break;
6749
        case TOOL_LEARNPATH:
6750
            $tool_id = 'learning';
6751
            break;
6752
        case TOOL_ANNOUNCEMENT:
6753
            $tool_id = 'announcements';
6754
            break;
6755
        case TOOL_FORUM:
6756
        case TOOL_FORUM_CATEGORY:
6757
        case TOOL_FORUM_THREAD:
6758
            $tool_id = 'forums';
6759
            break;
6760
        case TOOL_QUIZ:
6761
            $tool_id = 'quiz';
6762
            break;
6763
    }
6764
    $setting = api_get_setting('tool_visible_by_default_at_creation');
6765
6766
    if (isset($setting[$tool_id])) {
6767
        $visibility = 'invisible';
6768
        if ('true' == $setting[$tool_id]) {
6769
            $visibility = 'visible';
6770
        }
6771
6772
        // Read the portal and course default visibility
6773
        if ('documents' === $tool_id) {
6774
            $visibility = DocumentManager::getDocumentDefaultVisibility($courseInfo);
6775
        }
6776
6777
        // Fixes default visibility for tests
6778
        switch ($original_tool_id) {
6779
            case TOOL_QUIZ:
6780
                if (empty($sessionId)) {
6781
                    $objExerciseTmp = new Exercise($courseId);
6782
                    $objExerciseTmp->read($item_id);
6783
                    if ('visible' == $visibility) {
6784
                        $objExerciseTmp->enable();
6785
                        $objExerciseTmp->save();
6786
                    } else {
6787
                        $objExerciseTmp->disable();
6788
                        $objExerciseTmp->save();
6789
                    }
6790
                }
6791
                break;
6792
        }
6793
    }
6794
}
6795
6796
/**
6797
 * @param int $user_id
6798
 * @param int $courseId
6799
 * @param int $session_id
6800
 *
6801
 * @return array
6802
 */
6803
function api_detect_user_roles($user_id, $courseId, $session_id = 0)
6804
{
6805
    $user_roles = [];
6806
    $courseInfo = api_get_course_info_by_id($courseId);
6807
    $course_code = $courseInfo['code'];
6808
6809
    $url_id = api_get_current_access_url_id();
6810
    if (api_is_platform_admin_by_id($user_id, $url_id)) {
6811
        $user_roles[] = PLATFORM_ADMIN;
6812
    }
6813
6814
    /*if (api_is_drh()) {
6815
        $user_roles[] = DRH;
6816
    }*/
6817
6818
    if (!empty($session_id)) {
6819
        if (SessionManager::user_is_general_coach($user_id, $session_id)) {
6820
            $user_roles[] = SESSION_GENERAL_COACH;
6821
        }
6822
    }
6823
6824
    if (!empty($course_code)) {
6825
        if (empty($session_id)) {
6826
            if (CourseManager::isCourseTeacher($user_id, $courseInfo['real_id'])) {
6827
                $user_roles[] = COURSEMANAGER;
6828
            }
6829
            if (CourseManager::get_tutor_in_course_status($user_id, $courseInfo['real_id'])) {
6830
                $user_roles[] = COURSE_TUTOR;
6831
            }
6832
6833
            if (CourseManager::is_user_subscribed_in_course($user_id, $course_code)) {
6834
                $user_roles[] = COURSE_STUDENT;
6835
            }
6836
        } else {
6837
            $user_status_in_session = SessionManager::get_user_status_in_course_session(
6838
                $user_id,
6839
                $courseId,
6840
                $session_id
6841
            );
6842
6843
            if (!empty($user_status_in_session)) {
6844
                if (0 == $user_status_in_session) {
6845
                    $user_roles[] = SESSION_STUDENT;
6846
                }
6847
                if (2 == $user_status_in_session) {
6848
                    $user_roles[] = SESSION_COURSE_COACH;
6849
                }
6850
            }
6851
6852
            /*if (api_is_course_session_coach($user_id, $course_code, $session_id)) {
6853
               $user_roles[] = SESSION_COURSE_COACH;
6854
            }*/
6855
        }
6856
    }
6857
6858
    return $user_roles;
6859
}
6860
6861
/**
6862
 * @param int $courseId
6863
 * @param int $session_id
6864
 *
6865
 * @return bool
6866
 */
6867
function api_coach_can_edit_view_results($courseId = null, $session_id = null)
6868
{
6869
    if (api_is_platform_admin()) {
6870
        return true;
6871
    }
6872
6873
    $user_id = api_get_user_id();
6874
6875
    if (empty($courseId)) {
6876
        $courseId = api_get_course_int_id();
6877
    }
6878
6879
    if (empty($session_id)) {
6880
        $session_id = api_get_session_id();
6881
    }
6882
6883
    $roles = api_detect_user_roles($user_id, $courseId, $session_id);
6884
6885
    if (in_array(SESSION_COURSE_COACH, $roles)) {
6886
        //return api_get_setting('session_tutor_reports_visibility') == 'true';
6887
        return true;
6888
    } else {
6889
        if (in_array(COURSEMANAGER, $roles)) {
6890
            return true;
6891
        }
6892
6893
        return false;
6894
    }
6895
}
6896
6897
/**
6898
 * @param string $file
6899
 *
6900
 * @return string
6901
 */
6902
function api_get_js_simple($file)
6903
{
6904
    return '<script type="text/javascript" src="'.$file.'"></script>'."\n";
6905
}
6906
6907
/**
6908
 * Modify default memory_limit and max_execution_time limits
6909
 * Needed when processing long tasks.
6910
 */
6911
function api_set_more_memory_and_time_limits()
6912
{
6913
    if (function_exists('ini_set')) {
6914
        api_set_memory_limit('256M');
6915
        ini_set('max_execution_time', 1800);
6916
    }
6917
}
6918
6919
/**
6920
 * Tries to set memory limit, if authorized and new limit is higher than current.
6921
 *
6922
 * @param string $mem New memory limit
6923
 *
6924
 * @return bool True on success, false on failure or current is higher than suggested
6925
 * @assert (null) === false
6926
 * @assert (-1) === false
6927
 * @assert (0) === true
6928
 * @assert ('1G') === true
6929
 */
6930
function api_set_memory_limit($mem)
6931
{
6932
    //if ini_set() not available, this function is useless
6933
    if (!function_exists('ini_set') || is_null($mem) || -1 == $mem) {
6934
        return false;
6935
    }
6936
6937
    $memory_limit = ini_get('memory_limit');
6938
    if (api_get_bytes_memory_limit($mem) > api_get_bytes_memory_limit($memory_limit)) {
6939
        ini_set('memory_limit', $mem);
6940
6941
        return true;
6942
    }
6943
6944
    return false;
6945
}
6946
6947
/**
6948
 * Gets memory limit in bytes.
6949
 *
6950
 * @param string The memory size (128M, 1G, 1000K, etc)
6951
 *
6952
 * @return int
6953
 * @assert (null) === false
6954
 * @assert ('1t')  === 1099511627776
6955
 * @assert ('1g')  === 1073741824
6956
 * @assert ('1m')  === 1048576
6957
 * @assert ('100k') === 102400
6958
 */
6959
function api_get_bytes_memory_limit($mem)
6960
{
6961
    $size = strtolower(substr($mem, -1));
6962
6963
    switch ($size) {
6964
        case 't':
6965
            $mem = intval(substr($mem, -1)) * 1024 * 1024 * 1024 * 1024;
6966
            break;
6967
        case 'g':
6968
            $mem = intval(substr($mem, 0, -1)) * 1024 * 1024 * 1024;
6969
            break;
6970
        case 'm':
6971
            $mem = intval(substr($mem, 0, -1)) * 1024 * 1024;
6972
            break;
6973
        case 'k':
6974
            $mem = intval(substr($mem, 0, -1)) * 1024;
6975
            break;
6976
        default:
6977
            // we assume it's integer only
6978
            $mem = intval($mem);
6979
            break;
6980
    }
6981
6982
    return $mem;
6983
}
6984
6985
/**
6986
 * Finds all the information about a user from username instead of user id.
6987
 *
6988
 * @param string $officialCode
6989
 *
6990
 * @return array $user_info user_id, lastname, firstname, username, email, ...
6991
 *
6992
 * @author Yannick Warnier <[email protected]>
6993
 */
6994
function api_get_user_info_from_official_code($officialCode)
6995
{
6996
    if (empty($officialCode)) {
6997
        return false;
6998
    }
6999
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
7000
            WHERE official_code ='".Database::escape_string($officialCode)."'";
7001
    $result = Database::query($sql);
7002
    if (Database::num_rows($result) > 0) {
7003
        $result_array = Database::fetch_array($result);
7004
7005
        return _api_format_user($result_array);
7006
    }
7007
7008
    return false;
7009
}
7010
7011
/**
7012
 * @param string $usernameInputId
7013
 * @param string $passwordInputId
7014
 *
7015
 * @return string|null
7016
 */
7017
function api_get_password_checker_js($usernameInputId, $passwordInputId)
7018
{
7019
    $checkPass = api_get_setting('allow_strength_pass_checker');
7020
    $useStrengthPassChecker = 'true' === $checkPass;
7021
7022
    if (false === $useStrengthPassChecker) {
7023
        return null;
7024
    }
7025
7026
    $translations = [
7027
        'wordLength' => get_lang('The password is too short'),
7028
        'wordNotEmail' => get_lang('Your password cannot be the same as your email'),
7029
        'wordSimilarToUsername' => get_lang('Your password cannot contain your username'),
7030
        'wordTwoCharacterClasses' => get_lang('Use different character classes'),
7031
        'wordRepetitions' => get_lang('Too many repetitions'),
7032
        'wordSequences' => get_lang('Your password contains sequences'),
7033
        'errorList' => get_lang('errors found'),
7034
        'veryWeak' => get_lang('Very weak'),
7035
        'weak' => get_lang('Weak'),
7036
        'normal' => get_lang('Normal'),
7037
        'medium' => get_lang('Medium'),
7038
        'strong' => get_lang('Strong'),
7039
        'veryStrong' => get_lang('Very strong'),
7040
    ];
7041
7042
    $js = api_get_asset('pwstrength-bootstrap/dist/pwstrength-bootstrap.js');
7043
    $js .= "<script>
7044
    var errorMessages = {
7045
        password_to_short : \"".get_lang('The password is too short')."\",
7046
        same_as_username : \"".get_lang('Your password cannot be the same as your username')."\"
7047
    };
7048
7049
    $(function() {
7050
        var lang = ".json_encode($translations).";
7051
        var options = {
7052
            onLoad : function () {
7053
                //$('#messages').text('Start typing password');
7054
            },
7055
            onKeyUp: function (evt) {
7056
                $(evt.target).pwstrength('outputErrorList');
7057
            },
7058
            errorMessages : errorMessages,
7059
            viewports: {
7060
                progress: '#password_progress',
7061
                verdict: '#password-verdict',
7062
                errors: '#password-errors'
7063
            },
7064
            usernameField: '$usernameInputId'
7065
        };
7066
        options.i18n = {
7067
            t: function (key) {
7068
                var result = lang[key];
7069
                return result === key ? '' : result; // This assumes you return the
7070
            }
7071
        };
7072
        $('".$passwordInputId."').pwstrength(options);
7073
    });
7074
    </script>";
7075
7076
    return $js;
7077
}
7078
7079
/**
7080
 * create an user extra field called 'captcha_blocked_until_date'.
7081
 *
7082
 * @param string $username
7083
 *
7084
 * @return bool
7085
 */
7086
function api_block_account_captcha($username)
7087
{
7088
    $userInfo = api_get_user_info_from_username($username);
7089
    if (empty($userInfo)) {
7090
        return false;
7091
    }
7092
    $minutesToBlock = api_get_setting('captcha_time_to_block');
7093
    $time = time() + $minutesToBlock * 60;
7094
    UserManager::update_extra_field_value(
7095
        $userInfo['user_id'],
7096
        'captcha_blocked_until_date',
7097
        api_get_utc_datetime($time)
7098
    );
7099
7100
    return true;
7101
}
7102
7103
/**
7104
 * @param string $username
7105
 *
7106
 * @return bool
7107
 */
7108
function api_clean_account_captcha($username)
7109
{
7110
    $userInfo = api_get_user_info_from_username($username);
7111
    if (empty($userInfo)) {
7112
        return false;
7113
    }
7114
    Session::erase('loginFailedCount');
7115
    UserManager::update_extra_field_value(
7116
        $userInfo['user_id'],
7117
        'captcha_blocked_until_date',
7118
        null
7119
    );
7120
7121
    return true;
7122
}
7123
7124
/**
7125
 * @param string $username
7126
 *
7127
 * @return bool
7128
 */
7129
function api_get_user_blocked_by_captcha($username)
7130
{
7131
    $userInfo = api_get_user_info_from_username($username);
7132
    if (empty($userInfo)) {
7133
        return false;
7134
    }
7135
    $data = UserManager::get_extra_user_data_by_field(
7136
        $userInfo['user_id'],
7137
        'captcha_blocked_until_date'
7138
    );
7139
    if (isset($data) && isset($data['captcha_blocked_until_date'])) {
7140
        return $data['captcha_blocked_until_date'];
7141
    }
7142
7143
    return false;
7144
}
7145
7146
/**
7147
 * Remove tags from HTML anf return the $in_number_char first non-HTML char
7148
 * Postfix the text with "..." if it has been truncated.
7149
 *
7150
 * @param string $text
7151
 * @param int    $number
7152
 *
7153
 * @return string
7154
 *
7155
 * @author hubert borderiou
7156
 */
7157
function api_get_short_text_from_html($text, $number)
7158
{
7159
    // Delete script and style tags
7160
    $text = preg_replace('/(<(script|style)\b[^>]*>).*?(<\/\2>)/is', "$1$3", $text);
7161
    $text = api_html_entity_decode($text);
7162
    $out_res = api_remove_tags_with_space($text, false);
7163
    $postfix = "...";
7164
    if (strlen($out_res) > $number) {
7165
        $out_res = substr($out_res, 0, $number).$postfix;
7166
    }
7167
7168
    return $out_res;
7169
}
7170
7171
/**
7172
 * Replace tags with a space in a text.
7173
 * If $in_double_quote_replace, replace " with '' (for HTML attribute purpose, for exemple).
7174
 *
7175
 * @return string
7176
 *
7177
 * @author hubert borderiou
7178
 */
7179
function api_remove_tags_with_space($in_html, $in_double_quote_replace = true)
7180
{
7181
    $out_res = $in_html;
7182
    if ($in_double_quote_replace) {
7183
        $out_res = str_replace('"', "''", $out_res);
7184
    }
7185
    // avoid text stuck together when tags are removed, adding a space after >
7186
    $out_res = str_replace(">", "> ", $out_res);
7187
    $out_res = strip_tags($out_res);
7188
7189
    return $out_res;
7190
}
7191
7192
/**
7193
 * If true, the drh can access all content (courses, users) inside a session.
7194
 *
7195
 * @return bool
7196
 */
7197
function api_drh_can_access_all_session_content()
7198
{
7199
    return 'true' === api_get_setting('drh_can_access_all_session_content');
7200
}
7201
7202
/**
7203
 * @param string $tool
7204
 * @param string $setting
7205
 * @param int    $defaultValue
7206
 *
7207
 * @return string
7208
 */
7209
function api_get_default_tool_setting($tool, $setting, $defaultValue)
7210
{
7211
    global $_configuration;
7212
    if (isset($_configuration[$tool]) &&
7213
        isset($_configuration[$tool]['default_settings']) &&
7214
        isset($_configuration[$tool]['default_settings'][$setting])
7215
    ) {
7216
        return $_configuration[$tool]['default_settings'][$setting];
7217
    }
7218
7219
    return $defaultValue;
7220
}
7221
7222
/**
7223
 * Checks if user can login as another user.
7224
 *
7225
 * @param int $loginAsUserId the user id to log in
7226
 * @param int $userId        my user id
7227
 *
7228
 * @return bool
7229
 */
7230
function api_can_login_as($loginAsUserId, $userId = null)
7231
{
7232
    $loginAsUserId = (int) $loginAsUserId;
7233
7234
    if (empty($loginAsUserId)) {
7235
        return false;
7236
    }
7237
7238
    if (empty($userId)) {
7239
        $userId = api_get_user_id();
7240
    }
7241
7242
    if ($loginAsUserId == $userId) {
7243
        return false;
7244
    }
7245
7246
    // Check if the user to login is an admin
7247
    if (api_is_platform_admin_by_id($loginAsUserId)) {
7248
        // Only super admins can login to admin accounts
7249
        if (!api_global_admin_can_edit_admin($loginAsUserId)) {
7250
            return false;
7251
        }
7252
    }
7253
7254
    $userInfo = api_get_user_info($loginAsUserId);
7255
    $isDrh = function () use ($loginAsUserId) {
7256
        if (api_is_drh()) {
7257
            if (api_drh_can_access_all_session_content()) {
7258
                $users = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus(
7259
                    'drh_all',
7260
                    api_get_user_id()
7261
                );
7262
                $userList = [];
7263
                if (is_array($users)) {
7264
                    foreach ($users as $user) {
7265
                        $userList[] = $user['id'];
7266
                    }
7267
                }
7268
                if (in_array($loginAsUserId, $userList)) {
7269
                    return true;
7270
                }
7271
            } else {
7272
                if (api_is_drh() &&
7273
                    UserManager::is_user_followed_by_drh($loginAsUserId, api_get_user_id())
7274
                ) {
7275
                    return true;
7276
                }
7277
            }
7278
        }
7279
7280
        return false;
7281
    };
7282
7283
    $loginAsStatusForSessionAdmins = [STUDENT];
7284
7285
    if (api_get_setting('session.allow_session_admin_login_as_teacher')) {
7286
        $loginAsStatusForSessionAdmins[] = COURSEMANAGER;
7287
    }
7288
7289
    return api_is_platform_admin() ||
7290
        (api_is_session_admin() && in_array($userInfo['status'], $loginAsStatusForSessionAdmins)) ||
7291
        $isDrh();
7292
}
7293
7294
/**
7295
 * @return bool
7296
 */
7297
function api_is_allowed_in_course()
7298
{
7299
    if (api_is_platform_admin()) {
7300
        return true;
7301
    }
7302
7303
    $user = api_get_current_user();
7304
    if ($user instanceof User) {
7305
        if ($user->hasRole('ROLE_CURRENT_COURSE_SESSION_STUDENT') ||
7306
            $user->hasRole('ROLE_CURRENT_COURSE_SESSION_TEACHER') ||
7307
            $user->hasRole('ROLE_CURRENT_COURSE_STUDENT') ||
7308
            $user->hasRole('ROLE_CURRENT_COURSE_TEACHER')
7309
        ) {
7310
            return true;
7311
        }
7312
    }
7313
7314
    return false;
7315
}
7316
7317
/**
7318
 * Return true on https install.
7319
 *
7320
 * @return bool
7321
 */
7322
function api_is_https()
7323
{
7324
    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...
7325
        'https' == $_SERVER['HTTP_X_FORWARDED_PROTO'] || !empty(api_get_configuration_value('force_https_forwarded_proto'))
7326
    ) {
7327
        $isSecured = true;
7328
    } else {
7329
        if (!empty($_SERVER['HTTPS']) && 'off' != $_SERVER['HTTPS']) {
7330
            $isSecured = true;
7331
        } else {
7332
            $isSecured = false;
7333
            // last chance
7334
            if (!empty($_SERVER['SERVER_PORT']) && 443 == $_SERVER['SERVER_PORT']) {
7335
                $isSecured = true;
7336
            }
7337
        }
7338
    }
7339
7340
    return $isSecured;
7341
}
7342
7343
/**
7344
 * Return protocol (http or https).
7345
 *
7346
 * @return string
7347
 */
7348
function api_get_protocol()
7349
{
7350
    return api_is_https() ? 'https' : 'http';
7351
}
7352
7353
/**
7354
 * Get origin.
7355
 *
7356
 * @param string
7357
 *
7358
 * @return string
7359
 */
7360
function api_get_origin()
7361
{
7362
    return isset($_REQUEST['origin']) ? Security::remove_XSS($_REQUEST['origin']) : '';
7363
}
7364
7365
/**
7366
 * Warns an user that the portal reach certain limit.
7367
 *
7368
 * @param string $limitName
7369
 */
7370
function api_warn_hosting_contact($limitName)
7371
{
7372
    $hostingParams = api_get_configuration_value(1);
7373
    $email = null;
7374
7375
    if (!empty($hostingParams)) {
7376
        if (isset($hostingParams['hosting_contact_mail'])) {
7377
            $email = $hostingParams['hosting_contact_mail'];
7378
        }
7379
    }
7380
7381
    if (!empty($email)) {
7382
        $subject = get_lang('Hosting warning reached');
7383
        $body = get_lang('Portal name').': '.api_get_path(WEB_PATH)." \n ";
7384
        $body .= get_lang('Portal\'s limit type').': '.$limitName." \n ";
7385
        if (isset($hostingParams[$limitName])) {
7386
            $body .= get_lang('Value').': '.$hostingParams[$limitName];
7387
        }
7388
        api_mail_html(null, $email, $subject, $body);
7389
    }
7390
}
7391
7392
/**
7393
 * Gets value of a variable from config/configuration.php
7394
 * Variables that are not set in the configuration.php file but set elsewhere:
7395
 * - virtual_css_theme_folder (vchamilo plugin)
7396
 * - access_url (global.inc.php)
7397
 * - apc/apc_prefix (global.inc.php).
7398
 *
7399
 * @param string $variable
7400
 *
7401
 * @return bool|mixed
7402
 */
7403
function api_get_configuration_value($variable)
7404
{
7405
    global $_configuration;
7406
    // Check the current url id, id = 1 by default
7407
    $urlId = isset($_configuration['access_url']) ? (int) $_configuration['access_url'] : 1;
7408
7409
    $variable = trim($variable);
7410
7411
    // Check if variable exists
7412
    if (isset($_configuration[$variable])) {
7413
        if (is_array($_configuration[$variable])) {
7414
            // Check if it exists for the sub portal
7415
            if (array_key_exists($urlId, $_configuration[$variable])) {
7416
                return $_configuration[$variable][$urlId];
7417
            } else {
7418
                // Try to found element with id = 1 (master portal)
7419
                if (array_key_exists(1, $_configuration[$variable])) {
7420
                    return $_configuration[$variable][1];
7421
                }
7422
            }
7423
        }
7424
7425
        return $_configuration[$variable];
7426
    }
7427
7428
    return false;
7429
}
7430
7431
/**
7432
 * Retreives and returns a value in a hierarchical configuration array
7433
 * api_get_configuration_sub_value('a/b/c') returns api_get_configuration_value('a')['b']['c'].
7434
 *
7435
 * @param string $path      the successive array keys, separated by the separator
7436
 * @param mixed  $default   value to be returned if not found, null by default
7437
 * @param string $separator '/' by default
7438
 * @param array  $array     the active configuration array by default
7439
 *
7440
 * @return mixed the found value or $default
7441
 */
7442
function api_get_configuration_sub_value($path, $default = null, $separator = '/', $array = null)
7443
{
7444
    $pos = strpos($path, $separator);
7445
    if (false === $pos) {
7446
        if (is_null($array)) {
7447
            return api_get_configuration_value($path);
7448
        }
7449
        if (is_array($array) && array_key_exists($path, $array)) {
7450
            return $array[$path];
7451
        }
7452
7453
        return $default;
7454
    }
7455
    $key = substr($path, 0, $pos);
7456
    if (is_null($array)) {
7457
        $newArray = api_get_configuration_value($key);
7458
    } elseif (is_array($array) && array_key_exists($key, $array)) {
7459
        $newArray = $array[$key];
7460
    } else {
7461
        return $default;
7462
    }
7463
    if (is_array($newArray)) {
7464
        $newPath = substr($path, $pos + 1);
7465
7466
        return api_get_configuration_sub_value($newPath, $default, $separator, $newArray);
7467
    }
7468
7469
    return $default;
7470
}
7471
7472
/**
7473
 * Retrieves and returns a value in a hierarchical configuration array
7474
 * api_array_sub_value($array, 'a/b/c') returns $array['a']['b']['c'].
7475
 *
7476
 * @param array  $array     the recursive array that contains the value to be returned (or not)
7477
 * @param string $path      the successive array keys, separated by the separator
7478
 * @param mixed  $default   the value to be returned if not found
7479
 * @param string $separator the separator substring
7480
 *
7481
 * @return mixed the found value or $default
7482
 */
7483
function api_array_sub_value($array, $path, $default = null, $separator = '/')
7484
{
7485
    $pos = strpos($path, $separator);
7486
    if (false === $pos) {
7487
        if (is_array($array) && array_key_exists($path, $array)) {
7488
            return $array[$path];
7489
        }
7490
7491
        return $default;
7492
    }
7493
    $key = substr($path, 0, $pos);
7494
    if (is_array($array) && array_key_exists($key, $array)) {
7495
        $newArray = $array[$key];
7496
    } else {
7497
        return $default;
7498
    }
7499
    if (is_array($newArray)) {
7500
        $newPath = substr($path, $pos + 1);
7501
7502
        return api_array_sub_value($newArray, $newPath, $default);
7503
    }
7504
7505
    return $default;
7506
}
7507
7508
/**
7509
 * Returns supported image extensions in the portal.
7510
 *
7511
 * @param bool $supportVectors Whether vector images should also be accepted or not
7512
 *
7513
 * @return array Supported image extensions in the portal
7514
 */
7515
function api_get_supported_image_extensions($supportVectors = true)
7516
{
7517
    // jpg can also be called jpeg, jpe, jfif and jif. See https://en.wikipedia.org/wiki/JPEG#JPEG_filename_extensions
7518
    $supportedImageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'jpe', 'jfif', 'jif'];
7519
    if ($supportVectors) {
7520
        array_push($supportedImageExtensions, 'svg');
7521
    }
7522
    if (version_compare(PHP_VERSION, '5.5.0', '>=')) {
7523
        array_push($supportedImageExtensions, 'webp');
7524
    }
7525
7526
    return $supportedImageExtensions;
7527
}
7528
7529
/**
7530
 * This setting changes the registration status for the campus.
7531
 *
7532
 * @author Patrick Cool <[email protected]>, Ghent University
7533
 *
7534
 * @version August 2006
7535
 *
7536
 * @param bool $listCampus Whether we authorize
7537
 *
7538
 * @todo the $_settings should be reloaded here. => write api function for this and use this in global.inc.php also.
7539
 */
7540
function api_register_campus($listCampus = true)
7541
{
7542
    $tbl_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
7543
7544
    $sql = "UPDATE $tbl_settings SET selected_value='true' WHERE variable='registered'";
7545
    Database::query($sql);
7546
7547
    if (!$listCampus) {
7548
        $sql = "UPDATE $tbl_settings SET selected_value='true' WHERE variable='donotlistcampus'";
7549
        Database::query($sql);
7550
    }
7551
}
7552
7553
/**
7554
 * Checks whether current user is a student boss.
7555
 *
7556
 * @global array $_user
7557
 *
7558
 * @return bool
7559
 */
7560
function api_is_student_boss()
7561
{
7562
    $_user = api_get_user_info();
7563
7564
    return isset($_user['status']) && STUDENT_BOSS == $_user['status'];
7565
}
7566
7567
/**
7568
 * Check whether the user type should be exclude.
7569
 * Such as invited or anonymous users.
7570
 *
7571
 * @param bool $checkDB Optional. Whether check the user status
7572
 * @param int  $userId  Options. The user id
7573
 *
7574
 * @return bool
7575
 */
7576
function api_is_excluded_user_type($checkDB = false, $userId = 0)
7577
{
7578
    if ($checkDB) {
7579
        $userId = empty($userId) ? api_get_user_id() : (int) $userId;
7580
7581
        if (0 == $userId) {
7582
            return true;
7583
        }
7584
7585
        $userInfo = api_get_user_info($userId);
7586
7587
        switch ($userInfo['status']) {
7588
            case INVITEE:
7589
            case ANONYMOUS:
7590
                return true;
7591
            default:
7592
                return false;
7593
        }
7594
    }
7595
7596
    $isInvited = api_is_invitee();
7597
    $isAnonymous = api_is_anonymous();
7598
7599
    if ($isInvited || $isAnonymous) {
7600
        return true;
7601
    }
7602
7603
    return false;
7604
}
7605
7606
/**
7607
 * Get the user status to ignore in reports.
7608
 *
7609
 * @param string $format Optional. The result type (array or string)
7610
 *
7611
 * @return array|string
7612
 */
7613
function api_get_users_status_ignored_in_reports($format = 'array')
7614
{
7615
    $excludedTypes = [
7616
        INVITEE,
7617
        ANONYMOUS,
7618
    ];
7619
7620
    if ('string' == $format) {
7621
        return implode(', ', $excludedTypes);
7622
    }
7623
7624
    return $excludedTypes;
7625
}
7626
7627
/**
7628
 * Set the Site Use Cookie Warning for 1 year.
7629
 */
7630
function api_set_site_use_cookie_warning_cookie()
7631
{
7632
    setcookie('ChamiloUsesCookies', 'ok', time() + 31556926);
7633
}
7634
7635
/**
7636
 * Return true if the Site Use Cookie Warning Cookie warning exists.
7637
 *
7638
 * @return bool
7639
 */
7640
function api_site_use_cookie_warning_cookie_exist()
7641
{
7642
    return isset($_COOKIE['ChamiloUsesCookies']);
7643
}
7644
7645
/**
7646
 * Given a number of seconds, format the time to show hours, minutes and seconds.
7647
 *
7648
 * @param int    $time         The time in seconds
7649
 * @param string $originFormat Optional. PHP o JS
7650
 *
7651
 * @return string (00h00'00")
7652
 */
7653
function api_format_time($time, $originFormat = 'php')
7654
{
7655
    $h = get_lang('h');
7656
    $hours = $time / 3600;
7657
    $mins = ($time % 3600) / 60;
7658
    $secs = ($time % 60);
7659
7660
    if ($time < 0) {
7661
        $hours = 0;
7662
        $mins = 0;
7663
        $secs = 0;
7664
    }
7665
7666
    if ('js' === $originFormat) {
7667
        $formattedTime = trim(sprintf("%02d : %02d : %02d", $hours, $mins, $secs));
7668
    } else {
7669
        $formattedTime = trim(sprintf("%02d$h%02d'%02d\"", $hours, $mins, $secs));
7670
    }
7671
7672
    return $formattedTime;
7673
}
7674
7675
/**
7676
 * Sends an email
7677
 * Sender name and email can be specified, if not specified
7678
 * name and email of the platform admin are used.
7679
 *
7680
 * @param string    name of recipient
7681
 * @param string    email of recipient
7682
 * @param string    email subject
7683
 * @param string    email body
7684
 * @param string    sender name
7685
 * @param string    sender e-mail
7686
 * @param array     extra headers in form $headers = array($name => $value) to allow parsing
7687
 * @param array     data file (path and filename)
7688
 * @param bool      True for attaching a embedded file inside content html (optional)
7689
 * @param array     Additional parameters
7690
 *
7691
 * @return bool true if mail was sent
7692
 */
7693
function api_mail_html(
7694
    $recipientName,
7695
    $recipientEmail,
7696
    $subject,
7697
    $body,
7698
    $senderName = '',
7699
    $senderEmail = '',
7700
    $extra_headers = [],
7701
    $data_file = [],
7702
    $embeddedImage = false,
7703
    $additionalParameters = []
7704
) {
7705
    if (!api_valid_email($recipientEmail)) {
7706
        return false;
7707
    }
7708
7709
    // Default values
7710
    $notification = new Notification();
7711
    $defaultEmail = $notification->getDefaultPlatformSenderEmail();
7712
    $defaultName = $notification->getDefaultPlatformSenderName();
7713
7714
    // If the parameter is set don't use the admin.
7715
    $senderName = !empty($senderName) ? $senderName : $defaultName;
7716
    $senderEmail = !empty($senderEmail) ? $senderEmail : $defaultEmail;
7717
7718
    // Reply to first
7719
    $replyToName = '';
7720
    $replyToEmail = '';
7721
    if (isset($extra_headers['reply_to'])) {
7722
        $replyToEmail = $extra_headers['reply_to']['mail'];
7723
        $replyToName = $extra_headers['reply_to']['name'];
7724
    }
7725
7726
    try {
7727
        $message = new TemplatedEmail();
7728
        $message->subject($subject);
7729
7730
        $list = api_get_configuration_value('send_all_emails_to');
7731
        if (!empty($list) && isset($list['emails'])) {
7732
            foreach ($list['emails'] as $email) {
7733
                $message->cc($email);
7734
            }
7735
        }
7736
7737
        // Attachment
7738
        if (!empty($data_file)) {
7739
            foreach ($data_file as $file_attach) {
7740
                if (!empty($file_attach['path']) && !empty($file_attach['filename'])) {
7741
                    $message->attachFromPath($file_attach['path'], $file_attach['filename']);
7742
                }
7743
            }
7744
        }
7745
7746
        $noReply = api_get_setting('noreply_email_address');
7747
        $automaticEmailText = '';
7748
        if (!empty($noReply)) {
7749
            $automaticEmailText = '<br />'.get_lang('This is an automatic email message. Please do not reply to it.');
7750
        }
7751
7752
        $params = [
7753
            'mail_header_style' => api_get_configuration_value('mail_header_style'),
7754
            'mail_content_style' => api_get_configuration_value('mail_content_style'),
7755
            'link' => $additionalParameters['link'] ?? '',
7756
            'automatic_email_text' => $automaticEmailText,
7757
            'content' => $body,
7758
            'theme' => api_get_visual_theme(),
7759
        ];
7760
7761
        if (!empty($senderEmail)) {
7762
            $message->from(new Address($senderEmail, $senderName));
7763
        }
7764
7765
        if (!empty($recipientEmail)) {
7766
            $message->to(new Address($recipientEmail, $recipientName));
7767
        }
7768
7769
        if (!empty($replyToEmail)) {
7770
            $message->replyTo(new Address($replyToEmail, $replyToName));
7771
        }
7772
7773
        $message
7774
            ->htmlTemplate('ChamiloCoreBundle:Mailer:Default/default.html.twig')
7775
            ->textTemplate('ChamiloCoreBundle:Mailer:Default/default.text.twig')
7776
        ;
7777
        $message->context($params);
7778
        Container::getMailer()->send($message);
7779
7780
        return true;
7781
    } catch (Exception $e) {
7782
        error_log($e->getMessage());
7783
    }
7784
7785
    if (!empty($additionalParameters)) {
7786
        $plugin = new AppPlugin();
7787
        $smsPlugin = $plugin->getSMSPluginLibrary();
7788
        if ($smsPlugin) {
0 ignored issues
show
introduced by
$smsPlugin is of type SmsPluginLibraryInterface, thus it always evaluated to true.
Loading history...
7789
            $smsPlugin->send($additionalParameters);
7790
        }
7791
    }
7792
7793
    return 1;
7794
}
7795
7796
/**
7797
 * @param int  $tool Possible values: GroupManager::GROUP_TOOL_*
7798
 * @param bool $showHeader
7799
 */
7800
function api_protect_course_group($tool, $showHeader = true)
7801
{
7802
    $groupId = api_get_group_id();
7803
    if (!empty($groupId)) {
7804
        if (api_is_platform_admin()) {
7805
            return true;
7806
        }
7807
7808
        if (api_is_allowed_to_edit(false, true, true)) {
7809
            return true;
7810
        }
7811
7812
        $userId = api_get_user_id();
7813
        $sessionId = api_get_session_id();
7814
        if (!empty($sessionId)) {
7815
            if (api_is_coach($sessionId, api_get_course_int_id())) {
7816
                return true;
7817
            }
7818
7819
            if (api_is_drh()) {
7820
                if (SessionManager::isUserSubscribedAsHRM($sessionId, $userId)) {
7821
                    return true;
7822
                }
7823
            }
7824
        }
7825
7826
        $group = api_get_group_entity($groupId);
7827
7828
        // Group doesn't exists
7829
        if (null === $group) {
7830
            api_not_allowed($showHeader);
7831
        }
7832
7833
        // Check group access
7834
        $allow = GroupManager::userHasAccess(
7835
            $userId,
7836
            $group,
7837
            $tool
7838
        );
7839
7840
        if (!$allow) {
7841
            api_not_allowed($showHeader);
7842
        }
7843
    }
7844
7845
    return false;
7846
}
7847
7848
/**
7849
 * Check if a date is in a date range.
7850
 *
7851
 * @param datetime $startDate
7852
 * @param datetime $endDate
7853
 * @param datetime $currentDate
7854
 *
7855
 * @return bool true if date is in rage, false otherwise
7856
 */
7857
function api_is_date_in_date_range($startDate, $endDate, $currentDate = null)
7858
{
7859
    $startDate = strtotime(api_get_local_time($startDate));
7860
    $endDate = strtotime(api_get_local_time($endDate));
7861
    $currentDate = strtotime(api_get_local_time($currentDate));
7862
7863
    if ($currentDate >= $startDate && $currentDate <= $endDate) {
7864
        return true;
7865
    }
7866
7867
    return false;
7868
}
7869
7870
/**
7871
 * Eliminate the duplicates of a multidimensional array by sending the key.
7872
 *
7873
 * @param array $array multidimensional array
7874
 * @param int   $key   key to find to compare
7875
 *
7876
 * @return array
7877
 */
7878
function api_unique_multidim_array($array, $key)
7879
{
7880
    $temp_array = [];
7881
    $i = 0;
7882
    $key_array = [];
7883
7884
    foreach ($array as $val) {
7885
        if (!in_array($val[$key], $key_array)) {
7886
            $key_array[$i] = $val[$key];
7887
            $temp_array[$i] = $val;
7888
        }
7889
        $i++;
7890
    }
7891
7892
    return $temp_array;
7893
}
7894
7895
/**
7896
 * Limit the access to Session Admins when the limit_session_admin_role
7897
 * configuration variable is set to true.
7898
 */
7899
function api_protect_limit_for_session_admin()
7900
{
7901
    $limitAdmin = api_get_setting('limit_session_admin_role');
7902
    if (api_is_session_admin() && 'true' === $limitAdmin) {
7903
        api_not_allowed(true);
7904
    }
7905
}
7906
7907
/**
7908
 * Limits that a session admin has access to list users.
7909
 * When limit_session_admin_list_users configuration variable is set to true.
7910
 */
7911
function api_protect_session_admin_list_users()
7912
{
7913
    $limitAdmin = api_get_configuration_value('limit_session_admin_list_users');
7914
7915
    if (api_is_session_admin() && true === $limitAdmin) {
7916
        api_not_allowed(true);
7917
    }
7918
}
7919
7920
/**
7921
 * @return bool
7922
 */
7923
function api_is_student_view_active()
7924
{
7925
    $studentView = Session::read('studentview');
7926
7927
    return 'studentview' === $studentView;
7928
}
7929
7930
/**
7931
 * Adds a file inside the upload/$type/id.
7932
 *
7933
 * @param string $type
7934
 * @param array  $file
7935
 * @param int    $itemId
7936
 * @param string $cropParameters
7937
 *
7938
 * @return array|bool
7939
 */
7940
function api_upload_file($type, $file, $itemId, $cropParameters = '')
7941
{
7942
    throw new Exception('api_upload_file not implemented');
7943
    $upload = process_uploaded_file($file);
0 ignored issues
show
Unused Code introduced by
$upload = process_uploaded_file($file) 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...
7944
    if ($upload) {
7945
        $name = api_replace_dangerous_char($file['name']);
7946
7947
        // No "dangerous" files
7948
        $name = disable_dangerous_file($name);
7949
7950
        $pathId = '/'.substr((string) $itemId, 0, 1).'/'.$itemId.'/';
7951
        $path = api_get_path(SYS_UPLOAD_PATH).$type.$pathId;
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...
7952
7953
        if (!is_dir($path)) {
7954
            mkdir($path, api_get_permissions_for_new_directories(), true);
7955
        }
7956
7957
        $pathToSave = $path.$name;
7958
        $result = moveUploadedFile($file, $pathToSave);
7959
7960
        if ($result) {
7961
            if (!empty($cropParameters)) {
7962
                $image = new Image($pathToSave);
7963
                $image->crop($cropParameters);
7964
            }
7965
7966
            return ['path_to_save' => $pathId.$name];
7967
        }
7968
    }
7969
7970
    return false;
7971
}
7972
7973
/**
7974
 * @param string $type
7975
 * @param int    $itemId
7976
 * @param string $file
7977
 *
7978
 * @return bool
7979
 */
7980
function api_get_uploaded_web_url($type, $itemId, $file)
7981
{
7982
    return api_get_uploaded_file($type, $itemId, $file, true);
7983
}
7984
7985
/**
7986
 * @param string $type
7987
 * @param int    $itemId
7988
 * @param string $file
7989
 * @param bool   $getUrl
7990
 *
7991
 * @return bool
7992
 */
7993
function api_get_uploaded_file($type, $itemId, $file, $getUrl = false)
7994
{
7995
    $itemId = (int) $itemId;
7996
    $pathId = '/'.substr((string) $itemId, 0, 1).'/'.$itemId.'/';
7997
    $path = api_get_path(SYS_UPLOAD_PATH).$type.$pathId;
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...
7998
    $file = basename($file);
7999
    $file = $path.'/'.$file;
8000
    if (Security::check_abs_path($file, $path) && is_file($file) && file_exists($file)) {
8001
        if ($getUrl) {
8002
            return str_replace(api_get_path(SYS_UPLOAD_PATH), api_get_path(WEB_UPLOAD_PATH), $file);
0 ignored issues
show
Bug introduced by
The constant WEB_UPLOAD_PATH was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
8003
        }
8004
8005
        return $file;
8006
    }
8007
8008
    return false;
8009
}
8010
8011
/**
8012
 * @param string $type
8013
 * @param int    $itemId
8014
 * @param string $file
8015
 * @param string $title
8016
 */
8017
function api_download_uploaded_file($type, $itemId, $file, $title = '')
8018
{
8019
    $file = api_get_uploaded_file($type, $itemId, $file);
8020
    if ($file) {
8021
        if (Security::check_abs_path($file, api_get_path(SYS_UPLOAD_PATH).$type)) {
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...
8022
            DocumentManager::file_send_for_download($file, true, $title);
8023
            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...
8024
        }
8025
    }
8026
    api_not_allowed(true);
8027
}
8028
8029
/**
8030
 * @param string $type
8031
 * @param string $file
8032
 */
8033
function api_remove_uploaded_file($type, $file)
8034
{
8035
    $typePath = api_get_path(SYS_UPLOAD_PATH).$type;
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...
8036
    $path = $typePath.'/'.$file;
8037
    if (Security::check_abs_path($path, $typePath) && file_exists($path) && is_file($path)) {
8038
        unlink($path);
8039
    }
8040
}
8041
8042
/**
8043
 * @param string $type
8044
 * @param int    $itemId
8045
 * @param string $file
8046
 *
8047
 * @return bool
8048
 */
8049
function api_remove_uploaded_file_by_id($type, $itemId, $file)
8050
{
8051
    $file = api_get_uploaded_file($type, $itemId, $file, false);
8052
    $typePath = api_get_path(SYS_UPLOAD_PATH).$type;
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...
8053
    if (Security::check_abs_path($file, $typePath) && file_exists($file) && is_file($file)) {
8054
        unlink($file);
8055
8056
        return true;
8057
    }
8058
8059
    return false;
8060
}
8061
8062
/**
8063
 * Converts string value to float value.
8064
 *
8065
 * 3.141516 => 3.141516
8066
 * 3,141516 => 3.141516
8067
 *
8068
 * @todo WIP
8069
 *
8070
 * @param string $number
8071
 *
8072
 * @return float
8073
 */
8074
function api_float_val($number)
8075
{
8076
    $number = (float) str_replace(',', '.', trim($number));
8077
8078
    return $number;
8079
}
8080
8081
/**
8082
 * Converts float values
8083
 * Example if $decimals = 2.
8084
 *
8085
 * 3.141516 => 3.14
8086
 * 3,141516 => 3,14
8087
 *
8088
 * @param string $number            number in iso code
8089
 * @param int    $decimals
8090
 * @param string $decimalSeparator
8091
 * @param string $thousandSeparator
8092
 *
8093
 * @return bool|string
8094
 */
8095
function api_number_format($number, $decimals = 0, $decimalSeparator = '.', $thousandSeparator = ',')
8096
{
8097
    $number = api_float_val($number);
8098
8099
    return number_format($number, $decimals, $decimalSeparator, $thousandSeparator);
8100
}
8101
8102
/**
8103
 * Set location url with a exit break by default.
8104
 *
8105
 * @param string $url
8106
 * @param bool   $exit
8107
 */
8108
function api_location($url, $exit = true)
8109
{
8110
    header('Location: '.$url);
8111
8112
    if ($exit) {
8113
        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...
8114
    }
8115
}
8116
8117
/**
8118
 * @param string $from
8119
 * @param string $to
8120
 *
8121
 * @return string
8122
 */
8123
function api_get_relative_path($from, $to)
8124
{
8125
    // some compatibility fixes for Windows paths
8126
    $from = is_dir($from) ? rtrim($from, '\/').'/' : $from;
8127
    $to = is_dir($to) ? rtrim($to, '\/').'/' : $to;
8128
    $from = str_replace('\\', '/', $from);
8129
    $to = str_replace('\\', '/', $to);
8130
8131
    $from = explode('/', $from);
8132
    $to = explode('/', $to);
8133
    $relPath = $to;
8134
8135
    foreach ($from as $depth => $dir) {
8136
        // find first non-matching dir
8137
        if ($dir === $to[$depth]) {
8138
            // ignore this directory
8139
            array_shift($relPath);
8140
        } else {
8141
            // get number of remaining dirs to $from
8142
            $remaining = count($from) - $depth;
8143
            if ($remaining > 1) {
8144
                // add traversals up to first matching dir
8145
                $padLength = (count($relPath) + $remaining - 1) * -1;
8146
                $relPath = array_pad($relPath, $padLength, '..');
8147
                break;
8148
            } else {
8149
                $relPath[0] = './'.$relPath[0];
8150
            }
8151
        }
8152
    }
8153
8154
    return implode('/', $relPath);
8155
}
8156
8157
/**
8158
 * Unserialize content using Brummann\Polyfill\Unserialize.
8159
 *
8160
 * @param string $type
8161
 * @param string $serialized
8162
 *
8163
 * @return mixed
8164
 */
8165
function api_unserialize_content($type, $serialized, $ignoreErrors = false)
8166
{
8167
    switch ($type) {
8168
        case 'career':
8169
        case 'sequence_graph':
8170
            $allowedClasses = [
8171
                \Fhaculty\Graph\Graph::class,
8172
                \Fhaculty\Graph\Set\VerticesMap::class,
8173
                \Fhaculty\Graph\Set\Vertices::class,
8174
                \Fhaculty\Graph\Set\Edges::class,
8175
            ];
8176
            break;
8177
        case 'lp':
8178
            $allowedClasses = [
8179
                learnpath::class,
8180
                learnpathItem::class,
8181
                aicc::class,
8182
                aiccBlock::class,
8183
                aiccItem::class,
8184
                aiccObjective::class,
8185
                aiccResource::class,
8186
                scorm::class,
8187
                scormItem::class,
8188
                scormMetadata::class,
8189
                scormOrganization::class,
8190
                scormResource::class,
8191
                Link::class,
8192
                LpItem::class,
8193
            ];
8194
            break;
8195
        case 'course':
8196
            $allowedClasses = [
8197
                \Chamilo\CourseBundle\Component\CourseCopy\Course::class,
8198
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Announcement::class,
8199
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Attendance::class,
8200
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\CalendarEvent::class,
8201
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\CourseCopyLearnpath::class,
8202
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\CourseCopyTestCategory::class,
8203
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\CourseDescription::class,
8204
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\CourseSession::class,
8205
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Document::class,
8206
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Forum::class,
8207
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\ForumCategory::class,
8208
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\ForumPost::class,
8209
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\ForumTopic::class,
8210
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Glossary::class,
8211
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\GradeBookBackup::class,
8212
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Link::class,
8213
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\LinkCategory::class,
8214
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Quiz::class,
8215
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\QuizQuestion::class,
8216
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\QuizQuestionOption::class,
8217
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\ScormDocument::class,
8218
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Survey::class,
8219
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\SurveyInvitation::class,
8220
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\SurveyQuestion::class,
8221
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Thematic::class,
8222
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\ToolIntro::class,
8223
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Wiki::class,
8224
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Work::class,
8225
                stdClass::class,
8226
            ];
8227
            break;
8228
        case 'not_allowed_classes':
8229
        default:
8230
            $allowedClasses = false;
8231
    }
8232
8233
    if ($ignoreErrors) {
8234
        return @UnserializeApi::unserialize(
8235
            $serialized,
8236
            ['allowed_classes' => $allowedClasses]
8237
        );
8238
    }
8239
8240
    return UnserializeApi::unserialize(
8241
        $serialized,
8242
        ['allowed_classes' => $allowedClasses]
8243
    );
8244
}
8245
8246
/**
8247
 * @param string $template
8248
 *
8249
 * @return string
8250
 */
8251
function api_find_template($template)
8252
{
8253
    return Template::findTemplateFilePath($template);
8254
}
8255
8256
/**
8257
 * @return array
8258
 */
8259
function api_get_language_list_for_flag()
8260
{
8261
    $table = Database::get_main_table(TABLE_MAIN_LANGUAGE);
8262
    $sql = "SELECT english_name, isocode FROM $table
8263
            ORDER BY original_name ASC";
8264
    static $languages = [];
8265
    if (empty($languages)) {
8266
        $result = Database::query($sql);
8267
        while ($row = Database::fetch_array($result)) {
8268
            $languages[$row['english_name']] = $row['isocode'];
8269
        }
8270
        $languages['english'] = 'gb';
8271
    }
8272
8273
    return $languages;
8274
}
8275
8276
/**
8277
 * @param string $name
8278
 *
8279
 * @return ZipStream
8280
 */
8281
function api_create_zip($name)
8282
{
8283
    $zipStreamOptions = new Archive();
8284
    $zipStreamOptions->setSendHttpHeaders(true);
8285
    $zipStreamOptions->setContentDisposition('attachment');
8286
    $zipStreamOptions->setContentType('application/x-zip');
8287
8288
    return new ZipStream($name, $zipStreamOptions);
8289
}
8290
8291
/**
8292
 * @return string
8293
 */
8294
function api_get_language_translate_html()
8295
{
8296
    $translate = api_get_configuration_value('translate_html');
8297
8298
    if (!$translate) {
8299
        return '';
8300
    }
8301
8302
    $languageList = api_get_languages();
8303
    $hideAll = '';
8304
    foreach ($languageList['all'] as $language) {
8305
        $hideAll .= '
8306
        $("span:lang('.$language['isocode'].')").filter(
8307
            function(e, val) {
8308
                // Only find the spans if they have set the lang
8309
                if ($(this).attr("lang") == null) {
8310
                    return false;
8311
                }
8312
8313
                // Ignore ckeditor classes
8314
                return !this.className.match(/cke(.*)/);
8315
        }).hide();'."\n";
8316
    }
8317
8318
    $userInfo = api_get_user_info();
8319
    $languageId = api_get_language_id($userInfo['language']);
8320
    $languageInfo = api_get_language_info($languageId);
8321
    $isoCode = 'en';
8322
8323
    if (!empty($languageInfo)) {
8324
        $isoCode = $languageInfo['isocode'];
8325
    }
8326
8327
    return '
8328
            $(function() {
8329
                '.$hideAll.'
8330
                var defaultLanguageFromUser = "'.$isoCode.'";
8331
8332
                $("span:lang('.$isoCode.')").filter(
8333
                    function() {
8334
                        // Ignore ckeditor classes
8335
                        return !this.className.match(/cke(.*)/);
8336
                }).show();
8337
8338
                var defaultLanguage = "";
8339
                var langFromUserFound = false;
8340
8341
                $(this).find("span").filter(
8342
                    function() {
8343
                        // Ignore ckeditor classes
8344
                        return !this.className.match(/cke(.*)/);
8345
                }).each(function() {
8346
                    defaultLanguage = $(this).attr("lang");
8347
                    if (defaultLanguage) {
8348
                        $(this).before().next("br").remove();
8349
                        if (defaultLanguageFromUser == defaultLanguage) {
8350
                            langFromUserFound = true;
8351
                        }
8352
                    }
8353
                });
8354
8355
                // Show default language
8356
                if (langFromUserFound == false && defaultLanguage) {
8357
                    $("span:lang("+defaultLanguage+")").filter(
8358
                    function() {
8359
                            // Ignore ckeditor classes
8360
                            return !this.className.match(/cke(.*)/);
8361
                    }).show();
8362
                }
8363
            });
8364
    ';
8365
}
8366
8367
/**
8368
 * Filter a multi-language HTML string (for the multi-language HTML
8369
 * feature) into the given language (strip the rest).
8370
 *
8371
 * @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>
8372
 * @param string $language   The language in which we want to get the
8373
 *
8374
 * @throws Exception
8375
 *
8376
 * @return string The filtered string in the given language, or the full string if no translated string was identified
8377
 */
8378
function api_get_filtered_multilingual_HTML_string($htmlString, $language = null)
8379
{
8380
    if (true != api_get_configuration_value('translate_html')) {
8381
        return $htmlString;
8382
    }
8383
    $userInfo = api_get_user_info();
8384
    $languageId = 0;
8385
    if (!empty($language)) {
8386
        $languageId = api_get_language_id($language);
8387
    } elseif (!empty($userInfo['language'])) {
8388
        $languageId = api_get_language_id($userInfo['language']);
8389
    }
8390
    $languageInfo = api_get_language_info($languageId);
8391
    $isoCode = 'en';
8392
8393
    if (!empty($languageInfo)) {
8394
        $isoCode = $languageInfo['isocode'];
8395
    }
8396
8397
    // Split HTML in the separate language strings
8398
    // Note: some strings might look like <p><span ..>...</span></p> but others might be like combine 2 <span> in 1 <p>
8399
    if (!preg_match('/<span.*?lang="(\w\w)">/is', $htmlString)) {
8400
        return $htmlString;
8401
    }
8402
    $matches = [];
8403
    preg_match_all('/<span.*?lang="(\w\w)">(.*?)<\/span>/is', $htmlString, $matches);
8404
    if (!empty($matches)) {
8405
        // matches[0] are the full string
8406
        // matches[1] are the languages
8407
        // matches[2] are the strings
8408
        foreach ($matches[1] as $id => $match) {
8409
            if ($match == $isoCode) {
8410
                return $matches[2][$id];
8411
            }
8412
        }
8413
        // Could find the pattern but could not find our language. Return the first language found.
8414
        return $matches[2][0];
8415
    }
8416
    // Could not find pattern. Just return the whole string. We shouldn't get here.
8417
    return $htmlString;
8418
}
8419