Passed
Push — master ( 42955e...d12b02 )
by Julito
09:41 queued 10s
created

api_remove_uploaded_file()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 4
nc 2
nop 2
dl 0
loc 6
rs 10
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
22
/**
23
 * This is a code library for Chamilo.
24
 * It is included by default in every Chamilo file (through including the global.inc.php)
25
 * This library is in process of being transferred to src/Chamilo/CoreBundle/Component/Utils/ChamiloApi.
26
 * Whenever a function is transferred to the ChamiloApi class, the places where it is used should include
27
 * the "use Chamilo\CoreBundle\Component\Utils\ChamiloApi;" statement.
28
 */
29
30
// PHP version requirement.
31
define('REQUIRED_PHP_VERSION', '7.3');
32
define('REQUIRED_MIN_MEMORY_LIMIT', '128');
33
define('REQUIRED_MIN_UPLOAD_MAX_FILESIZE', '10');
34
define('REQUIRED_MIN_POST_MAX_SIZE', '10');
35
36
// USER STATUS CONSTANTS
37
/** global status of a user: student */
38
define('STUDENT', 5);
39
/** global status of a user: course manager */
40
define('COURSEMANAGER', 1);
41
/** global status of a user: session admin */
42
define('SESSIONADMIN', 3);
43
/** global status of a user: human ressource manager */
44
define('DRH', 4);
45
/** global status of a user: human ressource manager */
46
define('ANONYMOUS', 6);
47
/** global status of a user: low security, necessary for inserting data from
48
 * the teacher through HTMLPurifier */
49
define('COURSEMANAGERLOWSECURITY', 10);
50
// Soft user status
51
define('PLATFORM_ADMIN', 11);
52
define('SESSION_COURSE_COACH', 12);
53
define('SESSION_GENERAL_COACH', 13);
54
define('COURSE_STUDENT', 14); //student subscribed in a course
55
define('SESSION_STUDENT', 15); //student subscribed in a session course
56
define('COURSE_TUTOR', 16); // student is tutor of a course (NOT in session)
57
define('STUDENT_BOSS', 17); // student is boss
58
define('INVITEE', 20);
59
define('HRM_REQUEST', 21); //HRM has request for vinculation with user
60
61
// COURSE VISIBILITY CONSTANTS
62
/** only visible for course admin */
63
define('COURSE_VISIBILITY_CLOSED', 0);
64
/** only visible for users registered in the course */
65
define('COURSE_VISIBILITY_REGISTERED', 1);
66
/** Open for all registered users on the platform */
67
define('COURSE_VISIBILITY_OPEN_PLATFORM', 2);
68
/** Open for the whole world */
69
define('COURSE_VISIBILITY_OPEN_WORLD', 3);
70
/** Invisible to all except admin */
71
define('COURSE_VISIBILITY_HIDDEN', 4);
72
73
define('COURSE_REQUEST_PENDING', 0);
74
define('COURSE_REQUEST_ACCEPTED', 1);
75
define('COURSE_REQUEST_REJECTED', 2);
76
define('DELETE_ACTION_ENABLED', false);
77
78
// EMAIL SENDING RECIPIENT CONSTANTS
79
define('SEND_EMAIL_EVERYONE', 1);
80
define('SEND_EMAIL_STUDENTS', 2);
81
define('SEND_EMAIL_TEACHERS', 3);
82
83
// SESSION VISIBILITY CONSTANTS
84
define('SESSION_VISIBLE_READ_ONLY', 1);
85
define('SESSION_VISIBLE', 2);
86
define('SESSION_INVISIBLE', 3); // not available
87
define('SESSION_AVAILABLE', 4);
88
89
define('SESSION_LINK_TARGET', '_self');
90
91
define('SUBSCRIBE_ALLOWED', 1);
92
define('SUBSCRIBE_NOT_ALLOWED', 0);
93
define('UNSUBSCRIBE_ALLOWED', 1);
94
define('UNSUBSCRIBE_NOT_ALLOWED', 0);
95
96
// SURVEY VISIBILITY CONSTANTS
97
define('SURVEY_VISIBLE_TUTOR', 0);
98
define('SURVEY_VISIBLE_TUTOR_STUDENT', 1);
99
define('SURVEY_VISIBLE_PUBLIC', 2);
100
101
// CONSTANTS defining all tools, using the english version
102
/* When you add a new tool you must add it into function api_get_tools_lists() too */
103
define('TOOL_DOCUMENT', 'document');
104
define('TOOL_LP_FINAL_ITEM', 'final_item');
105
define('TOOL_READOUT_TEXT', 'readout_text');
106
define('TOOL_THUMBNAIL', 'thumbnail');
107
define('TOOL_HOTPOTATOES', 'hotpotatoes');
108
define('TOOL_CALENDAR_EVENT', 'calendar_event');
109
define('TOOL_LINK', 'link');
110
define('TOOL_LINK_CATEGORY', 'link_category');
111
define('TOOL_COURSE_DESCRIPTION', 'course_description');
112
define('TOOL_SEARCH', 'search');
113
define('TOOL_LEARNPATH', 'learnpath');
114
define('TOOL_LEARNPATH_CATEGORY', 'learnpath_category');
115
define('TOOL_AGENDA', 'agenda');
116
define('TOOL_ANNOUNCEMENT', 'announcement');
117
define('TOOL_FORUM', 'forum');
118
define('TOOL_FORUM_CATEGORY', 'forum_category');
119
define('TOOL_FORUM_THREAD', 'forum_thread');
120
define('TOOL_FORUM_POST', 'forum_post');
121
define('TOOL_FORUM_ATTACH', 'forum_attachment');
122
define('TOOL_FORUM_THREAD_QUALIFY', 'forum_thread_qualify');
123
define('TOOL_THREAD', 'thread');
124
define('TOOL_POST', 'post');
125
define('TOOL_DROPBOX', 'dropbox');
126
define('TOOL_QUIZ', 'quiz');
127
define('TOOL_TEST_CATEGORY', 'test_category');
128
define('TOOL_USER', 'user');
129
define('TOOL_GROUP', 'group');
130
define('TOOL_BLOGS', 'blog_management');
131
define('TOOL_CHAT', 'chat');
132
define('TOOL_STUDENTPUBLICATION', 'student_publication');
133
define('TOOL_TRACKING', 'tracking');
134
define('TOOL_HOMEPAGE_LINK', 'homepage_link');
135
define('TOOL_COURSE_SETTING', 'course_setting');
136
define('TOOL_BACKUP', 'backup');
137
define('TOOL_COPY_COURSE_CONTENT', 'copy_course_content');
138
define('TOOL_RECYCLE_COURSE', 'recycle_course');
139
define('TOOL_COURSE_HOMEPAGE', 'course_homepage');
140
define('TOOL_COURSE_RIGHTS_OVERVIEW', 'course_rights');
141
define('TOOL_UPLOAD', 'file_upload');
142
define('TOOL_COURSE_MAINTENANCE', 'course_maintenance');
143
define('TOOL_SURVEY', 'survey');
144
define('TOOL_WIKI', 'wiki');
145
define('TOOL_GLOSSARY', 'glossary');
146
define('TOOL_GRADEBOOK', 'gradebook');
147
define('TOOL_NOTEBOOK', 'notebook');
148
define('TOOL_ATTENDANCE', 'attendance');
149
define('TOOL_COURSE_PROGRESS', 'course_progress');
150
define('TOOL_PORTFOLIO', 'portfolio');
151
define('TOOL_PLAGIARISM', 'compilatio');
152
153
// CONSTANTS defining Chamilo interface sections
154
define('SECTION_CAMPUS', 'mycampus');
155
define('SECTION_COURSES', 'mycourses');
156
define('SECTION_CATALOG', 'catalog');
157
define('SECTION_MYPROFILE', 'myprofile');
158
define('SECTION_MYAGENDA', 'myagenda');
159
define('SECTION_COURSE_ADMIN', 'course_admin');
160
define('SECTION_PLATFORM_ADMIN', 'platform_admin');
161
define('SECTION_MYGRADEBOOK', 'mygradebook');
162
define('SECTION_TRACKING', 'session_my_space');
163
define('SECTION_SOCIAL', 'social-network');
164
define('SECTION_DASHBOARD', 'dashboard');
165
define('SECTION_REPORTS', 'reports');
166
define('SECTION_GLOBAL', 'global');
167
define('SECTION_INCLUDE', 'include');
168
define('SECTION_CUSTOMPAGE', 'custompage');
169
170
// CONSTANT name for local authentication source
171
define('PLATFORM_AUTH_SOURCE', 'platform');
172
define('CAS_AUTH_SOURCE', 'cas');
173
define('LDAP_AUTH_SOURCE', 'extldap');
174
175
// CONSTANT defining the default HotPotatoes files directory
176
define('DIR_HOTPOTATOES', '/HotPotatoes_files');
177
178
// event logs types
179
define('LOG_COURSE_DELETE', 'course_deleted');
180
define('LOG_COURSE_CREATE', 'course_created');
181
define('LOG_COURSE_SETTINGS_CHANGED', 'course_settings_changed');
182
183
// @todo replace 'soc_gr' with social_group
184
define('LOG_GROUP_PORTAL_CREATED', 'soc_gr_created');
185
define('LOG_GROUP_PORTAL_UPDATED', 'soc_gr_updated');
186
define('LOG_GROUP_PORTAL_DELETED', 'soc_gr_deleted');
187
define('LOG_GROUP_PORTAL_USER_DELETE_ALL', 'soc_gr_delete_users');
188
189
define('LOG_GROUP_PORTAL_ID', 'soc_gr_portal_id');
190
define('LOG_GROUP_PORTAL_REL_USER_ARRAY', 'soc_gr_user_array');
191
192
define('LOG_GROUP_PORTAL_USER_SUBSCRIBED', 'soc_gr_u_subs');
193
define('LOG_GROUP_PORTAL_USER_UNSUBSCRIBED', 'soc_gr_u_unsubs');
194
define('LOG_GROUP_PORTAL_USER_UPDATE_ROLE', 'soc_gr_update_role');
195
196
define('LOG_USER_DELETE', 'user_deleted');
197
define('LOG_USER_CREATE', 'user_created');
198
define('LOG_USER_UPDATE', 'user_updated');
199
define('LOG_USER_PASSWORD_UPDATE', 'user_password_updated');
200
define('LOG_USER_ENABLE', 'user_enable');
201
define('LOG_USER_DISABLE', 'user_disable');
202
define('LOG_USER_ANONYMIZE', 'user_anonymized');
203
define('LOG_USER_FIELD_CREATE', 'user_field_created');
204
define('LOG_USER_FIELD_DELETE', 'user_field_deleted');
205
define('LOG_SESSION_CREATE', 'session_created');
206
define('LOG_SESSION_DELETE', 'session_deleted');
207
define('LOG_SESSION_ADD_USER_COURSE', 'session_add_user_course');
208
define('LOG_SESSION_DELETE_USER_COURSE', 'session_delete_user_course');
209
define('LOG_SESSION_ADD_USER', 'session_add_user');
210
define('LOG_SESSION_DELETE_USER', 'session_delete_user');
211
define('LOG_SESSION_ADD_COURSE', 'session_add_course');
212
define('LOG_SESSION_DELETE_COURSE', 'session_delete_course');
213
define('LOG_SESSION_CATEGORY_CREATE', 'session_cat_created'); //changed in 1.9.8
214
define('LOG_SESSION_CATEGORY_DELETE', 'session_cat_deleted'); //changed in 1.9.8
215
define('LOG_CONFIGURATION_SETTINGS_CHANGE', 'settings_changed');
216
define('LOG_PLATFORM_LANGUAGE_CHANGE', 'platform_lng_changed'); //changed in 1.9.8
217
define('LOG_SUBSCRIBE_USER_TO_COURSE', 'user_subscribed');
218
define('LOG_UNSUBSCRIBE_USER_FROM_COURSE', 'user_unsubscribed');
219
define('LOG_ATTEMPTED_FORCED_LOGIN', 'attempted_forced_login');
220
define('LOG_PLUGIN_CHANGE', 'plugin_changed');
221
define('LOG_HOMEPAGE_CHANGED', 'homepage_changed');
222
define('LOG_PROMOTION_CREATE', 'promotion_created');
223
define('LOG_PROMOTION_DELETE', 'promotion_deleted');
224
define('LOG_CAREER_CREATE', 'career_created');
225
define('LOG_CAREER_DELETE', 'career_deleted');
226
define('LOG_USER_PERSONAL_DOC_DELETED', 'user_doc_deleted');
227
define('LOG_WIKI_ACCESS', 'wiki_page_view');
228
// All results from an exercise
229
define('LOG_EXERCISE_RESULT_DELETE', 'exe_result_deleted');
230
// Logs only the one attempt
231
define('LOG_EXERCISE_ATTEMPT_DELETE', 'exe_attempt_deleted');
232
define('LOG_LP_ATTEMPT_DELETE', 'lp_attempt_deleted');
233
define('LOG_QUESTION_RESULT_DELETE', 'qst_attempt_deleted');
234
235
define('LOG_MY_FOLDER_CREATE', 'my_folder_created');
236
define('LOG_MY_FOLDER_CHANGE', 'my_folder_changed');
237
define('LOG_MY_FOLDER_DELETE', 'my_folder_deleted');
238
define('LOG_MY_FOLDER_COPY', 'my_folder_copied');
239
define('LOG_MY_FOLDER_CUT', 'my_folder_cut');
240
define('LOG_MY_FOLDER_PASTE', 'my_folder_pasted');
241
define('LOG_MY_FOLDER_UPLOAD', 'my_folder_uploaded');
242
243
// Event logs data types (max 20 chars)
244
define('LOG_COURSE_CODE', 'course_code');
245
define('LOG_COURSE_ID', 'course_id');
246
define('LOG_USER_ID', 'user_id');
247
define('LOG_USER_OBJECT', 'user_object');
248
define('LOG_USER_FIELD_VARIABLE', 'user_field_variable');
249
define('LOG_SESSION_ID', 'session_id');
250
251
define('LOG_QUESTION_ID', 'question_id');
252
define('LOG_SESSION_CATEGORY_ID', 'session_category_id');
253
define('LOG_CONFIGURATION_SETTINGS_CATEGORY', 'settings_category');
254
define('LOG_CONFIGURATION_SETTINGS_VARIABLE', 'settings_variable');
255
define('LOG_PLATFORM_LANGUAGE', 'default_platform_language');
256
define('LOG_PLUGIN_UPLOAD', 'plugin_upload');
257
define('LOG_PLUGIN_ENABLE', 'plugin_enable');
258
define('LOG_PLUGIN_SETTINGS_CHANGE', 'plugin_settings_change');
259
define('LOG_CAREER_ID', 'career_id');
260
define('LOG_PROMOTION_ID', 'promotion_id');
261
define('LOG_GRADEBOOK_LOCKED', 'gradebook_locked');
262
define('LOG_GRADEBOOK_UNLOCKED', 'gradebook_unlocked');
263
define('LOG_GRADEBOOK_ID', 'gradebook_id');
264
define('LOG_WIKI_PAGE_ID', 'wiki_page_id');
265
define('LOG_EXERCISE_ID', 'exercise_id');
266
define('LOG_EXERCISE_AND_USER_ID', 'exercise_and_user_id');
267
define('LOG_LP_ID', 'lp_id');
268
define('LOG_EXERCISE_ATTEMPT_QUESTION_ID', 'exercise_a_q_id');
269
define('LOG_EXERCISE_ATTEMPT', 'exe_id');
270
271
define('LOG_WORK_DIR_DELETE', 'work_dir_delete');
272
define('LOG_WORK_FILE_DELETE', 'work_file_delete');
273
define('LOG_WORK_DATA', 'work_data_array');
274
275
define('LOG_MY_FOLDER_PATH', 'path');
276
define('LOG_MY_FOLDER_NEW_PATH', 'new_path');
277
278
define('LOG_TERM_CONDITION_ACCEPTED', 'term_condition_accepted');
279
define('LOG_USER_CONFIRMED_EMAIL', 'user_confirmed_email');
280
define('LOG_USER_REMOVED_LEGAL_ACCEPT', 'user_removed_legal_accept');
281
282
define('LOG_USER_DELETE_ACCOUNT_REQUEST', 'user_delete_account_request');
283
284
define('LOG_QUESTION_CREATED', 'question_created');
285
define('LOG_QUESTION_UPDATED', 'question_updated');
286
define('LOG_QUESTION_DELETED', 'question_deleted');
287
define('LOG_QUESTION_REMOVED_FROM_QUIZ', 'question_removed_from_quiz');
288
289
define('LOG_SURVEY_ID', 'survey_id');
290
define('LOG_SURVEY_CREATED', 'survey_created');
291
define('LOG_SURVEY_DELETED', 'survey_deleted');
292
define('LOG_SURVEY_CLEAN_RESULTS', 'survey_clean_results');
293
define('USERNAME_PURIFIER', '/[^0-9A-Za-z_\.-]/');
294
295
//used when login_is_email setting is true
296
define('USERNAME_PURIFIER_MAIL', '/[^0-9A-Za-z_\.@]/');
297
define('USERNAME_PURIFIER_SHALLOW', '/\s/');
298
299
// This constant is a result of Windows OS detection, it has a boolean value:
300
// true whether the server runs on Windows OS, false otherwise.
301
define('IS_WINDOWS_OS', api_is_windows_os());
302
303
// iconv extension, for PHP5 on Windows it is installed by default.
304
define('ICONV_INSTALLED', function_exists('iconv'));
305
define('MBSTRING_INSTALLED', function_exists('mb_strlen')); // mbstring extension.
306
307
// Patterns for processing paths. Examples.
308
define('REPEATED_SLASHES_PURIFIER', '/\/{2,}/'); // $path = preg_replace(REPEATED_SLASHES_PURIFIER, '/', $path);
309
define('VALID_WEB_PATH', '/https?:\/\/[^\/]*(\/.*)?/i'); // $is_valid_path = preg_match(VALID_WEB_PATH, $path);
310
// $new_path = preg_replace(VALID_WEB_SERVER_BASE, $new_base, $path);
311
define('VALID_WEB_SERVER_BASE', '/https?:\/\/[^\/]*/i');
312
// Constants for api_get_path() and api_get_path_type(), etc. - registered path types.
313
// basic (leaf elements)
314
define('REL_CODE_PATH', 'REL_CODE_PATH');
315
define('REL_COURSE_PATH', 'REL_COURSE_PATH');
316
define('REL_HOME_PATH', 'REL_HOME_PATH');
317
318
// Constants for api_get_path() and api_get_path_type(), etc. - registered path types.
319
define('WEB_PATH', 'WEB_PATH');
320
define('SYS_PATH', 'SYS_PATH');
321
define('SYMFONY_SYS_PATH', 'SYMFONY_SYS_PATH');
322
//define('SYS_UPLOAD_PATH', 'SYS_UPLOAD_PATH');
323
//define('WEB_UPLOAD_PATH', 'WEB_UPLOAD_PATH');
324
325
define('REL_PATH', 'REL_PATH');
326
define('WEB_COURSE_PATH', 'WEB_COURSE_PATH');
327
define('WEB_CODE_PATH', 'WEB_CODE_PATH');
328
define('SYS_CODE_PATH', 'SYS_CODE_PATH');
329
define('SYS_LANG_PATH', 'SYS_LANG_PATH');
330
define('WEB_IMG_PATH', 'WEB_IMG_PATH');
331
define('WEB_CSS_PATH', 'WEB_CSS_PATH');
332
define('WEB_PUBLIC_PATH', 'WEB_PUBLIC_PATH');
333
define('SYS_CSS_PATH', 'SYS_CSS_PATH');
334
define('SYS_PLUGIN_PATH', 'SYS_PLUGIN_PATH');
335
define('WEB_PLUGIN_PATH', 'WEB_PLUGIN_PATH');
336
define('WEB_PLUGIN_ASSET_PATH', 'WEB_PLUGIN_ASSET_PATH');
337
define('SYS_ARCHIVE_PATH', 'SYS_ARCHIVE_PATH');
338
define('WEB_ARCHIVE_PATH', 'WEB_ARCHIVE_PATH');
339
define('LIBRARY_PATH', 'LIBRARY_PATH');
340
define('CONFIGURATION_PATH', 'CONFIGURATION_PATH');
341
define('WEB_LIBRARY_PATH', 'WEB_LIBRARY_PATH');
342
define('WEB_LIBRARY_JS_PATH', 'WEB_LIBRARY_JS_PATH');
343
define('WEB_AJAX_PATH', 'WEB_AJAX_PATH');
344
define('SYS_TEST_PATH', 'SYS_TEST_PATH');
345
define('SYS_TEMPLATE_PATH', 'SYS_TEMPLATE_PATH');
346
define('SYS_PUBLIC_PATH', 'SYS_PUBLIC_PATH');
347
define('SYS_FONTS_PATH', 'SYS_FONTS_PATH');
348
349
// Relations type with Course manager
350
define('COURSE_RELATION_TYPE_COURSE_MANAGER', 1);
351
define('SESSION_RELATION_TYPE_COURSE_MANAGER', 1);
352
353
// Relations type with Human resources manager
354
define('COURSE_RELATION_TYPE_RRHH', 1);
355
define('SESSION_RELATION_TYPE_RRHH', 1);
356
357
//User image sizes
358
define('USER_IMAGE_SIZE_ORIGINAL', 1);
359
define('USER_IMAGE_SIZE_BIG', 2);
360
define('USER_IMAGE_SIZE_MEDIUM', 3);
361
define('USER_IMAGE_SIZE_SMALL', 4);
362
363
// Relation type between users
364
define('USER_UNKNOWN', 0);
365
define('USER_RELATION_TYPE_UNKNOWN', 1);
366
define('USER_RELATION_TYPE_PARENT', 2); // should be deprecated is useless
367
define('USER_RELATION_TYPE_FRIEND', 3);
368
define('USER_RELATION_TYPE_GOODFRIEND', 4); // should be deprecated is useless
369
define('USER_RELATION_TYPE_ENEMY', 5); // should be deprecated is useless
370
define('USER_RELATION_TYPE_DELETED', 6);
371
define('USER_RELATION_TYPE_RRHH', 7);
372
define('USER_RELATION_TYPE_BOSS', 8);
373
define('USER_RELATION_TYPE_HRM_REQUEST', 9);
374
375
// Gradebook link constants
376
// Please do not change existing values, they are used in the database !
377
define('GRADEBOOK_ITEM_LIMIT', 1000);
378
379
define('LINK_EXERCISE', 1);
380
define('LINK_DROPBOX', 2);
381
define('LINK_STUDENTPUBLICATION', 3);
382
define('LINK_LEARNPATH', 4);
383
define('LINK_FORUM_THREAD', 5);
384
//define('LINK_WORK',6);
385
define('LINK_ATTENDANCE', 7);
386
define('LINK_SURVEY', 8);
387
define('LINK_HOTPOTATOES', 9);
388
389
// Score display types constants
390
define('SCORE_DIV', 1); // X / Y
391
define('SCORE_PERCENT', 2); // XX %
392
define('SCORE_DIV_PERCENT', 3); // X / Y (XX %)
393
define('SCORE_AVERAGE', 4); // XX %
394
define('SCORE_DECIMAL', 5); // 0.50  (X/Y)
395
define('SCORE_BAR', 6); // Uses the Display::bar_progress function
396
define('SCORE_SIMPLE', 7); // X
397
define('SCORE_IGNORE_SPLIT', 8); //  ??
398
define('SCORE_DIV_PERCENT_WITH_CUSTOM', 9); // X / Y (XX %) - Good!
399
define('SCORE_CUSTOM', 10); // Good!
400
define('SCORE_DIV_SIMPLE_WITH_CUSTOM', 11); // X - Good!
401
define('SCORE_DIV_SIMPLE_WITH_CUSTOM_LETTERS', 12); // X - Good!
402
define('SCORE_ONLY_SCORE', 13); // X - Good!
403
define('SCORE_NUMERIC', 14);
404
405
define('SCORE_BOTH', 1);
406
define('SCORE_ONLY_DEFAULT', 2);
407
define('SCORE_ONLY_CUSTOM', 3);
408
409
// From display.lib.php
410
411
define('MAX_LENGTH_BREADCRUMB', 100);
412
define('ICON_SIZE_ATOM', 8);
413
define('ICON_SIZE_TINY', 16);
414
define('ICON_SIZE_SMALL', 22);
415
define('ICON_SIZE_MEDIUM', 32);
416
define('ICON_SIZE_LARGE', 48);
417
define('ICON_SIZE_BIG', 64);
418
define('ICON_SIZE_HUGE', 128);
419
define('SHOW_TEXT_NEAR_ICONS', false);
420
421
// Session catalog
422
define('CATALOG_COURSES', 0);
423
define('CATALOG_SESSIONS', 1);
424
define('CATALOG_COURSES_SESSIONS', 2);
425
426
// Hook type events, pre-process and post-process.
427
// All means to be executed for both hook event types
428
define('HOOK_EVENT_TYPE_PRE', 0);
429
define('HOOK_EVENT_TYPE_POST', 1);
430
define('HOOK_EVENT_TYPE_ALL', 10);
431
432
define('CAREER_STATUS_ACTIVE', 1);
433
define('CAREER_STATUS_INACTIVE', 0);
434
435
define('PROMOTION_STATUS_ACTIVE', 1);
436
define('PROMOTION_STATUS_INACTIVE', 0);
437
438
// Group permissions
439
define('GROUP_PERMISSION_OPEN', '1');
440
define('GROUP_PERMISSION_CLOSED', '2');
441
442
// Group user permissions
443
define('GROUP_USER_PERMISSION_ADMIN', 1); // the admin of a group
444
define('GROUP_USER_PERMISSION_READER', 2); // a normal user
445
define('GROUP_USER_PERMISSION_PENDING_INVITATION', 3); // When an admin/moderator invites a user
446
define('GROUP_USER_PERMISSION_PENDING_INVITATION_SENT_BY_USER', 4); // an user joins a group
447
define('GROUP_USER_PERMISSION_MODERATOR', 5); // a moderator
448
define('GROUP_USER_PERMISSION_ANONYMOUS', 6); // an anonymous user
449
define('GROUP_USER_PERMISSION_HRM', 7); // a human resources manager
450
451
define('GROUP_IMAGE_SIZE_ORIGINAL', 1);
452
define('GROUP_IMAGE_SIZE_BIG', 2);
453
define('GROUP_IMAGE_SIZE_MEDIUM', 3);
454
define('GROUP_IMAGE_SIZE_SMALL', 4);
455
define('GROUP_TITLE_LENGTH', 50);
456
457
// Exercise
458
// @todo move into a class
459
define('ALL_ON_ONE_PAGE', 1);
460
define('ONE_PER_PAGE', 2);
461
462
define('EXERCISE_FEEDBACK_TYPE_END', 0); //Feedback 		 - show score and expected answers
463
define('EXERCISE_FEEDBACK_TYPE_DIRECT', 1); //DirectFeedback - Do not show score nor answers
464
define('EXERCISE_FEEDBACK_TYPE_EXAM', 2); // NoFeedback 	 - Show score only
465
define('EXERCISE_FEEDBACK_TYPE_POPUP', 3); // Popup BT#15827
466
467
define('RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS', 0); //show score and expected answers
468
define('RESULT_DISABLE_NO_SCORE_AND_EXPECTED_ANSWERS', 1); //Do not show score nor answers
469
define('RESULT_DISABLE_SHOW_SCORE_ONLY', 2); //Show score only
470
define('RESULT_DISABLE_SHOW_FINAL_SCORE_ONLY_WITH_CATEGORIES', 3); //Show final score only with categories
471
define('RESULT_DISABLE_SHOW_SCORE_ATTEMPT_SHOW_ANSWERS_LAST_ATTEMPT', 4);
472
define('RESULT_DISABLE_DONT_SHOW_SCORE_ONLY_IF_USER_FINISHES_ATTEMPTS_SHOW_ALWAYS_FEEDBACK', 5);
473
define('RESULT_DISABLE_RANKING', 6);
474
define('RESULT_DISABLE_SHOW_ONLY_IN_CORRECT_ANSWER', 7);
475
define('RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS_AND_RANKING', 8);
476
define('RESULT_DISABLE_RADAR', 9);
477
define('RESULT_DISABLE_SHOW_SCORE_ATTEMPT_SHOW_ANSWERS_LAST_ATTEMPT_NO_FEEDBACK', 10);
478
479
define('EXERCISE_MAX_NAME_SIZE', 80);
480
481
// Question types (edit next array as well when adding values)
482
// @todo move into a class
483
define('UNIQUE_ANSWER', 1);
484
define('MULTIPLE_ANSWER', 2);
485
define('FILL_IN_BLANKS', 3);
486
define('MATCHING', 4);
487
define('FREE_ANSWER', 5);
488
define('HOT_SPOT', 6);
489
define('HOT_SPOT_ORDER', 7);
490
define('HOT_SPOT_DELINEATION', 8);
491
define('MULTIPLE_ANSWER_COMBINATION', 9);
492
define('UNIQUE_ANSWER_NO_OPTION', 10);
493
define('MULTIPLE_ANSWER_TRUE_FALSE', 11);
494
define('MULTIPLE_ANSWER_COMBINATION_TRUE_FALSE', 12);
495
define('ORAL_EXPRESSION', 13);
496
define('GLOBAL_MULTIPLE_ANSWER', 14);
497
define('MEDIA_QUESTION', 15);
498
define('CALCULATED_ANSWER', 16);
499
define('UNIQUE_ANSWER_IMAGE', 17);
500
define('DRAGGABLE', 18);
501
define('MATCHING_DRAGGABLE', 19);
502
define('ANNOTATION', 20);
503
define('READING_COMPREHENSION', 21);
504
define('MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY', 22);
505
506
define('EXERCISE_CATEGORY_RANDOM_SHUFFLED', 1);
507
define('EXERCISE_CATEGORY_RANDOM_ORDERED', 2);
508
define('EXERCISE_CATEGORY_RANDOM_DISABLED', 0);
509
510
// Question selection type
511
define('EX_Q_SELECTION_ORDERED', 1);
512
define('EX_Q_SELECTION_RANDOM', 2);
513
define('EX_Q_SELECTION_CATEGORIES_ORDERED_QUESTIONS_ORDERED', 3);
514
define('EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_ORDERED', 4);
515
define('EX_Q_SELECTION_CATEGORIES_ORDERED_QUESTIONS_RANDOM', 5);
516
define('EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_RANDOM', 6);
517
define('EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_ORDERED_NO_GROUPED', 7);
518
define('EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_RANDOM_NO_GROUPED', 8);
519
define('EX_Q_SELECTION_CATEGORIES_ORDERED_BY_PARENT_QUESTIONS_ORDERED', 9);
520
define('EX_Q_SELECTION_CATEGORIES_ORDERED_BY_PARENT_QUESTIONS_RANDOM', 10);
521
522
// Used to save the skill_rel_item table
523
define('ITEM_TYPE_EXERCISE', 1);
524
define('ITEM_TYPE_HOTPOTATOES', 2);
525
define('ITEM_TYPE_LINK', 3);
526
define('ITEM_TYPE_LEARNPATH', 4);
527
define('ITEM_TYPE_GRADEBOOK', 5);
528
define('ITEM_TYPE_STUDENT_PUBLICATION', 6);
529
//define('ITEM_TYPE_FORUM', 7);
530
define('ITEM_TYPE_ATTENDANCE', 8);
531
define('ITEM_TYPE_SURVEY', 9);
532
define('ITEM_TYPE_FORUM_THREAD', 10);
533
534
// Course description blocks.
535
define('ADD_BLOCK', 8);
536
537
// one big string with all question types, for the validator in pear/HTML/QuickForm/Rule/QuestionType
538
define(
539
    'QUESTION_TYPES',
540
    UNIQUE_ANSWER.':'.
541
    MULTIPLE_ANSWER.':'.
542
    FILL_IN_BLANKS.':'.
543
    MATCHING.':'.
544
    FREE_ANSWER.':'.
545
    HOT_SPOT.':'.
546
    HOT_SPOT_ORDER.':'.
547
    HOT_SPOT_DELINEATION.':'.
548
    MULTIPLE_ANSWER_COMBINATION.':'.
549
    UNIQUE_ANSWER_NO_OPTION.':'.
550
    MULTIPLE_ANSWER_TRUE_FALSE.':'.
551
    MULTIPLE_ANSWER_COMBINATION_TRUE_FALSE.':'.
552
    ORAL_EXPRESSION.':'.
553
    GLOBAL_MULTIPLE_ANSWER.':'.
554
    MEDIA_QUESTION.':'.
555
    CALCULATED_ANSWER.':'.
556
    UNIQUE_ANSWER_IMAGE.':'.
557
    DRAGGABLE.':'.
558
    MATCHING_DRAGGABLE.':'.
559
    MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY.':'.
560
    ANNOTATION
561
);
562
563
//Some alias used in the QTI exports
564
define('MCUA', 1);
565
define('TF', 1);
566
define('MCMA', 2);
567
define('FIB', 3);
568
569
// Skills
570
define('SKILL_TYPE_REQUIREMENT', 'required');
571
define('SKILL_TYPE_ACQUIRED', 'acquired');
572
define('SKILL_TYPE_BOTH', 'both');
573
574
// Message
575
define('MESSAGE_STATUS_NEW', 0);
576
define('MESSAGE_STATUS_UNREAD', 1);
577
//2 ??
578
define('MESSAGE_STATUS_DELETED', 3);
579
define('MESSAGE_STATUS_OUTBOX', 4);
580
define('MESSAGE_STATUS_INVITATION_PENDING', 5);
581
define('MESSAGE_STATUS_INVITATION_ACCEPTED', 6);
582
define('MESSAGE_STATUS_INVITATION_DENIED', 7);
583
define('MESSAGE_STATUS_WALL', 8);
584
define('MESSAGE_STATUS_WALL_DELETE', 9);
585
define('MESSAGE_STATUS_WALL_POST', 10);
586
define('MESSAGE_STATUS_CONVERSATION', 11);
587
define('MESSAGE_STATUS_FORUM', 12);
588
define('MESSAGE_STATUS_PROMOTED', 13);
589
590
// Images
591
define('IMAGE_WALL_SMALL_SIZE', 200);
592
define('IMAGE_WALL_MEDIUM_SIZE', 500);
593
define('IMAGE_WALL_BIG_SIZE', 2000);
594
define('IMAGE_WALL_SMALL', 'small');
595
define('IMAGE_WALL_MEDIUM', 'medium');
596
define('IMAGE_WALL_BIG', 'big');
597
598
// Social PLUGIN PLACES
599
define('SOCIAL_LEFT_PLUGIN', 1);
600
define('SOCIAL_CENTER_PLUGIN', 2);
601
define('SOCIAL_RIGHT_PLUGIN', 3);
602
define('CUT_GROUP_NAME', 50);
603
604
/**
605
 * FormValidator Filter.
606
 */
607
define('NO_HTML', 1);
608
define('STUDENT_HTML', 2);
609
define('TEACHER_HTML', 3);
610
define('STUDENT_HTML_FULLPAGE', 4);
611
define('TEACHER_HTML_FULLPAGE', 5);
612
613
// Timeline
614
define('TIMELINE_STATUS_ACTIVE', '1');
615
define('TIMELINE_STATUS_INACTIVE', '2');
616
617
// Event email template class
618
define('EVENT_EMAIL_TEMPLATE_ACTIVE', 1);
619
define('EVENT_EMAIL_TEMPLATE_INACTIVE', 0);
620
621
// Course home
622
define('SHORTCUTS_HORIZONTAL', 0);
623
define('SHORTCUTS_VERTICAL', 1);
624
625
// Image class
626
define('IMAGE_PROCESSOR', 'gd'); // 'imagick' or 'gd' strings
627
628
// Course copy
629
define('FILE_SKIP', 1);
630
define('FILE_RENAME', 2);
631
define('FILE_OVERWRITE', 3);
632
define('UTF8_CONVERT', false); //false by default
633
634
define('DOCUMENT', 'file');
635
define('FOLDER', 'folder');
636
637
define('RESOURCE_ASSET', 'asset');
638
define('RESOURCE_DOCUMENT', 'document');
639
define('RESOURCE_GLOSSARY', 'glossary');
640
define('RESOURCE_EVENT', 'calendar_event');
641
define('RESOURCE_LINK', 'link');
642
define('RESOURCE_COURSEDESCRIPTION', 'course_description');
643
define('RESOURCE_LEARNPATH', 'learnpath');
644
define('RESOURCE_LEARNPATH_CATEGORY', 'learnpath_category');
645
define('RESOURCE_ANNOUNCEMENT', 'announcement');
646
define('RESOURCE_FORUM', 'forum');
647
define('RESOURCE_FORUMTOPIC', 'thread');
648
define('RESOURCE_FORUMPOST', 'post');
649
define('RESOURCE_QUIZ', 'quiz');
650
define('RESOURCE_TEST_CATEGORY', 'test_category');
651
define('RESOURCE_QUIZQUESTION', 'Exercise_Question');
652
define('RESOURCE_TOOL_INTRO', 'Tool introduction');
653
define('RESOURCE_LINKCATEGORY', 'Link_Category');
654
define('RESOURCE_FORUMCATEGORY', 'Forum_Category');
655
define('RESOURCE_SCORM', 'Scorm');
656
define('RESOURCE_SURVEY', 'survey');
657
define('RESOURCE_SURVEYQUESTION', 'survey_question');
658
define('RESOURCE_SURVEYINVITATION', 'survey_invitation');
659
define('RESOURCE_WIKI', 'wiki');
660
define('RESOURCE_THEMATIC', 'thematic');
661
define('RESOURCE_ATTENDANCE', 'attendance');
662
define('RESOURCE_WORK', 'work');
663
define('RESOURCE_SESSION_COURSE', 'session_course');
664
define('RESOURCE_GRADEBOOK', 'gradebook');
665
define('ADD_THEMATIC_PLAN', 6);
666
667
// Max online users to show per page (whoisonline)
668
define('MAX_ONLINE_USERS', 12);
669
670
// Number of characters maximum to show in preview of course blog posts
671
define('BLOG_MAX_PREVIEW_CHARS', 800);
672
// HTML string to replace with a 'Read more...' link
673
define('BLOG_PAGE_BREAK', '<div style="page-break-after: always"><span style="display: none;">&nbsp;</span></div>');
674
675
// Make sure the CHAMILO_LOAD_WYSIWYG constant is defined
676
// To remove CKeditor libs from HTML, set this constant to true before loading
677
if (!defined('CHAMILO_LOAD_WYSIWYG')) {
678
    define('CHAMILO_LOAD_WYSIWYG', true);
679
}
680
681
/* Constants for course home */
682
define('TOOL_PUBLIC', 'Public');
683
define('TOOL_PUBLIC_BUT_HIDDEN', 'PublicButHide');
684
define('TOOL_COURSE_ADMIN', 'courseAdmin');
685
define('TOOL_PLATFORM_ADMIN', 'platformAdmin');
686
define('TOOL_AUTHORING', 'toolauthoring');
687
define('TOOL_INTERACTION', 'toolinteraction');
688
define('TOOL_COURSE_PLUGIN', 'toolcourseplugin'); //all plugins that can be enabled in courses
689
define('TOOL_ADMIN', 'tooladmin');
690
define('TOOL_ADMIN_PLATFORM', 'tooladminplatform');
691
define('TOOL_DRH', 'tool_drh');
692
define('TOOL_STUDENT_VIEW', 'toolstudentview');
693
define('TOOL_ADMIN_VISIBLE', 'tooladminvisible');
694
695
// Search settings (from main/inc/lib/search/IndexableChunk.class.php )
696
// some constants to avoid serialize string keys on serialized data array
697
define('SE_COURSE_ID', 0);
698
define('SE_TOOL_ID', 1);
699
define('SE_DATA', 2);
700
define('SE_USER', 3);
701
702
// in some cases we need top differenciate xapian documents of the same tool
703
define('SE_DOCTYPE_EXERCISE_EXERCISE', 0);
704
define('SE_DOCTYPE_EXERCISE_QUESTION', 1);
705
706
// xapian prefixes
707
define('XAPIAN_PREFIX_COURSEID', 'C');
708
define('XAPIAN_PREFIX_TOOLID', 'O');
709
710
/**
711
 * Returns a path to a certain resource within the Chamilo area, specifyed through a parameter.
712
 * Also, this function provides conversion between path types, in this case the input path points inside the Chamilo area too.
713
 *
714
 * See $_configuration['course_folder'] in the configuration.php to alter the WEB_COURSE_PATH and SYS_COURSE_PATH parameters.
715
716
 *
717
 * @param string $path (optional)   A path which type is to be converted. Also, it may be a defined constant for a path.
718
 *                     This parameter has meaning when $type parameter has one of the following values: TO_WEB, TO_SYS, TO_REL. Otherwise it is ignored.
719
 *
720
 * @return string the requested path or the converted path
721
 *
722
 * Notes about the current behaviour model:
723
 * 1. Windows back-slashes are converted to slashes in the result.
724
 * 2. A semi-absolute web-path is detected by its leading slash. On Linux systems, absolute system paths start with
725
 * a slash too, so an additional check about presence of leading system server base is implemented. For example, the function is
726
 * able to distinguish type difference between /var/www/chamilo/courses/ (SYS) and /chamilo/courses/ (REL).
727
 * 3. The function api_get_path() returns only these three types of paths, which in some sense are absolute. The function has
728
 * no a mechanism for processing relative web/system paths, such as: lesson01.html, ./lesson01.html, ../css/my_styles.css.
729
 * It has not been identified as needed yet.
730
 * 4. Also, resolving the meta-symbols "." and ".." within paths has not been implemented, it is to be identified as needed.
731
 *
732
 * For examples go to: *
733
 * See main/admin/system_status.php?section=paths
734
 *
735
 * Vchamilo changes : allow using an alternate configuration
736
 * to get vchamilo  instance paths
737
 */
738
function api_get_path($path = '', $configuration = [])
739
{
740
    global $paths;
741
742
    // get proper configuration data if exists
743
    global $_configuration;
744
745
    $emptyConfigurationParam = false;
746
    if (empty($configuration)) {
747
        $configuration = (array) $_configuration;
748
        $emptyConfigurationParam = true;
749
    }
750
751
    $root_sys = Container::getProjectDir();
752
753
    $root_web = '';
754
    // If no $root_web has been set so far *and* no custom config has been passed to the function
755
    // then re-use the previously-calculated (run-specific) $root_web and skip this complex calculation
756
    /*
757
    if (empty($root_web) || $emptyConfigurationParam === false || empty($configuration)) {
758
        // Resolve master hostname.
759
        if (!empty($configuration) && array_key_exists('root_web', $configuration)) {
760
            $root_web = $configuration['root_web'];
761
        } else {
762
            $root_web = '';
763
            // Try guess it from server.
764
            if (defined('SYSTEM_INSTALLATION') && SYSTEM_INSTALLATION) {
765
                if (($pos = strpos(($requested_page_rel = api_get_self()), 'main/install')) !== false) {
766
                    $root_rel = substr($requested_page_rel, 0, $pos);
767
                    // See http://www.mediawiki.org/wiki/Manual:$wgServer
768
                    $server_protocol = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https' : 'http';
769
                    $server_name =
770
                        isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME']
771
                            : (isset($_SERVER['HOSTNAME']) ? $_SERVER['HOSTNAME']
772
                            : (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST']
773
                                : (isset($_SERVER['SERVER_ADDR']) ? $_SERVER['SERVER_ADDR']
774
                                    : 'localhost')));
775
                    if (isset($_SERVER['SERVER_PORT']) && !strpos($server_name, ':')
776
                        && (($server_protocol == 'http'
777
                                && $_SERVER['SERVER_PORT'] != 80) || ($server_protocol == 'https' && $_SERVER['SERVER_PORT'] != 443))
778
                    ) {
779
                        $server_name .= ":".$_SERVER['SERVER_PORT'];
780
                    }
781
                    $root_web = $server_protocol.'://'.$server_name.$root_rel;
782
                    $root_sys = str_replace('\\', '/', realpath(__DIR__.'/../../../')).'/';
783
                }
784
                // Here we give up, so we don't touch anything.
785
            }
786
        }
787
    }*/
788
    if (isset(Container::$container)) {
789
        $root_web = Container::$container->get('router')->generate(
790
            'home',
791
            [],
792
            UrlGeneratorInterface::ABSOLUTE_URL
793
        );
794
    }
795
796
    if (isset($configuration['multiple_access_urls']) &&
797
        $configuration['multiple_access_urls']
798
    ) {
799
        // To avoid that the api_get_access_url() function fails since global.inc.php also calls the main_api.lib.php
800
        if (isset($configuration['access_url']) && !empty($configuration['access_url'])) {
801
            // We look into the DB the function api_get_access_url
802
            $urlInfo = api_get_access_url($configuration['access_url']);
803
            // Avoid default value
804
            $defaultValues = ['http://localhost/', 'https://localhost/'];
805
            if (!empty($urlInfo['url']) && !in_array($urlInfo['url'], $defaultValues)) {
806
                $root_web = 1 == $urlInfo['active'] ? $urlInfo['url'] : $configuration['root_web'];
807
            }
808
        }
809
    }
810
811
    $paths = [
812
        WEB_PATH => $root_web,
813
        SYMFONY_SYS_PATH => $root_sys,
814
        SYS_PATH => $root_sys.'public/',
815
        REL_PATH => '',
816
        CONFIGURATION_PATH => 'app/config/',
817
        LIBRARY_PATH => $root_sys.'public/main/inc/lib/',
818
819
        REL_COURSE_PATH => '',
820
        REL_CODE_PATH => '/main/',
821
822
        SYS_CODE_PATH => $root_sys.'public/main/',
823
        SYS_CSS_PATH => $root_sys.'public/build/css/',
824
        SYS_PLUGIN_PATH => $root_sys.'public/plugin/',
825
        SYS_ARCHIVE_PATH => $root_sys.'var/cache/',
826
       // SYS_UPLOAD_PATH => 'var/upload/',
827
        SYS_TEST_PATH => $root_sys.'tests/',
828
        SYS_TEMPLATE_PATH => $root_sys.'public/main/template/',
829
        SYS_PUBLIC_PATH => $root_sys.'public/',
830
        SYS_FONTS_PATH => $root_sys.'public/fonts/',
831
832
        WEB_CODE_PATH => $root_web.'main/',
833
        WEB_PLUGIN_ASSET_PATH => $root_web.'plugins/',
834
        WEB_COURSE_PATH => $root_web.'course/',
835
        WEB_IMG_PATH => $root_web.'img/',
836
        WEB_CSS_PATH => $root_web.'build/css/',
837
        WEB_AJAX_PATH => $root_web.'main/inc/ajax/',
838
        WEB_LIBRARY_PATH => $root_web.'main/inc/lib/',
839
        WEB_LIBRARY_JS_PATH => $root_web.'main/inc/lib/javascript/',
840
        WEB_PLUGIN_PATH => $root_web.'plugin/',
841
       // WEB_ARCHIVE_PATH => 'var/cache/',
842
        //WEB_UPLOAD_PATH => 'var/upload/',
843
        WEB_PUBLIC_PATH => $root_web,
844
    ];
845
846
    $root_rel = '';
847
848
    // Dealing with trailing slashes.
849
    $rootWebWithSlash = api_add_trailing_slash($root_web);
850
    $root_sys = api_add_trailing_slash($root_sys);
851
    $root_rel = api_add_trailing_slash($root_rel);
852
853
    global $virtualChamilo;
854
    if (!empty($virtualChamilo)) {
855
        $paths[SYS_ARCHIVE_PATH] = api_add_trailing_slash($virtualChamilo[SYS_ARCHIVE_PATH]);
856
        $paths[SYS_UPLOAD_PATH] = api_add_trailing_slash($virtualChamilo[SYS_UPLOAD_PATH]);
0 ignored issues
show
Bug introduced by
The constant SYS_UPLOAD_PATH was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
857
        //$paths[$root_web][WEB_UPLOAD_PATH] = api_add_trailing_slash($virtualChamilo[WEB_UPLOAD_PATH]);
858
        $paths[WEB_ARCHIVE_PATH] = api_add_trailing_slash($virtualChamilo[WEB_ARCHIVE_PATH]);
859
        //$paths[$root_web][WEB_COURSE_PATH] = api_add_trailing_slash($virtualChamilo[WEB_COURSE_PATH]);
860
861
        // WEB_UPLOAD_PATH should be handle by apache htaccess in the vhost
862
863
        // RewriteEngine On
864
        // RewriteRule /app/upload/(.*)$ http://localhost/other/upload/my-chamilo111-net/$1 [QSA,L]
865
866
        //$paths[$root_web][WEB_UPLOAD_PATH] = api_add_trailing_slash($virtualChamilo[WEB_UPLOAD_PATH]);
867
        //$paths[$root_web][REL_PATH] = $virtualChamilo[REL_PATH];
868
        //$paths[$root_web][REL_COURSE_PATH] = $virtualChamilo[REL_COURSE_PATH];
869
    }
870
871
    $path = trim($path);
872
873
    // Retrieving a common-purpose path.
874
    if (isset($paths[$path])) {
875
        return $paths[$path];
876
    }
877
878
    return false;
879
}
880
881
/**
882
 * Adds to a given path a trailing slash if it is necessary (adds "/" character at the end of the string).
883
 *
884
 * @param string $path the input path
885
 *
886
 * @return string returns the modified path
887
 */
888
function api_add_trailing_slash($path)
889
{
890
    return '/' == substr($path, -1) ? $path : $path.'/';
891
}
892
893
/**
894
 * Removes from a given path the trailing slash if it is necessary (removes "/" character from the end of the string).
895
 *
896
 * @param string $path the input path
897
 *
898
 * @return string returns the modified path
899
 */
900
function api_remove_trailing_slash($path)
901
{
902
    return '/' == substr($path, -1) ? substr($path, 0, -1) : $path;
903
}
904
905
/**
906
 * Checks the RFC 3986 syntax of a given URL.
907
 *
908
 * @param string $url      the URL to be checked
909
 * @param bool   $absolute whether the URL is absolute (beginning with a scheme such as "http:")
910
 *
911
 * @return string|false Returns the URL if it is valid, FALSE otherwise.
912
 *                      This function is an adaptation from the function valid_url(), Drupal CMS.
913
 *
914
 * @see http://drupal.org
915
 * Note: The built-in function filter_var($urs, FILTER_VALIDATE_URL) has a bug for some versions of PHP.
916
 * @see http://bugs.php.net/51192
917
 */
918
function api_valid_url($url, $absolute = false)
919
{
920
    if ($absolute) {
921
        if (preg_match("
922
            /^                                                      # Start at the beginning of the text
923
            (?:ftp|https?|feed):\/\/                                # Look for ftp, http, https or feed schemes
924
            (?:                                                     # Userinfo (optional) which is typically
925
                (?:(?:[\w\.\-\+!$&'\(\)*\+,;=]|%[0-9a-f]{2})+:)*    # a username or a username and password
926
                (?:[\w\.\-\+%!$&'\(\)*\+,;=]|%[0-9a-f]{2})+@        # combination
927
            )?
928
            (?:
929
                (?:[a-z0-9\-\.]|%[0-9a-f]{2})+                      # A domain name or a IPv4 address
930
                |(?:\[(?:[0-9a-f]{0,4}:)*(?:[0-9a-f]{0,4})\])       # or a well formed IPv6 address
931
            )
932
            (?::[0-9]+)?                                            # Server port number (optional)
933
            (?:[\/|\?]
934
                (?:[\w#!:\.\?\+=&@$'~*,;\/\(\)\[\]\-]|%[0-9a-f]{2}) # The path and query (optional)
935
            *)?
936
            $/xi", $url)) {
937
            return $url;
938
        }
939
940
        return false;
941
    } else {
942
        return preg_match("/^(?:[\w#!:\.\?\+=&@$'~*,;\/\(\)\[\]\-]|%[0-9a-f]{2})+$/i", $url) ? $url : false;
943
    }
944
}
945
946
/**
947
 * Checks whether a given string looks roughly like an email address.
948
 *
949
 * @param string $address the e-mail address to be checked
950
 *
951
 * @return mixed returns the e-mail if it is valid, FALSE otherwise
952
 */
953
function api_valid_email($address)
954
{
955
    return filter_var($address, FILTER_VALIDATE_EMAIL);
956
}
957
958
/* PROTECTION FUNCTIONS
959
   Use these functions to protect your scripts. */
960
961
/**
962
 * Function used to protect a course script.
963
 * The function blocks access when
964
 * - there is no $_SESSION["_course"] defined; or
965
 * - $is_allowed_in_course is set to false (this depends on the course
966
 * visibility and user status).
967
 *
968
 * This is only the first proposal, test and improve!
969
 *
970
 * @param bool Option to print headers when displaying error message. Default: false
971
 * @param bool whether session admins should be allowed or not
972
 * @param string $checkTool check if tool is available for users (user, group)
973
 *
974
 * @return bool True if the user has access to the current course or is out of a course context, false otherwise
975
 *
976
 * @todo replace global variable
977
 *
978
 * @author Roan Embrechts
979
 */
980
function api_protect_course_script($print_headers = false, $allow_session_admins = false, $checkTool = '')
981
{
982
    $course_info = api_get_course_info();
983
    if (empty($course_info)) {
984
        api_not_allowed($print_headers);
985
986
        return false;
987
    }
988
989
    if (api_is_drh()) {
990
        return true;
991
    }
992
993
    // Session admin has access to course
994
    $sessionAccess = api_get_configuration_value('session_admins_access_all_content');
995
    if ($sessionAccess) {
996
        $allow_session_admins = true;
997
    }
998
999
    if (api_is_platform_admin($allow_session_admins)) {
1000
        return true;
1001
    }
1002
1003
    $isAllowedInCourse = api_is_allowed_in_course();
1004
    $is_visible = false;
1005
    if (isset($course_info) && isset($course_info['visibility'])) {
1006
        switch ($course_info['visibility']) {
1007
            default:
1008
            case COURSE_VISIBILITY_CLOSED:
1009
                // Completely closed: the course is only accessible to the teachers. - 0
1010
                if ($isAllowedInCourse && api_get_user_id() && !api_is_anonymous()) {
1011
                    $is_visible = true;
1012
                }
1013
                break;
1014
            case COURSE_VISIBILITY_REGISTERED:
1015
                // Private - access authorized to course members only - 1
1016
                if ($isAllowedInCourse && api_get_user_id() && !api_is_anonymous()) {
1017
                    $is_visible = true;
1018
                }
1019
                break;
1020
            case COURSE_VISIBILITY_OPEN_PLATFORM:
1021
                // Open - access allowed for users registered on the platform - 2
1022
                if ($isAllowedInCourse && api_get_user_id() && !api_is_anonymous()) {
1023
                    $is_visible = true;
1024
                }
1025
                break;
1026
            case COURSE_VISIBILITY_OPEN_WORLD:
1027
                //Open - access allowed for the whole world - 3
1028
                $is_visible = true;
1029
                break;
1030
            case COURSE_VISIBILITY_HIDDEN:
1031
                //Completely closed: the course is only accessible to the teachers. - 0
1032
                if (api_is_platform_admin()) {
1033
                    $is_visible = true;
1034
                }
1035
                break;
1036
        }
1037
1038
        //If password is set and user is not registered to the course then the course is not visible
1039
        if (false == $isAllowedInCourse &&
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...
1040
            isset($course_info['registration_code']) &&
1041
            !empty($course_info['registration_code'])
1042
        ) {
1043
            $is_visible = false;
1044
        }
1045
    }
1046
1047
    if (!empty($checkTool)) {
1048
        if (!api_is_allowed_to_edit(true, true, true)) {
1049
            $toolInfo = api_get_tool_information_by_name($checkTool);
1050
            if (!empty($toolInfo) && isset($toolInfo['visibility']) && 0 == $toolInfo['visibility']) {
1051
                api_not_allowed(true);
1052
1053
                return false;
1054
            }
1055
        }
1056
    }
1057
1058
    // Check session visibility
1059
    $session_id = api_get_session_id();
1060
1061
    if (!empty($session_id)) {
1062
        // $isAllowedInCourse was set in local.inc.php
1063
        if (!$isAllowedInCourse) {
1064
            $is_visible = false;
1065
        }
1066
    }
1067
1068
    if (!$is_visible) {
1069
        api_not_allowed($print_headers);
1070
1071
        return false;
1072
    }
1073
1074
    if ($is_visible && 'true' === api_get_plugin_setting('positioning', 'tool_enable')) {
1075
        $plugin = Positioning::create();
1076
        $block = $plugin->get('block_course_if_initial_exercise_not_attempted');
1077
        if ('true' === $block) {
1078
            $currentPath = $_SERVER['PHP_SELF'];
1079
            // Allowed only this course paths.
1080
            $paths = [
1081
                '/plugin/positioning/start.php',
1082
                '/plugin/positioning/start_student.php',
1083
                '/main/course_home/course_home.php',
1084
                '/main/exercise/overview.php',
1085
            ];
1086
1087
            if (!in_array($currentPath, $paths, true)) {
1088
                // Check if entering an exercise.
1089
                // @todo remove global $current_course_tool
1090
                /*global $current_course_tool;
1091
                if ('quiz' !== $current_course_tool) {
1092
                    $initialData = $plugin->getInitialExercise($course_info['real_id'], $session_id);
1093
                    if ($initialData && isset($initialData['exercise_id'])) {
1094
                        $results = Event::getExerciseResultsByUser(
1095
                            api_get_user_id(),
1096
                            $initialData['exercise_id'],
1097
                            $course_info['real_id'],
1098
                            $session_id
1099
                        );
1100
                        if (empty($results)) {
1101
                            api_not_allowed($print_headers);
1102
1103
                            return false;
1104
                        }
1105
                    }
1106
                }*/
1107
            }
1108
        }
1109
    }
1110
1111
    api_block_inactive_user();
1112
1113
    return true;
1114
}
1115
1116
/**
1117
 * Function used to protect an admin script.
1118
 *
1119
 * The function blocks access when the user has no platform admin rights
1120
 * with an error message printed on default output
1121
 *
1122
 * @param bool Whether to allow session admins as well
1123
 * @param bool Whether to allow HR directors as well
1124
 * @param string An optional message (already passed through get_lang)
1125
 *
1126
 * @return bool True if user is allowed, false otherwise.
1127
 *              The function also outputs an error message in case not allowed
1128
 *
1129
 * @author Roan Embrechts (original author)
1130
 */
1131
function api_protect_admin_script($allow_sessions_admins = false, $allow_drh = false, $message = null)
1132
{
1133
    if (!api_is_platform_admin($allow_sessions_admins, $allow_drh)) {
1134
        api_not_allowed(true, $message);
1135
1136
        return false;
1137
    }
1138
    api_block_inactive_user();
1139
1140
    return true;
1141
}
1142
1143
/**
1144
 * Blocks inactive users with a currently active session from accessing more pages "live".
1145
 *
1146
 * @return bool Returns true if the feature is disabled or the user account is still enabled.
1147
 *              Returns false (and shows a message) if the feature is enabled *and* the user is disabled.
1148
 */
1149
function api_block_inactive_user()
1150
{
1151
    $data = true;
1152
    if (1 != api_get_configuration_value('security_block_inactive_users_immediately')) {
1153
        return $data;
1154
    }
1155
1156
    $userId = api_get_user_id();
1157
    $homeUrl = api_get_path(WEB_PATH);
1158
    if (0 == $userId) {
1159
        return $data;
1160
    }
1161
1162
    $sql = "SELECT active FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1163
            WHERE id = $userId";
1164
1165
    $result = Database::query($sql);
1166
    if (Database::num_rows($result) > 0) {
1167
        $result_array = Database::fetch_array($result);
1168
        $data = (bool) $result_array['active'];
1169
    }
1170
    if (false == $data) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
1171
        $tpl = new Template(null, true, true, false, true, false, true, 0);
1172
        $tpl->assign('hide_login_link', 1);
1173
1174
        //api_not_allowed(true, get_lang('AccountInactive'));
1175
        // we were not in a course, return to home page
1176
        $msg = Display::return_message(
1177
            get_lang('AccountInactive'),
1178
            'error',
1179
            false
1180
        );
1181
1182
        $msg .= '<p class="text-center">
1183
                 <a class="btn btn-default" href="'.$homeUrl.'">'.get_lang('BackHome').'</a></p>';
1184
1185
        if (api_is_anonymous()) {
1186
            /*$form = api_get_not_allowed_login_form();
1187
            $msg .= '<div class="well">';
1188
            $msg .= $form->returnForm();
1189
            $msg .= '</div>';*/
1190
        }
1191
1192
        $tpl->assign('content', $msg);
1193
        $tpl->display_one_col_template();
1194
        exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
1195
    }
1196
1197
    return $data;
1198
}
1199
1200
/**
1201
 * Function used to protect a teacher script.
1202
 * The function blocks access when the user has no teacher rights.
1203
 *
1204
 * @return bool True if the current user can access the script, false otherwise
1205
 *
1206
 * @author Yoselyn Castillo
1207
 */
1208
function api_protect_teacher_script()
1209
{
1210
    if (!api_is_allowed_to_edit()) {
1211
        api_not_allowed(true);
1212
1213
        return false;
1214
    }
1215
1216
    return true;
1217
}
1218
1219
/**
1220
 * Function used to prevent anonymous users from accessing a script.
1221
 *
1222
 * @param bool $printHeaders
1223
 *
1224
 * @return bool
1225
 */
1226
function api_block_anonymous_users($printHeaders = true)
1227
{
1228
    $isAuth = Container::getAuthorizationChecker()->isGranted('IS_AUTHENTICATED_FULLY');
1229
1230
    if (false === $isAuth) {
1231
        api_not_allowed($printHeaders);
1232
1233
        return false;
1234
    }
1235
1236
    api_block_inactive_user();
1237
1238
    return true;
1239
1240
    /*$user = api_get_user_info();
1241
    if (!(isset($user['user_id']) && $user['user_id']) || api_is_anonymous($user['user_id'], true)) {
1242
        api_not_allowed($printHeaders);
1243
1244
        return false;
1245
    }
1246
    api_block_inactive_user();
1247
1248
    return true;*/
1249
}
1250
1251
/**
1252
 * Returns a rough evaluation of the browser's name and version based on very
1253
 * simple regexp.
1254
 *
1255
 * @return array with the navigator name and version ['name' => '...', 'version' => '...']
1256
 */
1257
function api_get_navigator()
1258
{
1259
    $navigator = 'Unknown';
1260
    $version = 0;
1261
1262
    if (!isset($_SERVER['HTTP_USER_AGENT'])) {
1263
        return ['name' => 'Unknown', 'version' => '0.0.0'];
1264
    }
1265
1266
    if (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Opera')) {
1267
        $navigator = 'Opera';
1268
        [, $version] = explode('Opera', $_SERVER['HTTP_USER_AGENT']);
1269
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Edge')) {
1270
        $navigator = 'Edge';
1271
        [, $version] = explode('Edge', $_SERVER['HTTP_USER_AGENT']);
1272
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE')) {
1273
        $navigator = 'Internet Explorer';
1274
        [, $version] = explode('MSIE ', $_SERVER['HTTP_USER_AGENT']);
1275
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Chrome')) {
1276
        $navigator = 'Chrome';
1277
        [, $version] = explode('Chrome', $_SERVER['HTTP_USER_AGENT']);
1278
    } elseif (false !== stripos($_SERVER['HTTP_USER_AGENT'], 'Safari')) {
1279
        $navigator = 'Safari';
1280
        if (false !== stripos($_SERVER['HTTP_USER_AGENT'], 'Version/')) {
1281
            // If this Safari does have the "Version/" string in its user agent
1282
            // then use that as a version indicator rather than what's after
1283
            // "Safari/" which is rather a "build number" or something
1284
            [, $version] = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1285
        } else {
1286
            [, $version] = explode('Safari/', $_SERVER['HTTP_USER_AGENT']);
1287
        }
1288
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Firefox')) {
1289
        $navigator = 'Firefox';
1290
        [, $version] = explode('Firefox', $_SERVER['HTTP_USER_AGENT']);
1291
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Netscape')) {
1292
        $navigator = 'Netscape';
1293
        if (false !== stripos($_SERVER['HTTP_USER_AGENT'], 'Netscape/')) {
1294
            [, $version] = explode('Netscape', $_SERVER['HTTP_USER_AGENT']);
1295
        } else {
1296
            [, $version] = explode('Navigator', $_SERVER['HTTP_USER_AGENT']);
1297
        }
1298
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Konqueror')) {
1299
        $navigator = 'Konqueror';
1300
        [, $version] = explode('Konqueror', $_SERVER['HTTP_USER_AGENT']);
1301
    } elseif (false !== stripos($_SERVER['HTTP_USER_AGENT'], 'applewebkit')) {
1302
        $navigator = 'AppleWebKit';
1303
        [, $version] = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1304
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Gecko')) {
1305
        $navigator = 'Mozilla';
1306
        [, $version] = explode('; rv:', $_SERVER['HTTP_USER_AGENT']);
1307
    }
1308
1309
    // Now cut extra stuff around (mostly *after*) the version number
1310
    $version = preg_replace('/^([\/\s])?([\d\.]+)?.*/', '\2', $version);
1311
1312
    if (false === strpos($version, '.')) {
1313
        $version = number_format(doubleval($version), 1);
1314
    }
1315
1316
    return ['name' => $navigator, 'version' => $version];
1317
}
1318
1319
/**
1320
 * @return true if user self registration is allowed, false otherwise
1321
 */
1322
function api_is_self_registration_allowed()
1323
{
1324
    return isset($GLOBALS['allowSelfReg']) ? $GLOBALS['allowSelfReg'] : false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return IssetNode ? $GLOB...'allowSelfReg'] : false could also return false which is incompatible with the documented return type true. Did you maybe forget to handle an error condition?

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

Loading history...
1325
}
1326
1327
/**
1328
 * This function returns the id of the user which is stored in the $_user array.
1329
 *
1330
 * example: The function can be used to check if a user is logged in
1331
 *          if (api_get_user_id())
1332
 *
1333
 * @return int the id of the current user, 0 if is empty
1334
 */
1335
function api_get_user_id()
1336
{
1337
    $userInfo = Session::read('_user');
1338
    if ($userInfo && isset($userInfo['user_id'])) {
1339
        return (int) $userInfo['user_id'];
1340
    }
1341
1342
    return 0;
1343
}
1344
1345
/**
1346
 * Gets the list of courses a specific user is subscribed to.
1347
 *
1348
 * @param int       User ID
1349
 * @param bool $fetch_session Whether to get session courses or not - NOT YET IMPLEMENTED
1350
 *
1351
 * @return array Array of courses in the form [0]=>('code'=>xxx,'db'=>xxx,'dir'=>xxx,'status'=>d)
1352
 *
1353
 * @deprecated use CourseManager::get_courses_list_by_user_id()
1354
 */
1355
function api_get_user_courses($userId, $fetch_session = true)
1356
{
1357
    // Get out if not integer
1358
    if ($userId != strval(intval($userId))) {
1359
        return [];
1360
    }
1361
1362
    $t_course = Database::get_main_table(TABLE_MAIN_COURSE);
1363
    $t_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
1364
1365
    $sql = "SELECT cc.id as real_id, cc.code code, cc.directory dir, cu.status status
1366
            FROM $t_course cc, $t_course_user cu
1367
            WHERE
1368
                cc.id = cu.c_id AND
1369
                cu.user_id = $userId AND
1370
                cu.relation_type <> ".COURSE_RELATION_TYPE_RRHH;
1371
    $result = Database::query($sql);
1372
    if (false === $result) {
1373
        return [];
1374
    }
1375
1376
    $courses = [];
1377
    while ($row = Database::fetch_array($result)) {
1378
        // we only need the database name of the course
1379
        $courses[] = $row;
1380
    }
1381
1382
    return $courses;
1383
}
1384
1385
/**
1386
 * Formats user information into a standard array
1387
 * This function should be only used inside api_get_user_info().
1388
 *
1389
 * @param array Non-standard user array
0 ignored issues
show
Documentation Bug introduced by
The doc comment Non-standard at position 0 could not be parsed: Unknown type name 'Non-standard' at position 0 in Non-standard.
Loading history...
1390
 * @param bool $add_password
1391
 * @param bool $loadAvatars  turn off to improve performance
1392
 *
1393
 * @return array Standard user array
1394
 */
1395
function _api_format_user($user, $add_password = false, $loadAvatars = true)
1396
{
1397
    $result = [];
1398
1399
    if (!isset($user['id'])) {
1400
        return [];
1401
    }
1402
1403
    $result['firstname'] = null;
1404
    $result['lastname'] = null;
1405
1406
    if (isset($user['firstname']) && isset($user['lastname'])) {
1407
        // with only lowercase
1408
        $result['firstname'] = $user['firstname'];
1409
        $result['lastname'] = $user['lastname'];
1410
    } elseif (isset($user['firstName']) && isset($user['lastName'])) {
1411
        // with uppercase letters
1412
        $result['firstname'] = isset($user['firstName']) ? $user['firstName'] : null;
1413
        $result['lastname'] = isset($user['lastName']) ? $user['lastName'] : null;
1414
    }
1415
1416
    if (isset($user['email'])) {
1417
        $result['mail'] = isset($user['email']) ? $user['email'] : null;
1418
        $result['email'] = isset($user['email']) ? $user['email'] : null;
1419
    } else {
1420
        $result['mail'] = isset($user['mail']) ? $user['mail'] : null;
1421
        $result['email'] = isset($user['mail']) ? $user['mail'] : null;
1422
    }
1423
1424
    $result['complete_name'] = api_get_person_name($result['firstname'], $result['lastname']);
1425
    $result['complete_name_with_username'] = $result['complete_name'];
1426
1427
    if (!empty($user['username']) && 'false' === api_get_setting('profile.hide_username_with_complete_name')) {
1428
        $result['complete_name_with_username'] = $result['complete_name'].' ('.$user['username'].')';
1429
    }
1430
1431
    $showEmail = 'true' === api_get_setting('show_email_addresses');
1432
    if (!empty($user['email'])) {
1433
        $result['complete_name_with_email_forced'] = $result['complete_name'].' ('.$user['email'].')';
1434
        if ($showEmail) {
1435
            $result['complete_name_with_email'] = $result['complete_name'].' ('.$user['email'].')';
1436
        }
1437
    } else {
1438
        $result['complete_name_with_email'] = $result['complete_name'];
1439
        $result['complete_name_with_email_forced'] = $result['complete_name'];
1440
    }
1441
1442
    // Kept for historical reasons
1443
    $result['firstName'] = $result['firstname'];
1444
    $result['lastName'] = $result['lastname'];
1445
1446
    $attributes = [
1447
        'phone',
1448
        'address',
1449
        'picture_uri',
1450
        'official_code',
1451
        'status',
1452
        'active',
1453
        'auth_source',
1454
        'username',
1455
        'theme',
1456
        'language',
1457
        'creator_id',
1458
        'registration_date',
1459
        'hr_dept_id',
1460
        'expiration_date',
1461
        'last_login',
1462
        'user_is_online',
1463
    ];
1464
1465
    if ('true' === api_get_setting('extended_profile')) {
1466
        $attributes[] = 'competences';
1467
        $attributes[] = 'diplomas';
1468
        $attributes[] = 'teach';
1469
        $attributes[] = 'openarea';
1470
    }
1471
1472
    foreach ($attributes as $attribute) {
1473
        $result[$attribute] = isset($user[$attribute]) ? $user[$attribute] : null;
1474
    }
1475
1476
    $user_id = (int) $user['id'];
1477
    // Maintain the user_id index for backwards compatibility
1478
    $result['user_id'] = $result['id'] = $user_id;
1479
1480
    $hasCertificates = Certificate::getCertificateByUser($user_id);
1481
    $result['has_certificates'] = 0;
1482
    if (!empty($hasCertificates)) {
1483
        $result['has_certificates'] = 1;
1484
    }
1485
1486
    $result['icon_status'] = '';
1487
    $result['icon_status_medium'] = '';
1488
    $result['is_admin'] = UserManager::is_admin($user_id);
1489
1490
    // Getting user avatar.
1491
    if ($loadAvatars) {
1492
        $result['avatar'] = '';
1493
        $result['avatar_no_query'] = '';
1494
        $result['avatar_small'] = '';
1495
        $result['avatar_medium'] = '';
1496
1497
        /*if (!isset($user['avatar'])) {
1498
            $originalFile = UserManager::getUserPicture(
1499
                $user_id,
1500
                USER_IMAGE_SIZE_ORIGINAL,
1501
                null,
1502
                $result
1503
            );
1504
            $result['avatar'] = $originalFile;
1505
            $avatarString = explode('?', $result['avatar']);
1506
            $result['avatar_no_query'] = reset($avatarString);
1507
        } else {
1508
            $result['avatar'] = $user['avatar'];
1509
            $avatarString = explode('?', $user['avatar']);
1510
            $result['avatar_no_query'] = reset($avatarString);
1511
        }
1512
1513
        if (!isset($user['avatar_small'])) {
1514
            $smallFile = UserManager::getUserPicture(
1515
                $user_id,
1516
                USER_IMAGE_SIZE_SMALL,
1517
                null,
1518
                $result
1519
            );
1520
            $result['avatar_small'] = $smallFile;
1521
        } else {
1522
            $result['avatar_small'] = $user['avatar_small'];
1523
        }
1524
1525
        if (!isset($user['avatar_medium'])) {
1526
            $mediumFile = UserManager::getUserPicture(
1527
                $user_id,
1528
                USER_IMAGE_SIZE_MEDIUM,
1529
                null,
1530
                $result
1531
            );
1532
            $result['avatar_medium'] = $mediumFile;
1533
        } else {
1534
            $result['avatar_medium'] = $user['avatar_medium'];
1535
        }*/
1536
1537
        $urlImg = api_get_path(WEB_IMG_PATH);
1538
        $iconStatus = '';
1539
        $iconStatusMedium = '';
1540
        $label = '';
1541
        switch ($result['status']) {
1542
            case STUDENT:
1543
                if ($result['has_certificates']) {
1544
                    $iconStatus = $urlImg.'icons/svg/identifier_graduated.svg';
1545
                    $label = get_lang('Graduated');
1546
                } else {
1547
                    $iconStatus = $urlImg.'icons/svg/identifier_student.svg';
1548
                    $label = get_lang('Student');
1549
                }
1550
                break;
1551
            case COURSEMANAGER:
1552
                if ($result['is_admin']) {
1553
                    $iconStatus = $urlImg.'icons/svg/identifier_admin.svg';
1554
                    $label = get_lang('Admin');
1555
                } else {
1556
                    $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1557
                    $label = get_lang('Teacher');
1558
                }
1559
                break;
1560
            case STUDENT_BOSS:
1561
                $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1562
                $label = get_lang('StudentBoss');
1563
                break;
1564
        }
1565
1566
        if (!empty($iconStatus)) {
1567
            $iconStatusMedium = '<img src="'.$iconStatus.'" width="32px" height="32px">';
1568
            $iconStatus = '<img src="'.$iconStatus.'" width="22px" height="22px">';
1569
        }
1570
1571
        $result['icon_status'] = $iconStatus;
1572
        $result['icon_status_label'] = $label;
1573
        $result['icon_status_medium'] = $iconStatusMedium;
1574
    }
1575
1576
    if (isset($user['user_is_online'])) {
1577
        $result['user_is_online'] = true == $user['user_is_online'] ? 1 : 0;
1578
    }
1579
    if (isset($user['user_is_online_in_chat'])) {
1580
        $result['user_is_online_in_chat'] = (int) $user['user_is_online_in_chat'];
1581
    }
1582
1583
    if ($add_password) {
1584
        $result['password'] = $user['password'];
1585
    }
1586
1587
    if (isset($result['profile_completed'])) {
1588
        $result['profile_completed'] = $user['profile_completed'];
1589
    }
1590
1591
    $result['profile_url'] = api_get_path(WEB_CODE_PATH).'social/profile.php?u='.$user_id;
1592
1593
    // Send message link
1594
    $sendMessage = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&user_id='.$user_id;
1595
    $result['complete_name_with_message_link'] = Display::url(
1596
        $result['complete_name_with_username'],
1597
        $sendMessage,
1598
        ['class' => 'ajax']
1599
    );
1600
1601
    if (isset($user['extra'])) {
1602
        $result['extra'] = $user['extra'];
1603
    }
1604
1605
    return $result;
1606
}
1607
1608
/**
1609
 * Finds all the information about a user.
1610
 * If no parameter is passed you find all the information about the current user.
1611
 *
1612
 * @param int  $user_id
1613
 * @param bool $checkIfUserOnline
1614
 * @param bool $showPassword
1615
 * @param bool $loadExtraData
1616
 * @param bool $loadOnlyVisibleExtraData Get the user extra fields that are visible
1617
 * @param bool $loadAvatars              turn off to improve performance and if avatars are not needed
1618
 * @param bool $updateCache              update apc cache if exists
1619
 *
1620
 * @return mixed $user_info user_id, lastname, firstname, username, email, etc or false on error
1621
 *
1622
 * @author Patrick Cool <[email protected]>
1623
 * @author Julio Montoya
1624
 *
1625
 * @version 21 September 2004
1626
 */
1627
function api_get_user_info(
1628
    $user_id = 0,
1629
    $checkIfUserOnline = false,
1630
    $showPassword = false,
1631
    $loadExtraData = false,
1632
    $loadOnlyVisibleExtraData = false,
1633
    $loadAvatars = true,
1634
    $updateCache = false
1635
) {
1636
    // Make sure user_id is safe
1637
    $user_id = (int) $user_id;
1638
    $user = false;
1639
    if (empty($user_id)) {
1640
        $userFromSession = Session::read('_user');
1641
        if (isset($userFromSession) && !empty($userFromSession)) {
1642
            return $userFromSession;
1643
            /*
1644
            return _api_format_user(
1645
                $userFromSession,
1646
                $showPassword,
1647
                $loadAvatars
1648
            );*/
1649
        }
1650
1651
        return false;
1652
    }
1653
1654
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1655
            WHERE id = $user_id";
1656
    $result = Database::query($sql);
1657
    if (Database::num_rows($result) > 0) {
1658
        $result_array = Database::fetch_array($result);
1659
        $result_array['user_is_online_in_chat'] = 0;
1660
        if ($checkIfUserOnline) {
1661
            $use_status_in_platform = user_is_online($user_id);
1662
            $result_array['user_is_online'] = $use_status_in_platform;
1663
            $user_online_in_chat = 0;
1664
            if ($use_status_in_platform) {
1665
                $user_status = UserManager::get_extra_user_data_by_field(
1666
                    $user_id,
1667
                    'user_chat_status',
1668
                    false,
1669
                    true
1670
                );
1671
                if (1 == (int) $user_status['user_chat_status']) {
1672
                    $user_online_in_chat = 1;
1673
                }
1674
            }
1675
            $result_array['user_is_online_in_chat'] = $user_online_in_chat;
1676
        }
1677
1678
        if ($loadExtraData) {
1679
            $fieldValue = new ExtraFieldValue('user');
1680
            $result_array['extra'] = $fieldValue->getAllValuesForAnItem(
1681
                $user_id,
1682
                $loadOnlyVisibleExtraData
1683
            );
1684
        }
1685
        $user = _api_format_user($result_array, $showPassword, $loadAvatars);
1686
    }
1687
1688
    return $user;
1689
}
1690
1691
function api_get_user_info_from_entity(
1692
    User $user,
1693
    $checkIfUserOnline = false,
1694
    $showPassword = false,
1695
    $loadExtraData = false,
1696
    $loadOnlyVisibleExtraData = false,
1697
    $loadAvatars = true,
1698
    $loadCertificate = false
1699
) {
1700
    if (!$user instanceof UserInterface) {
1701
        return false;
1702
    }
1703
1704
    // Make sure user_id is safe
1705
    $user_id = (int) $user->getId();
1706
1707
    if (empty($user_id)) {
1708
        $userFromSession = Session::read('_user');
1709
1710
        if (isset($userFromSession) && !empty($userFromSession)) {
1711
            return $userFromSession;
1712
        }
1713
1714
        return false;
1715
    }
1716
1717
    $result = [];
1718
    $result['user_is_online_in_chat'] = 0;
1719
    if ($checkIfUserOnline) {
1720
        $use_status_in_platform = user_is_online($user_id);
1721
        $result['user_is_online'] = $use_status_in_platform;
1722
        $user_online_in_chat = 0;
1723
        if ($use_status_in_platform) {
1724
            $user_status = UserManager::get_extra_user_data_by_field(
1725
                $user_id,
1726
                'user_chat_status',
1727
                false,
1728
                true
1729
            );
1730
            if (1 == (int) $user_status['user_chat_status']) {
1731
                $user_online_in_chat = 1;
1732
            }
1733
        }
1734
        $result['user_is_online_in_chat'] = $user_online_in_chat;
1735
    }
1736
1737
    if ($loadExtraData) {
1738
        $fieldValue = new ExtraFieldValue('user');
1739
        $result['extra'] = $fieldValue->getAllValuesForAnItem(
1740
            $user_id,
1741
            $loadOnlyVisibleExtraData
1742
        );
1743
    }
1744
1745
    $result['username'] = $user->getUsername();
1746
    $result['status'] = $user->getStatus();
1747
    $result['firstname'] = $user->getFirstname();
1748
    $result['lastname'] = $user->getLastname();
1749
    $result['email'] = $result['mail'] = $user->getEmail();
1750
    $result['complete_name'] = api_get_person_name($result['firstname'], $result['lastname']);
1751
    $result['complete_name_with_username'] = $result['complete_name'];
1752
1753
    if (!empty($result['username']) && 'false' === api_get_setting('profile.hide_username_with_complete_name')) {
1754
        $result['complete_name_with_username'] = $result['complete_name'].' ('.$result['username'].')';
1755
    }
1756
1757
    $showEmail = 'true' === api_get_setting('show_email_addresses');
1758
    if (!empty($result['email'])) {
1759
        $result['complete_name_with_email_forced'] = $result['complete_name'].' ('.$result['email'].')';
1760
        if ($showEmail) {
1761
            $result['complete_name_with_email'] = $result['complete_name'].' ('.$result['email'].')';
1762
        }
1763
    } else {
1764
        $result['complete_name_with_email'] = $result['complete_name'];
1765
        $result['complete_name_with_email_forced'] = $result['complete_name'];
1766
    }
1767
1768
    // Kept for historical reasons
1769
    $result['firstName'] = $result['firstname'];
1770
    $result['lastName'] = $result['lastname'];
1771
1772
    $attributes = [
1773
        'picture_uri',
1774
        'last_login',
1775
        'user_is_online',
1776
    ];
1777
1778
    $result['phone'] = $user->getPhone();
1779
    $result['address'] = $user->getAddress();
1780
    $result['official_code'] = $user->getOfficialCode();
1781
    $result['active'] = $user->getActive();
1782
    $result['auth_source'] = $user->getAuthSource();
1783
    $result['language'] = $user->getLanguage();
1784
    $result['creator_id'] = $user->getCreatorId();
1785
    $result['registration_date'] = $user->getRegistrationDate()->format('Y-m-d H:i:s');
1786
    $result['hr_dept_id'] = $user->getHrDeptId();
1787
    $result['expiration_date'] = '';
1788
    if ($user->getExpirationDate()) {
1789
        $result['expiration_date'] = $user->getExpirationDate()->format('Y-m-d H:i:s');
1790
    }
1791
1792
    $result['last_login'] = null;
1793
    if ($user->getLastLogin()) {
1794
        $result['last_login'] = $user->getLastLogin()->format('Y-m-d H:i:s');
1795
    }
1796
1797
    $result['competences'] = $user->getCompetences();
1798
    $result['diplomas'] = $user->getDiplomas();
1799
    $result['teach'] = $user->getTeach();
1800
    $result['openarea'] = $user->getOpenarea();
1801
    $user_id = (int) $user->getId();
1802
1803
    // Maintain the user_id index for backwards compatibility
1804
    $result['user_id'] = $result['id'] = $user_id;
1805
1806
    if ($loadCertificate) {
1807
        $hasCertificates = Certificate::getCertificateByUser($user_id);
1808
        $result['has_certificates'] = 0;
1809
        if (!empty($hasCertificates)) {
1810
            $result['has_certificates'] = 1;
1811
        }
1812
    }
1813
1814
    $result['icon_status'] = '';
1815
    $result['icon_status_medium'] = '';
1816
    $result['is_admin'] = UserManager::is_admin($user_id);
1817
1818
    // Getting user avatar.
1819
    if ($loadAvatars) {
1820
        $result['avatar'] = '';
1821
        $result['avatar_no_query'] = '';
1822
        $result['avatar_small'] = '';
1823
        $result['avatar_medium'] = '';
1824
1825
        /*if (!isset($user['avatar'])) {
1826
            $originalFile = UserManager::getUserPicture(
1827
                $user_id,
1828
                USER_IMAGE_SIZE_ORIGINAL,
1829
                null,
1830
                $result
1831
            );
1832
            $result['avatar'] = $originalFile;
1833
            $avatarString = explode('?', $result['avatar']);
1834
            $result['avatar_no_query'] = reset($avatarString);
1835
        } else {
1836
            $result['avatar'] = $user['avatar'];
1837
            $avatarString = explode('?', $user['avatar']);
1838
            $result['avatar_no_query'] = reset($avatarString);
1839
        }
1840
1841
        if (!isset($user['avatar_small'])) {
1842
            $smallFile = UserManager::getUserPicture(
1843
                $user_id,
1844
                USER_IMAGE_SIZE_SMALL,
1845
                null,
1846
                $result
1847
            );
1848
            $result['avatar_small'] = $smallFile;
1849
        } else {
1850
            $result['avatar_small'] = $user['avatar_small'];
1851
        }
1852
1853
        if (!isset($user['avatar_medium'])) {
1854
            $mediumFile = UserManager::getUserPicture(
1855
                $user_id,
1856
                USER_IMAGE_SIZE_MEDIUM,
1857
                null,
1858
                $result
1859
            );
1860
            $result['avatar_medium'] = $mediumFile;
1861
        } else {
1862
            $result['avatar_medium'] = $user['avatar_medium'];
1863
        }*/
1864
1865
        //$urlImg = api_get_path(WEB_IMG_PATH);
1866
        $urlImg = '/';
1867
        $iconStatus = '';
1868
        $iconStatusMedium = '';
1869
1870
        switch ($user->getStatus()) {
1871
            case STUDENT:
1872
                if (isset($result['has_certificates']) && $result['has_certificates']) {
1873
                    $iconStatus = $urlImg.'icons/svg/identifier_graduated.svg';
1874
                } else {
1875
                    $iconStatus = $urlImg.'icons/svg/identifier_student.svg';
1876
                }
1877
                break;
1878
            case COURSEMANAGER:
1879
                if ($result['is_admin']) {
1880
                    $iconStatus = $urlImg.'icons/svg/identifier_admin.svg';
1881
                } else {
1882
                    $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1883
                }
1884
                break;
1885
            case STUDENT_BOSS:
1886
                $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1887
                break;
1888
        }
1889
1890
        if (!empty($iconStatus)) {
1891
            $iconStatusMedium = '<img src="'.$iconStatus.'" width="32px" height="32px">';
1892
            $iconStatus = '<img src="'.$iconStatus.'" width="22px" height="22px">';
1893
        }
1894
1895
        $result['icon_status'] = $iconStatus;
1896
        $result['icon_status_medium'] = $iconStatusMedium;
1897
    }
1898
1899
    if (isset($result['user_is_online'])) {
1900
        $result['user_is_online'] = true == $result['user_is_online'] ? 1 : 0;
1901
    }
1902
    if (isset($result['user_is_online_in_chat'])) {
1903
        $result['user_is_online_in_chat'] = $result['user_is_online_in_chat'];
1904
    }
1905
1906
    $result['password'] = '';
1907
    if ($showPassword) {
1908
        $result['password'] = $user->getPassword();
1909
    }
1910
1911
    if (isset($result['profile_completed'])) {
1912
        $result['profile_completed'] = $result['profile_completed'];
1913
    }
1914
1915
    $result['profile_url'] = api_get_path(WEB_CODE_PATH).'social/profile.php?u='.$user_id;
1916
1917
    // Send message link
1918
    $sendMessage = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&user_id='.$user_id;
1919
    $result['complete_name_with_message_link'] = Display::url(
1920
        $result['complete_name_with_username'],
1921
        $sendMessage,
1922
        ['class' => 'ajax']
1923
    );
1924
1925
    if (isset($result['extra'])) {
1926
        $result['extra'] = $result['extra'];
1927
    }
1928
1929
    return $result;
1930
}
1931
1932
function api_get_lp_entity(int $id): ?CLp
1933
{
1934
    return Database::getManager()->getRepository(CLp::class)->find($id);
1935
}
1936
1937
function api_get_user_entity(int $userId = 0): ?User
1938
{
1939
    $userId = $userId ?: api_get_user_id();
1940
    $repo = UserManager::getRepository();
1941
1942
    /** @var User $user */
1943
    $user = $repo->find($userId);
1944
1945
    return $user;
1946
}
1947
1948
function api_get_current_user(): ?User
1949
{
1950
    $isLoggedIn = Container::$container->get('security.authorization_checker')->isGranted('IS_AUTHENTICATED_REMEMBERED');
1951
    if (false === $isLoggedIn) {
1952
        return null;
1953
    }
1954
1955
    $token = Container::$container->get('security.token_storage')->getToken();
1956
1957
    if (null !== $token) {
1958
        return $token->getUser();
1959
    }
1960
1961
    return null;
1962
}
1963
1964
/**
1965
 * Finds all the information about a user from username instead of user id.
1966
 *
1967
 * @param string $username
1968
 *
1969
 * @return mixed $user_info array user_id, lastname, firstname, username, email or false on error
1970
 *
1971
 * @author Yannick Warnier <[email protected]>
1972
 */
1973
function api_get_user_info_from_username($username)
1974
{
1975
    if (empty($username)) {
1976
        return false;
1977
    }
1978
    $username = trim($username);
1979
1980
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1981
            WHERE username='".Database::escape_string($username)."'";
1982
    $result = Database::query($sql);
1983
    if (Database::num_rows($result) > 0) {
1984
        $resultArray = Database::fetch_array($result);
1985
1986
        return _api_format_user($resultArray);
1987
    }
1988
1989
    return false;
1990
}
1991
1992
/**
1993
 * Get first user with an email.
1994
 *
1995
 * @param string $email
1996
 *
1997
 * @return array|bool
1998
 */
1999
function api_get_user_info_from_email($email = '')
2000
{
2001
    if (empty($email)) {
2002
        return false;
2003
    }
2004
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
2005
            WHERE email ='".Database::escape_string($email)."' LIMIT 1";
2006
    $result = Database::query($sql);
2007
    if (Database::num_rows($result) > 0) {
2008
        $resultArray = Database::fetch_array($result);
2009
2010
        return _api_format_user($resultArray);
2011
    }
2012
2013
    return false;
2014
}
2015
2016
/**
2017
 * @return string
2018
 */
2019
function api_get_course_id()
2020
{
2021
    return Session::read('_cid', null);
2022
}
2023
2024
/**
2025
 * Returns the current course id (integer).
2026
 *
2027
 * @param string $code Optional course code
2028
 *
2029
 * @return int
2030
 */
2031
function api_get_course_int_id($code = null)
2032
{
2033
    if (!empty($code)) {
2034
        $code = Database::escape_string($code);
2035
        $row = Database::select(
2036
            'id',
2037
            Database::get_main_table(TABLE_MAIN_COURSE),
2038
            ['where' => ['code = ?' => [$code]]],
2039
            'first'
2040
        );
2041
2042
        if (is_array($row) && isset($row['id'])) {
2043
            return $row['id'];
2044
        } else {
2045
            return false;
2046
        }
2047
    }
2048
2049
    return Session::read('_real_cid', 0);
2050
}
2051
2052
/**
2053
 * Returns the current course directory.
2054
 *
2055
 * This function relies on api_get_course_info()
2056
 *
2057
 * @param string    The course code - optional (takes it from session if not given)
2058
 *
2059
 * @return string The directory where the course is located inside the Chamilo "courses" directory
2060
 *
2061
 * @author Yannick Warnier <[email protected]>
2062
 */
2063
function api_get_course_path($course_code = null)
2064
{
2065
    $info = !empty($course_code) ? api_get_course_info($course_code) : api_get_course_info();
2066
2067
    return $info['path'];
2068
}
2069
2070
/**
2071
 * Gets a course setting from the current course_setting table. Try always using integer values.
2072
 *
2073
 * @param string $settingName The name of the setting we want from the table
2074
 * @param array  $courseInfo
2075
 * @param bool   $force       force checking the value in the database
2076
 *
2077
 * @return mixed The value of that setting in that table. Return -1 if not found.
2078
 */
2079
function api_get_course_setting($settingName, $courseInfo = [], $force = false)
2080
{
2081
    if (empty($courseInfo)) {
2082
        $courseInfo = api_get_course_info();
2083
    }
2084
2085
    if (empty($courseInfo) || empty($settingName)) {
2086
        return -1;
2087
    }
2088
2089
    $courseId = isset($courseInfo['real_id']) && !empty($courseInfo['real_id']) ? $courseInfo['real_id'] : 0;
2090
2091
    if (empty($courseId)) {
2092
        return -1;
2093
    }
2094
2095
    static $courseSettingInfo = [];
2096
2097
    if ($force) {
2098
        $courseSettingInfo = [];
2099
    }
2100
2101
    if (!isset($courseSettingInfo[$courseId])) {
2102
        $table = Database::get_course_table(TABLE_COURSE_SETTING);
2103
        $settingName = Database::escape_string($settingName);
2104
2105
        $sql = "SELECT variable, value FROM $table
2106
                WHERE c_id = $courseId ";
2107
        $res = Database::query($sql);
2108
        if (Database::num_rows($res) > 0) {
2109
            $result = Database::store_result($res, 'ASSOC');
2110
            $courseSettingInfo[$courseId] = array_column($result, 'value', 'variable');
2111
2112
            if (isset($courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'])) {
2113
                $value = $courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'];
2114
                if (!is_null($value)) {
2115
                    $result = explode(',', $value);
2116
                    $courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'] = $result;
2117
                }
2118
            }
2119
        }
2120
    }
2121
2122
    if (isset($courseSettingInfo[$courseId]) && isset($courseSettingInfo[$courseId][$settingName])) {
2123
        return $courseSettingInfo[$courseId][$settingName];
2124
    }
2125
2126
    return -1;
2127
}
2128
2129
function api_get_course_plugin_setting($plugin, $settingName, $courseInfo = [])
2130
{
2131
    $value = api_get_course_setting($settingName, $courseInfo, true);
2132
2133
    if (-1 === $value) {
2134
        // Check global settings
2135
        $value = api_get_plugin_setting($plugin, $settingName);
2136
        if ('true' === $value) {
2137
            return 1;
2138
        }
2139
        if ('false' === $value) {
2140
            return 0;
2141
        }
2142
        if (null === $value) {
2143
            return -1;
2144
        }
2145
    }
2146
2147
    return $value;
2148
}
2149
2150
/**
2151
 * Gets an anonymous user ID.
2152
 *
2153
 * For some tools that need tracking, like the learnpath tool, it is necessary
2154
 * to have a usable user-id to enable some kind of tracking, even if not
2155
 * perfect. An anonymous ID is taken from the users table by looking for a
2156
 * status of "6" (anonymous).
2157
 *
2158
 * @return int User ID of the anonymous user, or O if no anonymous user found
2159
 */
2160
function api_get_anonymous_id()
2161
{
2162
    // Find if another anon is connected now
2163
    $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
2164
    $tableU = Database::get_main_table(TABLE_MAIN_USER);
2165
    $ip = Database::escape_string(api_get_real_ip());
2166
    $max = (int) api_get_configuration_value('max_anonymous_users');
2167
    if ($max >= 2) {
2168
        $sql = "SELECT * FROM $table as TEL
2169
                JOIN $tableU as U
2170
                ON U.id = TEL.login_user_id
2171
                WHERE TEL.user_ip = '$ip'
2172
                    AND U.status = ".ANONYMOUS."
2173
                    AND U.id != 2 ";
2174
2175
        $result = Database::query($sql);
2176
        if (empty(Database::num_rows($result))) {
2177
            $login = uniqid('anon_');
2178
            $anonList = UserManager::get_user_list(['status' => ANONYMOUS], ['registration_date ASC']);
2179
            if (count($anonList) >= $max) {
2180
                foreach ($anonList as $userToDelete) {
2181
                    UserManager::delete_user($userToDelete['user_id']);
2182
                    break;
2183
                }
2184
            }
2185
2186
            return UserManager::create_user(
0 ignored issues
show
Bug Best Practice introduced by
The expression return UserManager::crea...lhost', $login, $login) could also return false which is incompatible with the documented return type integer. Did you maybe forget to handle an error condition?

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

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

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

8109
                $image = /** @scrutinizer ignore-deprecated */ new Image($pathToSave);
Loading history...
8110
                $image->crop($cropParameters);
8111
            }
8112
8113
            return ['path_to_save' => $pathId.$name];
8114
        }
8115
    }
8116
8117
    return false;
8118
}
8119
8120
/**
8121
 * @param string $type
8122
 * @param int    $itemId
8123
 * @param string $file
8124
 *
8125
 * @return bool
8126
 */
8127
function api_get_uploaded_web_url($type, $itemId, $file)
8128
{
8129
    return api_get_uploaded_file($type, $itemId, $file, true);
8130
}
8131
8132
/**
8133
 * @param string $type
8134
 * @param int    $itemId
8135
 * @param string $file
8136
 * @param bool   $getUrl
8137
 *
8138
 * @return bool
8139
 */
8140
function api_get_uploaded_file($type, $itemId, $file, $getUrl = false)
8141
{
8142
    $itemId = (int) $itemId;
8143
    $pathId = '/'.substr((string) $itemId, 0, 1).'/'.$itemId.'/';
8144
    $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...
8145
    $file = basename($file);
8146
    $file = $path.'/'.$file;
8147
    if (Security::check_abs_path($file, $path) && is_file($file) && file_exists($file)) {
8148
        if ($getUrl) {
8149
            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...
8150
        }
8151
8152
        return $file;
8153
    }
8154
8155
    return false;
8156
}
8157
8158
/**
8159
 * @param string $type
8160
 * @param int    $itemId
8161
 * @param string $file
8162
 * @param string $title
8163
 */
8164
function api_download_uploaded_file($type, $itemId, $file, $title = '')
8165
{
8166
    $file = api_get_uploaded_file($type, $itemId, $file);
8167
    if ($file) {
8168
        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...
8169
            DocumentManager::file_send_for_download($file, true, $title);
8170
            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...
8171
        }
8172
    }
8173
    api_not_allowed(true);
8174
}
8175
8176
/**
8177
 * @param string $type
8178
 * @param string $file
8179
 */
8180
function api_remove_uploaded_file($type, $file)
8181
{
8182
    $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...
8183
    $path = $typePath.'/'.$file;
8184
    if (Security::check_abs_path($path, $typePath) && file_exists($path) && is_file($path)) {
8185
        unlink($path);
8186
    }
8187
}
8188
8189
/**
8190
 * @param string $type
8191
 * @param int    $itemId
8192
 * @param string $file
8193
 *
8194
 * @return bool
8195
 */
8196
function api_remove_uploaded_file_by_id($type, $itemId, $file)
8197
{
8198
    $file = api_get_uploaded_file($type, $itemId, $file, false);
8199
    $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...
8200
    if (Security::check_abs_path($file, $typePath) && file_exists($file) && is_file($file)) {
8201
        unlink($file);
8202
8203
        return true;
8204
    }
8205
8206
    return false;
8207
}
8208
8209
/**
8210
 * Converts string value to float value.
8211
 *
8212
 * 3.141516 => 3.141516
8213
 * 3,141516 => 3.141516
8214
 *
8215
 * @todo WIP
8216
 *
8217
 * @param string $number
8218
 *
8219
 * @return float
8220
 */
8221
function api_float_val($number)
8222
{
8223
    $number = (float) str_replace(',', '.', trim($number));
8224
8225
    return $number;
8226
}
8227
8228
/**
8229
 * Converts float values
8230
 * Example if $decimals = 2.
8231
 *
8232
 * 3.141516 => 3.14
8233
 * 3,141516 => 3,14
8234
 *
8235
 * @param string $number            number in iso code
8236
 * @param int    $decimals
8237
 * @param string $decimalSeparator
8238
 * @param string $thousandSeparator
8239
 *
8240
 * @return bool|string
8241
 */
8242
function api_number_format($number, $decimals = 0, $decimalSeparator = '.', $thousandSeparator = ',')
8243
{
8244
    $number = api_float_val($number);
8245
8246
    return number_format($number, $decimals, $decimalSeparator, $thousandSeparator);
8247
}
8248
8249
/**
8250
 * Set location url with a exit break by default.
8251
 *
8252
 * @param string $url
8253
 * @param bool   $exit
8254
 */
8255
function api_location($url, $exit = true)
8256
{
8257
    header('Location: '.$url);
8258
8259
    if ($exit) {
8260
        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...
8261
    }
8262
}
8263
8264
/**
8265
 * @return string
8266
 */
8267
function api_get_web_url()
8268
{
8269
    if ('test' === api_get_setting('server_type')) {
8270
        return api_get_path(WEB_PATH).'web/app_dev.php/';
8271
    } else {
8272
        return api_get_path(WEB_PATH).'web/';
8273
    }
8274
}
8275
8276
/**
8277
 * @param string $from
8278
 * @param string $to
8279
 *
8280
 * @return string
8281
 */
8282
function api_get_relative_path($from, $to)
8283
{
8284
    // some compatibility fixes for Windows paths
8285
    $from = is_dir($from) ? rtrim($from, '\/').'/' : $from;
8286
    $to = is_dir($to) ? rtrim($to, '\/').'/' : $to;
8287
    $from = str_replace('\\', '/', $from);
8288
    $to = str_replace('\\', '/', $to);
8289
8290
    $from = explode('/', $from);
8291
    $to = explode('/', $to);
8292
    $relPath = $to;
8293
8294
    foreach ($from as $depth => $dir) {
8295
        // find first non-matching dir
8296
        if ($dir === $to[$depth]) {
8297
            // ignore this directory
8298
            array_shift($relPath);
8299
        } else {
8300
            // get number of remaining dirs to $from
8301
            $remaining = count($from) - $depth;
8302
            if ($remaining > 1) {
8303
                // add traversals up to first matching dir
8304
                $padLength = (count($relPath) + $remaining - 1) * -1;
8305
                $relPath = array_pad($relPath, $padLength, '..');
8306
                break;
8307
            } else {
8308
                $relPath[0] = './'.$relPath[0];
8309
            }
8310
        }
8311
    }
8312
8313
    return implode('/', $relPath);
8314
}
8315
8316
/**
8317
 * Unserialize content using Brummann\Polyfill\Unserialize.
8318
 *
8319
 * @param string $type
8320
 * @param string $serialized
8321
 *
8322
 * @return mixed
8323
 */
8324
function api_unserialize_content($type, $serialized, $ignoreErrors = false)
8325
{
8326
    switch ($type) {
8327
        case 'career':
8328
        case 'sequence_graph':
8329
            $allowedClasses = [
8330
                \Fhaculty\Graph\Graph::class,
8331
                \Fhaculty\Graph\Set\VerticesMap::class,
8332
                \Fhaculty\Graph\Set\Vertices::class,
8333
                \Fhaculty\Graph\Set\Edges::class,
8334
            ];
8335
            break;
8336
        case 'lp':
8337
            $allowedClasses = [
8338
                learnpath::class,
8339
                learnpathItem::class,
8340
                aicc::class,
8341
                aiccBlock::class,
8342
                aiccItem::class,
8343
                aiccObjective::class,
8344
                aiccResource::class,
8345
                scorm::class,
8346
                scormItem::class,
8347
                scormMetadata::class,
8348
                scormOrganization::class,
8349
                scormResource::class,
8350
                Link::class,
8351
                LpItem::class,
8352
            ];
8353
            break;
8354
        case 'course':
8355
            $allowedClasses = [
8356
                \Chamilo\CourseBundle\Component\CourseCopy\Course::class,
8357
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Announcement::class,
8358
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Attendance::class,
8359
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\CalendarEvent::class,
8360
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\CourseCopyLearnpath::class,
8361
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\CourseCopyTestCategory::class,
8362
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\CourseDescription::class,
8363
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\CourseSession::class,
8364
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Document::class,
8365
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Forum::class,
8366
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\ForumCategory::class,
8367
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\ForumPost::class,
8368
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\ForumTopic::class,
8369
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Glossary::class,
8370
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\GradeBookBackup::class,
8371
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Link::class,
8372
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\LinkCategory::class,
8373
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Quiz::class,
8374
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\QuizQuestion::class,
8375
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\QuizQuestionOption::class,
8376
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\ScormDocument::class,
8377
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Survey::class,
8378
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\SurveyInvitation::class,
8379
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\SurveyQuestion::class,
8380
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Thematic::class,
8381
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\ToolIntro::class,
8382
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Wiki::class,
8383
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Work::class,
8384
                stdClass::class,
8385
            ];
8386
            break;
8387
        case 'not_allowed_classes':
8388
        default:
8389
            $allowedClasses = false;
8390
    }
8391
8392
    if ($ignoreErrors) {
8393
        return @UnserializeApi::unserialize(
8394
            $serialized,
8395
            ['allowed_classes' => $allowedClasses]
8396
        );
8397
    }
8398
8399
    return UnserializeApi::unserialize(
8400
        $serialized,
8401
        ['allowed_classes' => $allowedClasses]
8402
    );
8403
}
8404
8405
/**
8406
 * @param string $template
8407
 *
8408
 * @return string
8409
 */
8410
function api_find_template($template)
8411
{
8412
    return Template::findTemplateFilePath($template);
8413
}
8414
8415
/**
8416
 * @return array
8417
 */
8418
function api_get_language_list_for_flag()
8419
{
8420
    $table = Database::get_main_table(TABLE_MAIN_LANGUAGE);
8421
    $sql = "SELECT english_name, isocode FROM $table
8422
            ORDER BY original_name ASC";
8423
    static $languages = [];
8424
    if (empty($languages)) {
8425
        $result = Database::query($sql);
8426
        while ($row = Database::fetch_array($result)) {
8427
            $languages[$row['english_name']] = $row['isocode'];
8428
        }
8429
        $languages['english'] = 'gb';
8430
    }
8431
8432
    return $languages;
8433
}
8434
8435
/**
8436
 * @param string $name
8437
 *
8438
 * @return \ZipStream\ZipStream
8439
 */
8440
function api_create_zip($name)
8441
{
8442
    $zipStreamOptions = new \ZipStream\Option\Archive();
8443
    $zipStreamOptions->setSendHttpHeaders(true);
8444
    $zipStreamOptions->setContentDisposition('attachment');
8445
    $zipStreamOptions->setContentType('application/x-zip');
8446
8447
    $zip = new \ZipStream\ZipStream($name, $zipStreamOptions);
8448
8449
    return $zip;
8450
}
8451
8452
/**
8453
 * @return string
8454
 */
8455
function api_get_language_translate_html()
8456
{
8457
    $translate = api_get_configuration_value('translate_html');
8458
8459
    if (!$translate) {
8460
        return '';
8461
    }
8462
8463
    $languageList = api_get_languages();
8464
    $hideAll = '';
8465
    foreach ($languageList['all'] as $language) {
8466
        $hideAll .= '
8467
        $("span:lang('.$language['isocode'].')").filter(
8468
            function(e, val) {
8469
                // Only find the spans if they have set the lang
8470
                if ($(this).attr("lang") == null) {
8471
                    return false;
8472
                }
8473
8474
                // Ignore ckeditor classes
8475
                return !this.className.match(/cke(.*)/);
8476
        }).hide();'."\n";
8477
    }
8478
8479
    $userInfo = api_get_user_info();
8480
    $languageId = api_get_language_id($userInfo['language']);
8481
    $languageInfo = api_get_language_info($languageId);
8482
    $isoCode = 'en';
8483
8484
    if (!empty($languageInfo)) {
8485
        $isoCode = $languageInfo['isocode'];
8486
    }
8487
8488
    return '
8489
            $(function() {
8490
                '.$hideAll.'
8491
                var defaultLanguageFromUser = "'.$isoCode.'";
8492
8493
                $("span:lang('.$isoCode.')").filter(
8494
                    function() {
8495
                        // Ignore ckeditor classes
8496
                        return !this.className.match(/cke(.*)/);
8497
                }).show();
8498
8499
                var defaultLanguage = "";
8500
                var langFromUserFound = false;
8501
8502
                $(this).find("span").filter(
8503
                    function() {
8504
                        // Ignore ckeditor classes
8505
                        return !this.className.match(/cke(.*)/);
8506
                }).each(function() {
8507
                    defaultLanguage = $(this).attr("lang");
8508
                    if (defaultLanguage) {
8509
                        $(this).before().next("br").remove();
8510
                        if (defaultLanguageFromUser == defaultLanguage) {
8511
                            langFromUserFound = true;
8512
                        }
8513
                    }
8514
                });
8515
8516
                // Show default language
8517
                if (langFromUserFound == false && defaultLanguage) {
8518
                    $("span:lang("+defaultLanguage+")").filter(
8519
                    function() {
8520
                            // Ignore ckeditor classes
8521
                            return !this.className.match(/cke(.*)/);
8522
                    }).show();
8523
                }
8524
            });
8525
    ';
8526
}
8527
8528
/**
8529
 * Filter a multi-language HTML string (for the multi-language HTML
8530
 * feature) into the given language (strip the rest).
8531
 *
8532
 * @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>
8533
 * @param string $language   The language in which we want to get the
8534
 *
8535
 * @throws Exception
8536
 *
8537
 * @return string The filtered string in the given language, or the full string if no translated string was identified
8538
 */
8539
function api_get_filtered_multilingual_HTML_string($htmlString, $language = null)
8540
{
8541
    if (true != api_get_configuration_value('translate_html')) {
8542
        return $htmlString;
8543
    }
8544
    $userInfo = api_get_user_info();
8545
    $languageId = 0;
8546
    if (!empty($language)) {
8547
        $languageId = api_get_language_id($language);
8548
    } elseif (!empty($userInfo['language'])) {
8549
        $languageId = api_get_language_id($userInfo['language']);
8550
    }
8551
    $languageInfo = api_get_language_info($languageId);
8552
    $isoCode = 'en';
8553
8554
    if (!empty($languageInfo)) {
8555
        $isoCode = $languageInfo['isocode'];
8556
    }
8557
8558
    // Split HTML in the separate language strings
8559
    // Note: some strings might look like <p><span ..>...</span></p> but others might be like combine 2 <span> in 1 <p>
8560
    if (!preg_match('/<span.*?lang="(\w\w)">/is', $htmlString)) {
8561
        return $htmlString;
8562
    }
8563
    $matches = [];
8564
    preg_match_all('/<span.*?lang="(\w\w)">(.*?)<\/span>/is', $htmlString, $matches);
8565
    if (!empty($matches)) {
8566
        // matches[0] are the full string
8567
        // matches[1] are the languages
8568
        // matches[2] are the strings
8569
        foreach ($matches[1] as $id => $match) {
8570
            if ($match == $isoCode) {
8571
                return $matches[2][$id];
8572
            }
8573
        }
8574
        // Could find the pattern but could not find our language. Return the first language found.
8575
        return $matches[2][0];
8576
    }
8577
    // Could not find pattern. Just return the whole string. We shouldn't get here.
8578
    return $htmlString;
8579
}
8580