Passed
Push — master ( 49d6fc...f737dc )
by Julito
08:44
created

api_get_course_path()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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

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

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

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

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

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

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

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

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

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

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