Passed
Push — master ( a02707...7dc539 )
by Julito
12:00
created

get_status_from_code()   C

Complexity

Conditions 12
Paths 12

Size

Total Lines 25
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 12
eloc 23
nc 12
nop 1
dl 0
loc 25
rs 6.9666
c 0
b 0
f 0

How to fix   Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
use Chamilo\CoreBundle\Entity\AccessUrl;
6
use Chamilo\CoreBundle\Entity\Course;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Course. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

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

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

Loading history...
1036
            isset($course_info['registration_code']) &&
1037
            !empty($course_info['registration_code'])
1038
        ) {
1039
            $is_visible = false;
1040
        }
1041
    }
1042
1043
    if (!empty($checkTool)) {
1044
        if (!api_is_allowed_to_edit(true, true, true)) {
1045
            $toolInfo = api_get_tool_information_by_name($checkTool);
1046
            if (!empty($toolInfo) && isset($toolInfo['visibility']) && 0 == $toolInfo['visibility']) {
1047
                api_not_allowed(true);
1048
1049
                return false;
1050
            }
1051
        }
1052
    }
1053
1054
    // Check session visibility
1055
    $session_id = api_get_session_id();
1056
1057
    if (!empty($session_id)) {
1058
        // $isAllowedInCourse was set in local.inc.php
1059
        if (!$isAllowedInCourse) {
1060
            $is_visible = false;
1061
        }
1062
    }
1063
1064
    if (!$is_visible) {
1065
        api_not_allowed($print_headers);
1066
1067
        return false;
1068
    }
1069
1070
    if ($is_visible && 'true' === api_get_plugin_setting('positioning', 'tool_enable')) {
1071
        $plugin = Positioning::create();
1072
        $block = $plugin->get('block_course_if_initial_exercise_not_attempted');
1073
        if ('true' === $block) {
1074
            $currentPath = $_SERVER['PHP_SELF'];
1075
            // Allowed only this course paths.
1076
            $paths = [
1077
                '/plugin/positioning/start.php',
1078
                '/plugin/positioning/start_student.php',
1079
                '/main/course_home/course_home.php',
1080
                '/main/exercise/overview.php',
1081
            ];
1082
1083
            if (!in_array($currentPath, $paths, true)) {
1084
                // Check if entering an exercise.
1085
                global $current_course_tool;
1086
                if ('quiz' !== $current_course_tool) {
1087
                    $initialData = $plugin->getInitialExercise($course_info['real_id'], $session_id);
1088
                    if ($initialData && isset($initialData['exercise_id'])) {
1089
                        $results = Event::getExerciseResultsByUser(
0 ignored issues
show
Bug introduced by
The method getExerciseResultsByUser() does not exist on Event. ( Ignorable by Annotation )

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

1089
                        /** @scrutinizer ignore-call */ 
1090
                        $results = Event::getExerciseResultsByUser(

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...
1090
                            api_get_user_id(),
1091
                            $initialData['exercise_id'],
1092
                            $course_info['real_id'],
1093
                            $session_id
1094
                        );
1095
                        if (empty($results)) {
1096
                            api_not_allowed($print_headers);
1097
1098
                            return false;
1099
                        }
1100
                    }
1101
                }
1102
            }
1103
        }
1104
    }
1105
1106
    api_block_inactive_user();
1107
    return true;
1108
}
1109
1110
/**
1111
 * Function used to protect an admin script.
1112
 *
1113
 * The function blocks access when the user has no platform admin rights
1114
 * with an error message printed on default output
1115
 *
1116
 * @param bool Whether to allow session admins as well
1117
 * @param bool Whether to allow HR directors as well
1118
 * @param string An optional message (already passed through get_lang)
1119
 *
1120
 * @return bool True if user is allowed, false otherwise.
1121
 *              The function also outputs an error message in case not allowed
1122
 *
1123
 * @author Roan Embrechts (original author)
1124
 */
1125
function api_protect_admin_script($allow_sessions_admins = false, $allow_drh = false, $message = null)
1126
{
1127
    if (!api_is_platform_admin($allow_sessions_admins, $allow_drh)) {
1128
        api_not_allowed(true, $message);
1129
1130
        return false;
1131
    }
1132
    api_block_inactive_user();
1133
1134
    return true;
1135
}
1136
1137
/**
1138
 * Blocks inactive users with a currently active session from accessing more pages "live".
1139
 *
1140
 * @return bool Returns true if the feature is disabled or the user account is still enabled.
1141
 *              Returns false (and shows a message) if the feature is enabled *and* the user is disabled.
1142
 */
1143
function api_block_inactive_user()
1144
{
1145
    $data = true;
1146
    if (api_get_configuration_value('security_block_inactive_users_immediately') != 1) {
1147
        return $data;
1148
    }
1149
1150
    $userId = api_get_user_id();
1151
    $homeUrl = api_get_path(WEB_PATH);
1152
    if ($userId == 0) {
1153
        return $data;
1154
    }
1155
1156
    $sql = "SELECT active FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1157
            WHERE id = $userId";
1158
1159
    $result = Database::query($sql);
1160
    if (Database::num_rows($result) > 0) {
1161
        $result_array = Database::fetch_array($result);
1162
        $data = (bool) $result_array['active'];
1163
    }
1164
    if ($data == false) {
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...
1165
        $tpl = new Template(null, true, true, false, true, false, true, 0);
1166
        $tpl->assign('hide_login_link', 1);
1167
1168
        //api_not_allowed(true, get_lang('AccountInactive'));
1169
        // we were not in a course, return to home page
1170
        $msg = Display::return_message(
1171
            get_lang('AccountInactive'),
1172
            'error',
1173
            false
1174
        );
1175
1176
        $msg .= '<p class="text-center">
1177
                 <a class="btn btn-default" href="'.$homeUrl.'">'.get_lang('BackHome').'</a></p>';
1178
1179
        if (api_is_anonymous()) {
1180
            $form = api_get_not_allowed_login_form();
0 ignored issues
show
Bug introduced by
The function api_get_not_allowed_login_form was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

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

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

Loading history...
2171
                $login,
2172
                'anon',
2173
                ANONYMOUS,
2174
                ' anonymous@localhost',
2175
                $login,
2176
                $login
2177
            );
2178
        } else {
2179
            $row = Database::fetch_array($result, 'ASSOC');
2180
2181
            return $row['id'];
2182
        }
2183
    }
2184
2185
    $table = Database::get_main_table(TABLE_MAIN_USER);
2186
    $sql = "SELECT id
2187
            FROM $table
2188
            WHERE status = ".ANONYMOUS." ";
2189
    $res = Database::query($sql);
2190
    if (Database::num_rows($res) > 0) {
2191
        $row = Database::fetch_array($res, 'ASSOC');
2192
2193
        return $row['id'];
2194
    }
2195
2196
    // No anonymous user was found.
2197
    return 0;
2198
}
2199
2200
/**
2201
 * @param int $courseId
2202
 * @param int $sessionId
2203
 * @param int $groupId
2204
 *
2205
 * @return string
2206
 */
2207
function api_get_cidreq_params($courseId, $sessionId = 0, $groupId = 0)
2208
{
2209
    $courseId = !empty($courseId) ? (int) $courseId : 0;
2210
    $sessionId = !empty($sessionId) ? (int) $sessionId : 0;
2211
    $groupId = !empty($groupId) ? (int) $groupId : 0;
2212
2213
    $url = 'cid='.$courseId;
2214
    $url .= '&sid='.$sessionId;
2215
    $url .= '&gid='.$groupId;
2216
2217
    return $url;
2218
}
2219
2220
/**
2221
 * Returns the current course url part including session, group, and gradebook params.
2222
 *
2223
 * @param bool   $addSessionId
2224
 * @param bool   $addGroupId
2225
 * @param string $origin
2226
 *
2227
 * @return string Course & session references to add to a URL
2228
 */
2229
function api_get_cidreq($addSessionId = true, $addGroupId = true, $origin = '')
2230
{
2231
    $courseId = api_get_course_int_id();
2232
    $url = empty($courseId) ? '' : 'cid='.$courseId;
2233
    $origin = empty($origin) ? api_get_origin() : Security::remove_XSS($origin);
2234
2235
    if ($addSessionId) {
2236
        if (!empty($url)) {
2237
            $url .= 0 == api_get_session_id() ? '&sid=0' : '&sid='.api_get_session_id();
2238
        }
2239
    }
2240
2241
    if ($addGroupId) {
2242
        if (!empty($url)) {
2243
            $url .= 0 == api_get_group_id() ? '&gid=0' : '&gid='.api_get_group_id();
2244
        }
2245
    }
2246
2247
    if (!empty($url)) {
2248
        $url .= '&gradebook='.(int) api_is_in_gradebook();
2249
        $url .= '&origin='.$origin;
2250
    }
2251
2252
    return $url;
2253
}
2254
2255
/**
2256
 * Get if we visited a gradebook page.
2257
 *
2258
 * @return bool
2259
 */
2260
function api_is_in_gradebook()
2261
{
2262
    return Session::read('in_gradebook', false);
2263
}
2264
2265
/**
2266
 * Set that we are in a page inside a gradebook.
2267
 */
2268
function api_set_in_gradebook()
2269
{
2270
    Session::write('in_gradebook', true);
2271
}
2272
2273
/**
2274
 * Remove gradebook session.
2275
 */
2276
function api_remove_in_gradebook()
2277
{
2278
    Session::erase('in_gradebook');
2279
}
2280
2281
/**
2282
 * Returns the current course info array see api_format_course_array()
2283
 * If the course_code is given, the returned array gives info about that
2284
 * particular course, if none given it gets the course info from the session.
2285
 *
2286
 * @param string $courseCode
2287
 *
2288
 * @return array
2289
 */
2290
function api_get_course_info($courseCode = null)
2291
{
2292
    if (!empty($courseCode)) {
2293
        $course = Container::getCourseRepository()->findOneByCode($courseCode);
2294
2295
        return api_format_course_array($course);
2296
    }
2297
2298
    /*$course_code = Database::escape_string($course_code);
2299
    $courseId = api_get_course_int_id($course_code);
2300
    if (empty($courseId)) {
2301
        return [];
2302
    }
2303
2304
    $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
2305
    $course_cat_table = Database::get_main_table(TABLE_MAIN_CATEGORY);
2306
    $sql = "SELECT
2307
                course.*,
2308
                course_category.code faCode,
2309
                course_category.name faName
2310
            FROM $course_table
2311
            LEFT JOIN $course_cat_table
2312
            ON course.category_code = course_category.code
2313
            WHERE course.id = $courseId";
2314
    $result = Database::query($sql);
2315
    $courseInfo = [];
2316
    if (Database::num_rows($result) > 0) {
2317
        $data = Database::fetch_array($result);
2318
        $courseInfo = api_format_course_array($data);
2319
    }
2320
2321
    return $courseInfo;*/
2322
2323
    $course = Session::read('_course');
2324
    if ('-1' == $course) {
2325
        $course = [];
2326
    }
2327
2328
    return $course;
2329
}
2330
2331
/**
2332
 * @param int $courseId
2333
 */
2334
function api_get_course_entity($courseId = 0): ?Course
2335
{
2336
    if (empty($courseId)) {
2337
        $courseId = api_get_course_int_id();
2338
    }
2339
2340
    return Container::getCourseRepository()->find($courseId);
0 ignored issues
show
Bug Best Practice introduced by
The expression return Chamilo\CoreBundl...tory()->find($courseId) returns the type Chamilo\CoreBundle\Entity\ResourceInterface which includes types incompatible with the type-hinted return Chamilo\CoreBundle\Entity\Course|null.
Loading history...
2341
}
2342
2343
/**
2344
 * @param int $id
2345
 */
2346
function api_get_session_entity($id = 0): ?SessionEntity
2347
{
2348
    if (empty($id)) {
2349
        $id = api_get_session_id();
2350
    }
2351
2352
    if (empty($id)) {
2353
        return null;
2354
    }
2355
2356
    return Container::getSessionRepository()->find($id);
2357
}
2358
2359
/**
2360
 * @param int $id
2361
 */
2362
function api_get_group_entity($id = 0): ?CGroup
2363
{
2364
    if (empty($id)) {
2365
        $id = api_get_group_id();
2366
    }
2367
2368
    return Container::getGroupRepository()->find($id);
0 ignored issues
show
Bug Best Practice introduced by
The expression return Chamilo\CoreBundl...Repository()->find($id) returns the type Chamilo\CoreBundle\Entity\ResourceInterface which includes types incompatible with the type-hinted return Chamilo\CourseBundle\Entity\CGroup|null.
Loading history...
2369
}
2370
2371
/**
2372
 * @param int $id
2373
 */
2374
function api_get_url_entity($id = 0): ?AccessUrl
2375
{
2376
    if (empty($id)) {
2377
        $id = api_get_current_access_url_id();
2378
    }
2379
2380
    return Container::getAccessUrlRepository()->find($id);
0 ignored issues
show
Bug Best Practice introduced by
The expression return Chamilo\CoreBundl...Repository()->find($id) returns the type Chamilo\CoreBundle\Entity\ResourceInterface which includes types incompatible with the type-hinted return Chamilo\CoreBundle\Entity\AccessUrl|null.
Loading history...
2381
}
2382
2383
/**
2384
 * Returns the current course info array.
2385
2386
 * Now if the course_code is given, the returned array gives info about that
2387
 * particular course, not specially the current one.
2388
 *
2389
 * @param int $id Numeric ID of the course
2390
 *
2391
 * @return array The course info as an array formatted by api_format_course_array, including category.name
2392
 */
2393
function api_get_course_info_by_id($id = 0)
2394
{
2395
    $id = (int) $id;
2396
    if (empty($id)) {
2397
        $course = Session::read('_course', []);
2398
2399
        return $course;
2400
    }
2401
2402
    $course = Container::getCourseRepository()->find($id);
2403
    if (empty($course)) {
2404
        return [];
2405
    }
2406
2407
    return api_format_course_array($course);
2408
}
2409
2410
/**
2411
 * Reformat the course array (output by api_get_course_info()) in order, mostly,
2412
 * to switch from 'code' to 'id' in the array.
2413
 *
2414
 * @return array
2415
 *
2416
 * @todo eradicate the false "id"=code field of the $_course array and use the int id
2417
 */
2418
function api_format_course_array(Course $course = null)
2419
{
2420
    if (empty($course)) {
2421
        return [];
2422
    }
2423
2424
    $courseData = [];
2425
    $courseData['id'] = $courseData['real_id'] = $course->getId();
2426
2427
    // Added
2428
    $courseData['code'] = $courseData['sysCode'] = $course->getCode();
2429
    $courseData['name'] = $courseData['title'] = $course->getTitle();
2430
    $courseData['official_code'] = $courseData['visual_code'] = $course->getVisualCode();
2431
    $courseData['path'] = $courseData['directory'] = $course->getDirectory(); // Use as key in path.
2432
    $courseData['creation_date'] = $course->getCreationDate()->format('Y-m-d H:i:s');
2433
    $courseData['titular'] = $course->getTutorName();
2434
    $courseData['language'] = $courseData['course_language'] = $course->getCourseLanguage();
2435
    $courseData['extLink']['url'] = $courseData['department_url'] = $course->getDepartmentUrl();
2436
    $courseData['extLink']['name'] = $courseData['department_name'] = $course->getDepartmentName();
2437
2438
    $courseData['visibility'] = $course->getVisibility();
2439
    $courseData['subscribe_allowed'] = $courseData['subscribe'] = $course->getSubscribe();
2440
    $courseData['unsubscribe'] = $course->getUnsubscribe();
2441
    $courseData['activate_legal'] = $course->getActivateLegal();
2442
    $courseData['legal'] = $course->getLegal();
2443
    $courseData['show_score'] = $course->getShowScore(); //used in the work tool
2444
2445
    //$coursePath = api_get_path(WEB_COURSE_PATH);
2446
    $coursePath = '/course/';
2447
    $webCourseHome = $coursePath.$courseData['real_id'].'/home';
2448
2449
    // Course password
2450
    $courseData['registration_code'] = $course->getRegistrationCode();
2451
    $courseData['disk_quota'] = $course->getDiskQuota();
2452
    $courseData['course_public_url'] = $webCourseHome;
2453
    $courseData['about_url'] = $coursePath.$courseData['real_id'].'/about';
2454
    $courseData['add_teachers_to_sessions_courses'] = $course->isAddTeachersToSessionsCourses();
2455
    $courseData['entity'] = $course;
2456
2457
    $image = Display::return_icon(
2458
        'course.png',
2459
        null,
2460
        null,
2461
        ICON_SIZE_BIG,
2462
        null,
2463
        true,
2464
        false
2465
    );
2466
2467
    $illustration = Container::getIllustrationRepository()->getIllustrationUrl($course);
2468
    if (!empty($illustration)) {
2469
        $image = $illustration;
2470
    }
2471
2472
    $courseData['course_image'] = $image.'?filter=course_picture_small';
2473
2474
    // Course large image
2475
    /*$courseData['course_image_large_source'] = '';
2476
    if (file_exists($courseSys.'/course-pic.png')) {
2477
        $url_image = $webCourseHome.'/course-pic.png';
2478
        $courseData['course_image_large_source'] = $courseSys.'/course-pic.png';
2479
    } else {
2480
        $url_image = Display::return_icon(
2481
            'session_default.png',
2482
            null,
2483
            null,
2484
            null,
2485
            null,
2486
            true,
2487
            true
2488
        );
2489
    }*/
2490
2491
    $courseData['course_image_large'] = $image.'?filter=course_picture_medium';
2492
2493
    return $courseData;
2494
}
2495
2496
/**
2497
 * Returns a difficult to guess password.
2498
 *
2499
 * @param int $length the length of the password
2500
 *
2501
 * @return string the generated password
2502
 */
2503
function api_generate_password($length = 8)
2504
{
2505
    if ($length < 2) {
2506
        $length = 2;
2507
    }
2508
2509
    $charactersLowerCase = 'abcdefghijkmnopqrstuvwxyz';
2510
    $charactersUpperCase = 'ABCDEFGHJKLMNPQRSTUVWXYZ';
2511
    $minNumbers = 2;
2512
    $length = $length - $minNumbers;
2513
    $minLowerCase = round($length / 2);
2514
    $minUpperCase = $length - $minLowerCase;
2515
2516
    $password = '';
2517
    $passwordRequirements = api_get_configuration_value('password_requirements');
2518
2519
    $factory = new RandomLib\Factory();
2520
    $generator = $factory->getGenerator(new SecurityLib\Strength(SecurityLib\Strength::MEDIUM));
2521
2522
    if (!empty($passwordRequirements)) {
2523
        $length = $passwordRequirements['min']['length'];
2524
        $minNumbers = $passwordRequirements['min']['numeric'];
2525
        $minLowerCase = $passwordRequirements['min']['lowercase'];
2526
        $minUpperCase = $passwordRequirements['min']['uppercase'];
2527
2528
        $rest = $length - $minNumbers - $minLowerCase - $minUpperCase;
2529
        // Add the rest to fill the length requirement
2530
        if ($rest > 0) {
2531
            $password .= $generator->generateString($rest, $charactersLowerCase.$charactersUpperCase);
2532
        }
2533
    }
2534
2535
    // Min digits default 2
2536
    for ($i = 0; $i < $minNumbers; $i++) {
2537
        $password .= $generator->generateInt(2, 9);
2538
    }
2539
2540
    // Min lowercase
2541
    $password .= $generator->generateString($minLowerCase, $charactersLowerCase);
2542
2543
    // Min uppercase
2544
    $password .= $generator->generateString($minUpperCase, $charactersUpperCase);
2545
    $password = str_shuffle($password);
2546
2547
    return $password;
2548
}
2549
2550
/**
2551
 * Checks a password to see wether it is OK to use.
2552
 *
2553
 * @param string $password
2554
 *
2555
 * @return bool if the password is acceptable, false otherwise
2556
 *              Notes about what a password "OK to use" is:
2557
 *              1. The password should be at least 5 characters long.
2558
 *              2. Only English letters (uppercase or lowercase, it doesn't matter) and digits are allowed.
2559
 *              3. The password should contain at least 3 letters.
2560
 *              4. It should contain at least 2 digits.
2561
 *              Settings will change if the configuration value is set: password_requirements
2562
 */
2563
function api_check_password($password)
2564
{
2565
    $passwordRequirements = Security::getPasswordRequirements();
2566
2567
    $minLength = $passwordRequirements['min']['length'];
2568
    $minNumbers = $passwordRequirements['min']['numeric'];
2569
    // Optional
2570
    $minLowerCase = $passwordRequirements['min']['lowercase'];
2571
    $minUpperCase = $passwordRequirements['min']['uppercase'];
2572
2573
    $minLetters = $minLowerCase + $minUpperCase;
2574
    $passwordLength = api_strlen($password);
2575
2576
    $conditions = [
2577
        'min_length' => $passwordLength >= $minLength,
2578
    ];
2579
2580
    $digits = 0;
2581
    $lowerCase = 0;
2582
    $upperCase = 0;
2583
2584
    for ($i = 0; $i < $passwordLength; $i++) {
2585
        $currentCharacterCode = api_ord(api_substr($password, $i, 1));
2586
        if ($currentCharacterCode >= 65 && $currentCharacterCode <= 90) {
2587
            $upperCase++;
2588
        }
2589
2590
        if ($currentCharacterCode >= 97 && $currentCharacterCode <= 122) {
2591
            $lowerCase++;
2592
        }
2593
        if ($currentCharacterCode >= 48 && $currentCharacterCode <= 57) {
2594
            $digits++;
2595
        }
2596
    }
2597
2598
    // Min number of digits
2599
    $conditions['min_numeric'] = $digits >= $minNumbers;
2600
2601
    if (!empty($minUpperCase)) {
2602
        // Uppercase
2603
        $conditions['min_uppercase'] = $upperCase >= $minUpperCase;
2604
    }
2605
2606
    if (!empty($minLowerCase)) {
2607
        // Lowercase
2608
        $conditions['min_lowercase'] = $upperCase >= $minLowerCase;
2609
    }
2610
2611
    // Min letters
2612
    $letters = $upperCase + $lowerCase;
2613
    $conditions['min_letters'] = $letters >= $minLetters;
2614
2615
    $isPasswordOk = true;
2616
    foreach ($conditions as $condition) {
2617
        if (false === $condition) {
2618
            $isPasswordOk = false;
2619
            break;
2620
        }
2621
    }
2622
2623
    if (false === $isPasswordOk) {
2624
        $output = get_lang('The new password does not match the minimum security requirements').'<br />';
2625
        $output .= Security::getPasswordRequirementsToString($conditions);
2626
2627
        Display::addFlash(Display::return_message($output, 'warning', false));
2628
    }
2629
2630
    return $isPasswordOk;
2631
}
2632
2633
/**
2634
 * Returns the status string corresponding to the status code.
2635
 *
2636
 * @author Noel Dieschburg
2637
 *
2638
 * @param the int status code
2639
 *
2640
 * @return string
2641
 */
2642
function get_status_from_code($status_code)
2643
{
2644
    switch ($status_code) {
2645
        case STUDENT:
2646
            return get_lang('Student', '');
2647
        case COURSEMANAGER:
2648
            return get_lang('Teacher', '');
2649
        case SESSIONADMIN:
2650
            return get_lang('SessionsAdmin', '');
2651
        case DRH:
2652
            return get_lang('Drh', '');
2653
        case ANONYMOUS:
2654
            return get_lang('Anonymous', '');
2655
        case PLATFORM_ADMIN:
2656
            return get_lang('Administrator', '');
2657
        case SESSION_COURSE_COACH:
2658
            return get_lang('SessionCourseCoach', '');
2659
        case SESSION_GENERAL_COACH:
2660
            return get_lang('SessionGeneralCoach', '');
2661
        case COURSE_TUTOR:
2662
            return get_lang('CourseAssistant', '');
2663
        case STUDENT_BOSS:
2664
            return get_lang('StudentBoss', '');
2665
        case INVITEE:
2666
            return get_lang('Invitee', '');
2667
    }
2668
}
2669
2670
/**
2671
 * Gets the current Chamilo (not PHP/cookie) session ID.
2672
 *
2673
 * @return int O if no active session, the session ID otherwise
2674
 */
2675
function api_get_session_id()
2676
{
2677
    return (int) Session::read('sid', 0);
2678
}
2679
2680
/**
2681
 * Gets the current Chamilo (not social network) group ID.
2682
 *
2683
 * @return int O if no active session, the session ID otherwise
2684
 */
2685
function api_get_group_id()
2686
{
2687
    return Session::read('gid', 0);
2688
}
2689
2690
/**
2691
 * Gets the current or given session name.
2692
 *
2693
 * @param   int     Session ID (optional)
2694
 *
2695
 * @return string The session name, or null if not found
2696
 */
2697
function api_get_session_name($session_id = 0)
2698
{
2699
    if (empty($session_id)) {
2700
        $session_id = api_get_session_id();
2701
        if (empty($session_id)) {
2702
            return null;
2703
        }
2704
    }
2705
    $t = Database::get_main_table(TABLE_MAIN_SESSION);
2706
    $s = "SELECT name FROM $t WHERE id = ".(int) $session_id;
2707
    $r = Database::query($s);
2708
    $c = Database::num_rows($r);
2709
    if ($c > 0) {
2710
        //technically, there can be only one, but anyway we take the first
2711
        $rec = Database::fetch_array($r);
2712
2713
        return $rec['name'];
2714
    }
2715
2716
    return null;
2717
}
2718
2719
/**
2720
 * Gets the session info by id.
2721
 *
2722
 * @param int $id Session ID
2723
 *
2724
 * @return array information of the session
2725
 */
2726
function api_get_session_info($id)
2727
{
2728
    return SessionManager::fetch($id);
2729
}
2730
2731
/**
2732
 * Gets the session visibility by session id.
2733
 *
2734
 * @param int  $session_id
2735
 * @param int  $courseId
2736
 * @param bool $ignore_visibility_for_admins
2737
 *
2738
 * @return int
2739
 *             0 = session still available,
2740
 *             SESSION_VISIBLE_READ_ONLY = 1,
2741
 *             SESSION_VISIBLE = 2,
2742
 *             SESSION_INVISIBLE = 3
2743
 */
2744
function api_get_session_visibility(
2745
    $session_id,
2746
    $courseId = null,
2747
    $ignore_visibility_for_admins = true
2748
) {
2749
    if (api_is_platform_admin()) {
2750
        if ($ignore_visibility_for_admins) {
2751
            return SESSION_AVAILABLE;
2752
        }
2753
    }
2754
2755
    $now = time();
2756
    if (empty($session_id)) {
2757
        return 0; // Means that the session is still available.
2758
    }
2759
2760
    $session_id = (int) $session_id;
2761
    $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
2762
2763
    $result = Database::query("SELECT * FROM $tbl_session WHERE id = $session_id");
2764
2765
    if (Database::num_rows($result) <= 0) {
2766
        return SESSION_INVISIBLE;
2767
    }
2768
2769
    $row = Database::fetch_array($result, 'ASSOC');
2770
    $visibility = $row['visibility'];
2771
2772
    // I don't care the session visibility.
2773
    if (empty($row['access_start_date']) && empty($row['access_end_date'])) {
2774
        // Session duration per student.
2775
        if (isset($row['duration']) && !empty($row['duration'])) {
2776
            $duration = $row['duration'] * 24 * 60 * 60;
2777
            $courseAccess = CourseManager::getFirstCourseAccessPerSessionAndUser($session_id, api_get_user_id());
2778
2779
            // If there is a session duration but there is no previous
2780
            // access by the user, then the session is still available
2781
            if (0 == count($courseAccess)) {
2782
                return SESSION_AVAILABLE;
2783
            }
2784
2785
            $currentTime = time();
2786
            $firstAccess = isset($courseAccess['login_course_date'])
2787
                ? api_strtotime($courseAccess['login_course_date'], 'UTC')
2788
                : 0;
2789
            $userDurationData = SessionManager::getUserSession(
2790
                api_get_user_id(),
2791
                $session_id
2792
            );
2793
            $userDuration = isset($userDurationData['duration'])
2794
                ? (intval($userDurationData['duration']) * 24 * 60 * 60)
2795
                : 0;
2796
2797
            $totalDuration = $firstAccess + $duration + $userDuration;
2798
2799
            return $totalDuration > $currentTime ? SESSION_AVAILABLE : SESSION_VISIBLE_READ_ONLY;
2800
        }
2801
2802
        return SESSION_AVAILABLE;
2803
    }
2804
2805
    // If start date was set.
2806
    if (!empty($row['access_start_date'])) {
2807
        $visibility = $now > api_strtotime($row['access_start_date'], 'UTC') ? SESSION_AVAILABLE : SESSION_INVISIBLE;
2808
    }
2809
2810
    // If the end date was set.
2811
    if (!empty($row['access_end_date'])) {
2812
        // Only if date_start said that it was ok
2813
        if (SESSION_AVAILABLE === $visibility) {
2814
            $visibility = $now < api_strtotime($row['access_end_date'], 'UTC')
2815
                ? SESSION_AVAILABLE // Date still available
2816
                : $row['visibility']; // Session ends
2817
        }
2818
    }
2819
2820
    // If I'm a coach the visibility can change in my favor depending in the coach dates.
2821
    $isCoach = api_is_coach($session_id, $courseId);
2822
2823
    if ($isCoach) {
2824
        // Test start date.
2825
        if (!empty($row['coach_access_start_date'])) {
2826
            $start = api_strtotime($row['coach_access_start_date'], 'UTC');
2827
            $visibility = $start < $now ? SESSION_AVAILABLE : SESSION_INVISIBLE;
2828
        }
2829
2830
        // Test end date.
2831
        if (!empty($row['coach_access_end_date'])) {
2832
            if (SESSION_AVAILABLE === $visibility) {
2833
                $endDateCoach = api_strtotime($row['coach_access_end_date'], 'UTC');
2834
                $visibility = $endDateCoach >= $now ? SESSION_AVAILABLE : $row['visibility'];
2835
            }
2836
        }
2837
    }
2838
2839
    return $visibility;
2840
}
2841
2842
/**
2843
 * This function returns a (star) session icon if the session is not null and
2844
 * the user is not a student.
2845
 *
2846
 * @param int $sessionId
2847
 * @param int $statusId  User status id - if 5 (student), will return empty
2848
 *
2849
 * @return string Session icon
2850
 */
2851
function api_get_session_image($sessionId, $statusId)
2852
{
2853
    $sessionId = (int) $sessionId;
2854
    $image = '';
2855
    if (STUDENT != $statusId) {
2856
        // Check whether is not a student
2857
        if ($sessionId > 0) {
2858
            $image = '&nbsp;&nbsp;'.Display::return_icon(
2859
                'star.png',
2860
                get_lang('Session-specific resource'),
2861
                ['align' => 'absmiddle'],
2862
                ICON_SIZE_SMALL
2863
            );
2864
        }
2865
    }
2866
2867
    return $image;
2868
}
2869
2870
/**
2871
 * This function add an additional condition according to the session of the course.
2872
 *
2873
 * @param int    $session_id        session id
2874
 * @param bool   $and               optional, true if more than one condition false if the only condition in the query
2875
 * @param bool   $with_base_content optional, true to accept content with session=0 as well,
2876
 *                                  false for strict session condition
2877
 * @param string $session_field
2878
 *
2879
 * @return string condition of the session
2880
 */
2881
function api_get_session_condition(
2882
    $session_id,
2883
    $and = true,
2884
    $with_base_content = false,
2885
    $session_field = 'session_id'
2886
) {
2887
    $session_id = (int) $session_id;
2888
2889
    if (empty($session_field)) {
2890
        $session_field = 'session_id';
2891
    }
2892
    // Condition to show resources by session
2893
    $condition_add = $and ? ' AND ' : ' WHERE ';
2894
2895
    if ($with_base_content) {
2896
        $condition_session = $condition_add." ( $session_field = $session_id OR $session_field = 0 OR $session_field IS NULL) ";
2897
    } else {
2898
        if (empty($session_id)) {
2899
            $condition_session = $condition_add." ($session_field = $session_id OR $session_field IS NULL)";
2900
        } else {
2901
            $condition_session = $condition_add." $session_field = $session_id ";
2902
        }
2903
    }
2904
2905
    return $condition_session;
2906
}
2907
2908
/**
2909
 * Returns the value of a setting from the web-adjustable admin config settings.
2910
 *
2911
 * WARNING true/false are stored as string, so when comparing you need to check e.g.
2912
 * if (api_get_setting('show_navigation_menu') == 'true') //CORRECT
2913
 * instead of
2914
 * if (api_get_setting('show_navigation_menu') == true) //INCORRECT
2915
 *
2916
 * @param string $variable The variable name
2917
 *
2918
 * @return string
2919
 */
2920
function api_get_setting($variable)
2921
{
2922
    $settingsManager = Container::getSettingsManager();
2923
    if (empty($settingsManager)) {
2924
        return '';
2925
    }
2926
    $variable = trim($variable);
2927
2928
    switch ($variable) {
2929
        /*case 'header_extra_content':
2930
            $filename = api_get_path(SYS_PATH).api_get_home_path().'header_extra_content.txt';
2931
            if (file_exists($filename)) {
2932
                $value = file_get_contents($filename);
2933
2934
                return $value;
2935
            } else {
2936
                return '';
2937
            }
2938
            break;
2939
        case 'footer_extra_content':
2940
            $filename = api_get_path(SYS_PATH).api_get_home_path().'footer_extra_content.txt';
2941
            if (file_exists($filename)) {
2942
                $value = file_get_contents($filename);
2943
2944
                return $value;
2945
            } else {
2946
                return '';
2947
            }
2948
            break;*/
2949
        case 'server_type':
2950
            $test = ['dev', 'test'];
2951
            $environment = Container::getEnvironment();
2952
            if (in_array($environment, $test)) {
2953
                return 'test';
2954
            }
2955
2956
            return 'prod';
2957
        case 'stylesheets':
2958
            $variable = 'platform.theme';
2959
        // deprecated settings
2960
        // no break
2961
        case 'openid_authentication':
2962
        case 'service_ppt2lp':
2963
        case 'formLogin_hide_unhide_label':
2964
            return false;
2965
            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...
2966
        case 'tool_visible_by_default_at_creation':
2967
            $values = $settingsManager->getSetting($variable);
2968
            $newResult = [];
2969
            foreach ($values as $parameter) {
2970
                $newResult[$parameter] = 'true';
2971
            }
2972
2973
            return $newResult;
2974
            break;
2975
        default:
2976
            return $settingsManager->getSetting($variable);
2977
            break;
2978
    }
2979
}
2980
2981
/**
2982
 * @param string $variable
2983
 * @param string $option
2984
 *
2985
 * @return bool
2986
 */
2987
function api_get_setting_in_list($variable, $option)
2988
{
2989
    $value = api_get_setting($variable);
2990
2991
    return in_array($option, $value);
2992
}
2993
2994
/**
2995
 * @param string $plugin
2996
 * @param string $variable
2997
 *
2998
 * @return string
2999
 */
3000
function api_get_plugin_setting($plugin, $variable)
3001
{
3002
    $variableName = $plugin.'_'.$variable;
3003
    //$result = api_get_setting($variableName);
3004
    $params = [
3005
        'category = ? AND subkey = ? AND variable = ?' => [
3006
            'Plugins',
3007
            $plugin,
3008
            $variableName,
3009
        ],
3010
    ];
3011
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
3012
    $result = Database::select(
3013
        'selected_value',
3014
        $table,
3015
        ['where' => $params],
3016
        'one'
3017
    );
3018
    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...
3019
        $value = $result['selected_value'];
3020
        $serializedValue = @unserialize($result['selected_value'], []);
3021
        if (false !== $serializedValue) {
3022
            $value = $serializedValue;
3023
        }
3024
3025
        return $value;
3026
    }
3027
3028
    return null;
3029
    /// Old code
3030
3031
    $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...
3032
    $result = api_get_setting($variableName);
3033
3034
    if (isset($result[$plugin])) {
3035
        $value = $result[$plugin];
3036
3037
        $unserialized = UnserializeApi::unserialize('not_allowed_classes', $value, true);
3038
3039
        if (false !== $unserialized) {
3040
            $value = $unserialized;
3041
        }
3042
3043
        return $value;
3044
    }
3045
3046
    return null;
3047
}
3048
3049
/**
3050
 * Returns the value of a setting from the web-adjustable admin config settings.
3051
 */
3052
function api_get_settings_params($params)
3053
{
3054
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
3055
    $result = Database::select('*', $table, ['where' => $params]);
3056
3057
    return $result;
3058
}
3059
3060
/**
3061
 * @param array $params example: [id = ? => '1']
3062
 *
3063
 * @return array
3064
 */
3065
function api_get_settings_params_simple($params)
3066
{
3067
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
3068
    $result = Database::select('*', $table, ['where' => $params], 'one');
3069
3070
    return $result;
3071
}
3072
3073
/**
3074
 * Returns the value of a setting from the web-adjustable admin config settings.
3075
 */
3076
function api_delete_settings_params($params)
3077
{
3078
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
3079
    $result = Database::delete($table, $params);
3080
3081
    return $result;
3082
}
3083
3084
/**
3085
 * Returns an escaped version of $_SERVER['PHP_SELF'] to avoid XSS injection.
3086
 *
3087
 * @return string Escaped version of $_SERVER['PHP_SELF']
3088
 */
3089
function api_get_self()
3090
{
3091
    return htmlentities($_SERVER['PHP_SELF']);
3092
}
3093
3094
/* USER PERMISSIONS */
3095
3096
/**
3097
 * Checks whether current user is a platform administrator.
3098
 *
3099
 * @param bool $allowSessionAdmins Whether session admins should be considered admins or not
3100
 * @param bool $allowDrh           Whether HR directors should be considered admins or not
3101
 *
3102
 * @return bool true if the user has platform admin rights,
3103
 *              false otherwise
3104
 *
3105
 * @see usermanager::is_admin(user_id) for a user-id specific function
3106
 */
3107
function api_is_platform_admin($allowSessionAdmins = false, $allowDrh = false)
3108
{
3109
    $currentUser = api_get_current_user();
3110
3111
    if (null === $currentUser) {
3112
        return false;
3113
    }
3114
3115
    $isAdmin = Session::read('is_platformAdmin');
3116
    if ($isAdmin) {
3117
        return true;
3118
    }
3119
    $user = api_get_user_info();
3120
3121
    return
3122
        isset($user['status']) &&
3123
        (
3124
            ($allowSessionAdmins && SESSIONADMIN == $user['status']) ||
3125
            ($allowDrh && DRH == $user['status'])
3126
        );
3127
}
3128
3129
/**
3130
 * Checks whether the user given as user id is in the admin table.
3131
 *
3132
 * @param int $user_id If none provided, will use current user
3133
 * @param int $url     URL ID. If provided, also check if the user is active on given URL
3134
 *
3135
 * @return bool True if the user is admin, false otherwise
3136
 */
3137
function api_is_platform_admin_by_id($user_id = null, $url = null)
3138
{
3139
    $user_id = (int) $user_id;
3140
    if (empty($user_id)) {
3141
        $user_id = api_get_user_id();
3142
    }
3143
    $admin_table = Database::get_main_table(TABLE_MAIN_ADMIN);
3144
    $sql = "SELECT * FROM $admin_table WHERE user_id = $user_id";
3145
    $res = Database::query($sql);
3146
    $is_admin = 1 === Database::num_rows($res);
3147
    if (!$is_admin || !isset($url)) {
3148
        return $is_admin;
3149
    }
3150
    // We get here only if $url is set
3151
    $url = (int) $url;
3152
    $url_user_table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
3153
    $sql = "SELECT * FROM $url_user_table
3154
            WHERE access_url_id = $url AND user_id = $user_id";
3155
    $res = Database::query($sql);
3156
    $result = 1 === Database::num_rows($res);
3157
3158
    return $result;
3159
}
3160
3161
/**
3162
 * Returns the user's numeric status ID from the users table.
3163
 *
3164
 * @param int $user_id If none provided, will use current user
3165
 *
3166
 * @return int User's status (1 for teacher, 5 for student, etc)
3167
 */
3168
function api_get_user_status($user_id = null)
3169
{
3170
    $user_id = (int) $user_id;
3171
    if (empty($user_id)) {
3172
        $user_id = api_get_user_id();
3173
    }
3174
    $table = Database::get_main_table(TABLE_MAIN_USER);
3175
    $sql = "SELECT status FROM $table WHERE id = $user_id ";
3176
    $result = Database::query($sql);
3177
    $status = null;
3178
    if (Database::num_rows($result)) {
3179
        $row = Database::fetch_array($result);
3180
        $status = $row['status'];
3181
    }
3182
3183
    return $status;
3184
}
3185
3186
/**
3187
 * Checks whether current user is allowed to create courses.
3188
 *
3189
 * @return bool true if the user has course creation rights,
3190
 *              false otherwise
3191
 */
3192
function api_is_allowed_to_create_course()
3193
{
3194
    if (api_is_platform_admin()) {
3195
        return true;
3196
    }
3197
3198
    // Teachers can only create courses
3199
    if (api_is_teacher()) {
3200
        if ('true' === api_get_setting('allow_users_to_create_courses')) {
3201
            return true;
3202
        } else {
3203
            return false;
3204
        }
3205
    }
3206
3207
    return Session::read('is_allowedCreateCourse');
3208
}
3209
3210
/**
3211
 * Checks whether the current user is a course administrator.
3212
 *
3213
 * @return bool True if current user is a course administrator
3214
 */
3215
function api_is_course_admin()
3216
{
3217
    if (api_is_platform_admin()) {
3218
        return true;
3219
    }
3220
3221
    $user = api_get_current_user();
3222
    if ($user) {
3223
        if (
3224
            $user->hasRole('ROLE_CURRENT_SESSION_COURSE_TEACHER') ||
3225
            $user->hasRole('ROLE_CURRENT_COURSE_TEACHER')
3226
        ) {
3227
            return true;
3228
        }
3229
    }
3230
3231
    return false;
3232
    //return Session::read('is_courseAdmin');
3233
}
3234
3235
/**
3236
 * Checks whether the current user is a course coach
3237
 * Based on the presence of user in session.id_coach (session general coach).
3238
 *
3239
 * @return bool True if current user is a course coach
3240
 */
3241
function api_is_session_general_coach()
3242
{
3243
    return Session::read('is_session_general_coach');
3244
}
3245
3246
/**
3247
 * Checks whether the current user is a course tutor
3248
 * Based on the presence of user in session_rel_course_rel_user.user_id with status = 2.
3249
 *
3250
 * @return bool True if current user is a course tutor
3251
 */
3252
function api_is_course_tutor()
3253
{
3254
    return Session::read('is_courseTutor');
3255
}
3256
3257
/**
3258
 * @param int $user_id
3259
 * @param int $courseId
3260
 * @param int $session_id
3261
 *
3262
 * @return bool
3263
 */
3264
function api_is_course_session_coach($user_id, $courseId, $session_id)
3265
{
3266
    $session_table = Database::get_main_table(TABLE_MAIN_SESSION);
3267
    $session_rel_course_rel_user_table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3268
3269
    $user_id = (int) $user_id;
3270
    $session_id = (int) $session_id;
3271
    $courseId = (int) $courseId;
3272
3273
    $sql = "SELECT DISTINCT session.id
3274
            FROM $session_table
3275
            INNER JOIN $session_rel_course_rel_user_table session_rc_ru
3276
            ON session.id = session_rc_ru.session_id
3277
            WHERE
3278
                session_rc_ru.user_id = '".$user_id."'  AND
3279
                session_rc_ru.c_id = '$courseId' AND
3280
                session_rc_ru.status = 2 AND
3281
                session_rc_ru.session_id = '$session_id'";
3282
    $result = Database::query($sql);
3283
3284
    return Database::num_rows($result) > 0;
3285
}
3286
3287
/**
3288
 * Checks whether the current user is a course or session coach.
3289
 *
3290
 * @param int $session_id
3291
 * @param int $courseId
3292
 * @param bool  Check whether we are in student view and, if we are, return false
3293
 *
3294
 * @return bool True if current user is a course or session coach
3295
 */
3296
function api_is_coach($session_id = 0, $courseId = null, $check_student_view = true)
3297
{
3298
    $userId = api_get_user_id();
3299
3300
    if (!empty($session_id)) {
3301
        $session_id = (int) $session_id;
3302
    } else {
3303
        $session_id = api_get_session_id();
3304
    }
3305
3306
    // The student preview was on
3307
    if ($check_student_view && api_is_student_view_active()) {
3308
        return false;
3309
    }
3310
3311
    if (!empty($courseId)) {
3312
        $courseId = (int) $courseId;
3313
    } else {
3314
        $courseId = api_get_course_int_id();
3315
    }
3316
3317
    $session_table = Database::get_main_table(TABLE_MAIN_SESSION);
3318
    $session_rel_course_rel_user_table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3319
    $sessionIsCoach = [];
3320
3321
    if (!empty($courseId)) {
3322
        $sql = "SELECT DISTINCT s.id, name, access_start_date, access_end_date
3323
                FROM $session_table s
3324
                INNER JOIN $session_rel_course_rel_user_table session_rc_ru
3325
                ON session_rc_ru.session_id = s.id AND session_rc_ru.user_id = '".$userId."'
3326
                WHERE
3327
                    session_rc_ru.c_id = '$courseId' AND
3328
                    session_rc_ru.status = 2 AND
3329
                    session_rc_ru.session_id = '$session_id'";
3330
        $result = Database::query($sql);
3331
        $sessionIsCoach = Database::store_result($result);
3332
    }
3333
3334
    if (!empty($session_id)) {
3335
        $sql = "SELECT DISTINCT id, name, access_start_date, access_end_date
3336
                FROM $session_table
3337
                WHERE session.id_coach = $userId AND id = $session_id
3338
                ORDER BY access_start_date, access_end_date, name";
3339
        $result = Database::query($sql);
3340
        if (!empty($sessionIsCoach)) {
3341
            $sessionIsCoach = array_merge(
3342
                $sessionIsCoach,
3343
                Database::store_result($result)
3344
            );
3345
        } else {
3346
            $sessionIsCoach = Database::store_result($result);
3347
        }
3348
    }
3349
3350
    return count($sessionIsCoach) > 0;
3351
}
3352
3353
/**
3354
 * Checks whether the current user is a session administrator.
3355
 *
3356
 * @return bool True if current user is a course administrator
3357
 */
3358
function api_is_session_admin()
3359
{
3360
    $user = api_get_user_info();
3361
3362
    return isset($user['status']) && SESSIONADMIN == $user['status'];
3363
}
3364
3365
/**
3366
 * Checks whether the current user is a human resources manager.
3367
 *
3368
 * @return bool True if current user is a human resources manager
3369
 */
3370
function api_is_drh()
3371
{
3372
    $user = api_get_user_info();
3373
3374
    return isset($user['status']) && DRH == $user['status'];
3375
}
3376
3377
/**
3378
 * Checks whether the current user is a student.
3379
 *
3380
 * @return bool True if current user is a human resources manager
3381
 */
3382
function api_is_student()
3383
{
3384
    $user = api_get_user_info();
3385
3386
    return isset($user['status']) && STUDENT == $user['status'];
3387
}
3388
3389
/**
3390
 * Checks whether the current user has the status 'teacher'.
3391
 *
3392
 * @return bool True if current user is a human resources manager
3393
 */
3394
function api_is_teacher()
3395
{
3396
    $user = api_get_user_info();
3397
3398
    return isset($user['status']) && COURSEMANAGER == $user['status'];
3399
}
3400
3401
/**
3402
 * Checks whether the current user is a invited user.
3403
 *
3404
 * @return bool
3405
 */
3406
function api_is_invitee()
3407
{
3408
    $user = api_get_user_info();
3409
3410
    return isset($user['status']) && INVITEE == $user['status'];
3411
}
3412
3413
/**
3414
 * This function checks whether a session is assigned into a category.
3415
 *
3416
 * @param int       - session id
0 ignored issues
show
Documentation Bug introduced by
The doc comment - at position 0 could not be parsed: Unknown type name '-' at position 0 in -.
Loading history...
3417
 * @param string    - category name
3418
 *
3419
 * @return bool - true if is found, otherwise false
3420
 */
3421
function api_is_session_in_category($session_id, $category_name)
3422
{
3423
    $session_id = (int) $session_id;
3424
    $category_name = Database::escape_string($category_name);
3425
    $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
3426
    $tbl_session_category = Database::get_main_table(TABLE_MAIN_SESSION_CATEGORY);
3427
3428
    $sql = "SELECT 1
3429
            FROM $tbl_session
3430
            WHERE $session_id IN (
3431
                SELECT s.id FROM $tbl_session s, $tbl_session_category sc
3432
                WHERE
3433
                  s.session_category_id = sc.id AND
3434
                  sc.name LIKE '%$category_name'
3435
            )";
3436
    $rs = Database::query($sql);
3437
3438
    if (Database::num_rows($rs) > 0) {
3439
        return true;
3440
    } else {
3441
        return false;
3442
    }
3443
}
3444
3445
/**
3446
 * Displays the title of a tool.
3447
 * Normal use: parameter is a string:
3448
 * api_display_tool_title("My Tool").
3449
 *
3450
 * Optionally, there can be a subtitle below
3451
 * the normal title, and / or a supra title above the normal title.
3452
 *
3453
 * e.g. supra title:
3454
 * group
3455
 * GROUP PROPERTIES
3456
 *
3457
 * e.g. subtitle:
3458
 * AGENDA
3459
 * calender & events tool
3460
 *
3461
 * @author Hugues Peeters <[email protected]>
3462
 *
3463
 * @param mixed $title_element - it could either be a string or an array
3464
 *                             containing 'supraTitle', 'mainTitle',
3465
 *                             'subTitle'
3466
 */
3467
function api_display_tool_title($title_element)
3468
{
3469
    if (is_string($title_element)) {
3470
        $tit = $title_element;
3471
        unset($title_element);
3472
        $title_element = [];
3473
        $title_element['mainTitle'] = $tit;
3474
    }
3475
    echo '<h3>';
3476
    if (!empty($title_element['supraTitle'])) {
3477
        echo '<small>'.$title_element['supraTitle'].'</small><br />';
3478
    }
3479
    if (!empty($title_element['mainTitle'])) {
3480
        echo $title_element['mainTitle'];
3481
    }
3482
    if (!empty($title_element['subTitle'])) {
3483
        echo '<br /><small>'.$title_element['subTitle'].'</small>';
3484
    }
3485
    echo '</h3>';
3486
}
3487
3488
/**
3489
 * Displays options for switching between student view and course manager view.
3490
 *
3491
 * Changes in version 1.2 (Patrick Cool)
3492
 * Student view switch now behaves as a real switch. It maintains its current state until the state
3493
 * is changed explicitly
3494
 *
3495
 * Changes in version 1.1 (Patrick Cool)
3496
 * student view now works correctly in subfolders of the document tool
3497
 * student view works correctly in the new links tool
3498
 *
3499
 * Example code for using this in your tools:
3500
 * //if ($is_courseAdmin && api_get_setting('student_view_enabled') == 'true') {
3501
 * //   display_tool_view_option($isStudentView);
3502
 * //}
3503
 * //and in later sections, use api_is_allowed_to_edit()
3504
 *
3505
 * @author Roan Embrechts
3506
 * @author Patrick Cool
3507
 * @author Julio Montoya, changes added in Chamilo
3508
 *
3509
 * @version 1.2
3510
 *
3511
 * @todo rewrite code so it is easier to understand
3512
 */
3513
function api_display_tool_view_option()
3514
{
3515
    if ('true' != api_get_setting('student_view_enabled')) {
3516
        return '';
3517
    }
3518
3519
    $sourceurl = '';
3520
    $is_framed = false;
3521
    // Exceptions apply for all multi-frames pages
3522
    if (false !== strpos($_SERVER['REQUEST_URI'], 'chat/chat_banner.php')) {
3523
        // The chat is a multiframe bit that doesn't work too well with the student_view, so do not show the link
3524
        return '';
3525
    }
3526
3527
    // Uncomment to remove student view link from document view page
3528
    if (false !== strpos($_SERVER['REQUEST_URI'], 'lp/lp_header.php')) {
3529
        if (empty($_GET['lp_id'])) {
3530
            return '';
3531
        }
3532
        $sourceurl = substr($_SERVER['REQUEST_URI'], 0, strpos($_SERVER['REQUEST_URI'], '?'));
3533
        $sourceurl = str_replace(
3534
            'lp/lp_header.php',
3535
            'lp/lp_controller.php?'.api_get_cidreq().'&action=view&lp_id='.intval($_GET['lp_id']).'&isStudentView='.('studentview' == $_SESSION['studentview'] ? 'false' : 'true'),
3536
            $sourceurl
3537
        );
3538
        //showinframes doesn't handle student view anyway...
3539
        //return '';
3540
        $is_framed = true;
3541
    }
3542
3543
    // Check whether the $_SERVER['REQUEST_URI'] contains already url parameters (thus a questionmark)
3544
    if (!$is_framed) {
3545
        if (false === strpos($_SERVER['REQUEST_URI'], '?')) {
3546
            $sourceurl = api_get_self().'?'.api_get_cidreq();
3547
        } else {
3548
            $sourceurl = $_SERVER['REQUEST_URI'];
3549
        }
3550
    }
3551
3552
    $output_string = '';
3553
    if (!empty($_SESSION['studentview'])) {
3554
        if ('studentview' == $_SESSION['studentview']) {
3555
            // We have to remove the isStudentView=true from the $sourceurl
3556
            $sourceurl = str_replace('&isStudentView=true', '', $sourceurl);
3557
            $sourceurl = str_replace('&isStudentView=false', '', $sourceurl);
3558
            $output_string .= '<a class="btn btn-primary btn-sm" href="'.$sourceurl.'&isStudentView=false" target="_self">'.
3559
                Display::returnFontAwesomeIcon('eye').' '.get_lang('Switch to teacher view').'</a>';
3560
        } elseif ('teacherview' == $_SESSION['studentview']) {
3561
            // Switching to teacherview
3562
            $sourceurl = str_replace('&isStudentView=true', '', $sourceurl);
3563
            $sourceurl = str_replace('&isStudentView=false', '', $sourceurl);
3564
            $output_string .= '<a class="btn btn-default btn-sm" href="'.$sourceurl.'&isStudentView=true" target="_self">'.
3565
                Display::returnFontAwesomeIcon('eye').' '.get_lang('Switch to student view').'</a>';
3566
        }
3567
    } else {
3568
        $output_string .= '<a class="btn btn-default btn-sm" href="'.$sourceurl.'&isStudentView=true" target="_self">'.
3569
            Display::returnFontAwesomeIcon('eye').' '.get_lang('Switch to student view').'</a>';
3570
    }
3571
    $output_string = Security::remove_XSS($output_string);
3572
    $html = Display::tag('div', $output_string, ['class' => 'view-options']);
3573
3574
    return $html;
3575
}
3576
3577
// TODO: This is for the permission section.
3578
/**
3579
 * Function that removes the need to directly use is_courseAdmin global in
3580
 * tool scripts. It returns true or false depending on the user's rights in
3581
 * this particular course.
3582
 * Optionally checking for tutor and coach roles here allows us to use the
3583
 * student_view feature altogether with these roles as well.
3584
 *
3585
 * @param bool  Whether to check if the user has the tutor role
3586
 * @param bool  Whether to check if the user has the coach role
3587
 * @param bool  Whether to check if the user has the session coach role
3588
 * @param bool  check the student view or not
3589
 *
3590
 * @author Roan Embrechts
3591
 * @author Patrick Cool
3592
 * @author Julio Montoya
3593
 *
3594
 * @version 1.1, February 2004
3595
 *
3596
 * @return bool true: the user has the rights to edit, false: he does not
3597
 */
3598
function api_is_allowed_to_edit(
3599
    $tutor = false,
3600
    $coach = false,
3601
    $session_coach = false,
3602
    $check_student_view = true
3603
) {
3604
    $allowSessionAdminEdit = true === api_get_setting('session.session_admins_edit_courses_content');
3605
    // Admins can edit anything.
3606
    if (api_is_platform_admin($allowSessionAdminEdit)) {
3607
        //The student preview was on
3608
        if ($check_student_view && api_is_student_view_active()) {
3609
            return false;
3610
        }
3611
3612
        return true;
3613
    }
3614
3615
    $sessionId = api_get_session_id();
3616
3617
    if ($sessionId && api_get_configuration_value('session_courses_read_only_mode')) {
3618
        $efv = new ExtraFieldValue('course');
3619
        $lockExrafieldField = $efv->get_values_by_handler_and_field_variable(
3620
            api_get_course_int_id(),
3621
            'session_courses_read_only_mode'
3622
        );
3623
3624
        if (!empty($lockExrafieldField['value'])) {
3625
            return false;
3626
        }
3627
    }
3628
3629
    $is_allowed_coach_to_edit = api_is_coach(null, null, $check_student_view);
3630
    $session_visibility = api_get_session_visibility($sessionId);
3631
    $is_courseAdmin = api_is_course_admin();
3632
3633
    if (!$is_courseAdmin && $tutor) {
3634
        // If we also want to check if the user is a tutor...
3635
        $is_courseAdmin = $is_courseAdmin || api_is_course_tutor();
3636
    }
3637
3638
    if (!$is_courseAdmin && $coach) {
3639
        // If we also want to check if the user is a coach...';
3640
        // Check if session visibility is read only for coaches.
3641
        if (SESSION_VISIBLE_READ_ONLY == $session_visibility) {
3642
            $is_allowed_coach_to_edit = false;
3643
        }
3644
3645
        if ('true' === api_get_setting('allow_coach_to_edit_course_session')) {
3646
            // Check if coach is allowed to edit a course.
3647
            $is_courseAdmin = $is_courseAdmin || $is_allowed_coach_to_edit;
3648
        }
3649
    }
3650
3651
    if (!$is_courseAdmin && $session_coach) {
3652
        $is_courseAdmin = $is_courseAdmin || $is_allowed_coach_to_edit;
3653
    }
3654
3655
    // Check if the student_view is enabled, and if so, if it is activated.
3656
    if ('true' === api_get_setting('student_view_enabled')) {
3657
        $studentView = api_is_student_view_active();
3658
        if (!empty($sessionId)) {
3659
            // Check if session visibility is read only for coaches.
3660
            if (SESSION_VISIBLE_READ_ONLY == $session_visibility) {
3661
                $is_allowed_coach_to_edit = false;
3662
            }
3663
3664
            $is_allowed = false;
3665
            if ('true' === api_get_setting('allow_coach_to_edit_course_session')) {
3666
                // Check if coach is allowed to edit a course.
3667
                $is_allowed = $is_allowed_coach_to_edit;
3668
            }
3669
            if ($check_student_view) {
3670
                $is_allowed = $is_allowed && false === $studentView;
3671
            }
3672
        } else {
3673
            $is_allowed = $is_courseAdmin;
3674
            if ($check_student_view) {
3675
                $is_allowed = $is_courseAdmin && false === $studentView;
3676
            }
3677
        }
3678
3679
        return $is_allowed;
3680
    } else {
3681
        return $is_courseAdmin;
3682
    }
3683
}
3684
3685
/**
3686
 * Returns true if user is a course coach of at least one course in session.
3687
 *
3688
 * @param int $sessionId
3689
 *
3690
 * @return bool
3691
 */
3692
function api_is_coach_of_course_in_session($sessionId)
3693
{
3694
    if (api_is_platform_admin()) {
3695
        return true;
3696
    }
3697
3698
    $userId = api_get_user_id();
3699
    $courseList = UserManager::get_courses_list_by_session(
3700
        $userId,
3701
        $sessionId
3702
    );
3703
3704
    // Session visibility.
3705
    $visibility = api_get_session_visibility(
3706
        $sessionId,
3707
        null,
3708
        false
3709
    );
3710
3711
    if (SESSION_VISIBLE != $visibility && !empty($courseList)) {
3712
        // Course Coach session visibility.
3713
        $blockedCourseCount = 0;
3714
        $closedVisibilityList = [
3715
            COURSE_VISIBILITY_CLOSED,
3716
            COURSE_VISIBILITY_HIDDEN,
3717
        ];
3718
3719
        foreach ($courseList as $course) {
3720
            // Checking session visibility
3721
            $sessionCourseVisibility = api_get_session_visibility(
3722
                $sessionId,
3723
                $course['real_id']
3724
            );
3725
3726
            $courseIsVisible = !in_array(
3727
                $course['visibility'],
3728
                $closedVisibilityList
3729
            );
3730
            if (false === $courseIsVisible || SESSION_INVISIBLE == $sessionCourseVisibility) {
3731
                $blockedCourseCount++;
3732
            }
3733
        }
3734
3735
        // If all courses are blocked then no show in the list.
3736
        if ($blockedCourseCount === count($courseList)) {
3737
            $visibility = SESSION_INVISIBLE;
3738
        } else {
3739
            $visibility = SESSION_VISIBLE;
3740
        }
3741
    }
3742
3743
    switch ($visibility) {
3744
        case SESSION_VISIBLE_READ_ONLY:
3745
        case SESSION_VISIBLE:
3746
        case SESSION_AVAILABLE:
3747
            return true;
3748
            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...
3749
        case SESSION_INVISIBLE:
3750
            return false;
3751
    }
3752
3753
    return false;
3754
}
3755
3756
/**
3757
 * Checks if a student can edit contents in a session depending
3758
 * on the session visibility.
3759
 *
3760
 * @param bool $tutor Whether to check if the user has the tutor role
3761
 * @param bool $coach Whether to check if the user has the coach role
3762
 *
3763
 * @return bool true: the user has the rights to edit, false: he does not
3764
 */
3765
function api_is_allowed_to_session_edit($tutor = false, $coach = false)
3766
{
3767
    if (api_is_allowed_to_edit($tutor, $coach)) {
3768
        // If I'm a teacher, I will return true in order to not affect the normal behaviour of Chamilo tools.
3769
        return true;
3770
    } else {
3771
        $sessionId = api_get_session_id();
3772
3773
        if (0 == $sessionId) {
3774
            // I'm not in a session so i will return true to not affect the normal behaviour of Chamilo tools.
3775
            return true;
3776
        } else {
3777
            // I'm in a session and I'm a student
3778
            // Get the session visibility
3779
            $session_visibility = api_get_session_visibility($sessionId);
3780
            // if 5 the session is still available
3781
            switch ($session_visibility) {
3782
                case SESSION_VISIBLE_READ_ONLY: // 1
3783
                    return false;
3784
                case SESSION_VISIBLE:           // 2
3785
                    return true;
3786
                case SESSION_INVISIBLE:         // 3
3787
                    return false;
3788
                case SESSION_AVAILABLE:         //5
3789
                    return true;
3790
            }
3791
        }
3792
    }
3793
3794
    return false;
3795
}
3796
3797
/**
3798
 * Checks whether the user is allowed in a specific tool for a specific action.
3799
 *
3800
 * @param string $tool   the tool we are checking if the user has a certain permission
3801
 * @param string $action the action we are checking (add, edit, delete, move, visibility)
3802
 *
3803
 * @return bool
3804
 *
3805
 * @author Patrick Cool <[email protected]>, Ghent University
3806
 * @author Julio Montoya
3807
 *
3808
 * @version 1.0
3809
 */
3810
function api_is_allowed($tool, $action, $task_id = 0)
3811
{
3812
    $_user = api_get_user_info();
3813
    $_course = api_get_course_info();
3814
3815
    if (api_is_course_admin()) {
3816
        return true;
3817
    }
3818
3819
    if (is_array($_course) and count($_course) > 0) {
3820
        require_once api_get_path(SYS_CODE_PATH).'permissions/permissions_functions.inc.php';
3821
3822
        // Getting the permissions of this user.
3823
        if (0 == $task_id) {
3824
            $user_permissions = get_permissions('user', $_user['user_id']);
3825
            $_SESSION['total_permissions'][$_course['code']] = $user_permissions;
3826
        }
3827
3828
        // Getting the permissions of the task.
3829
        if (0 != $task_id) {
3830
            $task_permissions = get_permissions('task', $task_id);
3831
            /* !!! */$_SESSION['total_permissions'][$_course['code']] = $task_permissions;
3832
        }
3833
    }
3834
3835
    // If the permissions are limited, we have to map the extended ones to the limited ones.
3836
    if ('limited' == api_get_setting('permissions')) {
3837
        if ('Visibility' == $action) {
3838
            $action = 'Edit';
3839
        }
3840
        if ('Move' == $action) {
3841
            $action = 'Edit';
3842
        }
3843
    }
3844
3845
    // The session that contains all the permissions already exists for this course
3846
    // so there is no need to requery everything.
3847
    //my_print_r($_SESSION['total_permissions'][$_course['code']][$tool]);
3848
    if (is_array($_SESSION['total_permissions'][$_course['code']][$tool])) {
3849
        if (in_array($action, $_SESSION['total_permissions'][$_course['code']][$tool])) {
3850
            return true;
3851
        } else {
3852
            return false;
3853
        }
3854
    }
3855
3856
    return false;
3857
}
3858
3859
/**
3860
 * Tells whether this user is an anonymous user.
3861
 *
3862
 * @param int  $user_id  User ID (optional, will take session ID if not provided)
3863
 * @param bool $db_check Whether to check in the database (true) or simply in
3864
 *                       the session (false) to see if the current user is the anonymous user
3865
 *
3866
 * @return bool true if this user is anonymous, false otherwise
3867
 */
3868
function api_is_anonymous($user_id = null, $db_check = false)
3869
{
3870
    /*if ($db_check) {
3871
        if (!isset($user_id)) {
3872
            $user_id = api_get_user_id();
3873
        }
3874
3875
        $info = api_get_user_info($user_id);
3876
3877
        if (6 == $info['status'] || 0 == $user_id || empty($info)) {
3878
            return true;
3879
        }
3880
    }*/
3881
3882
    return !Container::getAuthorizationChecker()->isGranted('IS_AUTHENTICATED_FULLY');
3883
}
3884
3885
/**
3886
 * Displays message "You are not allowed here..." and exits the entire script.
3887
 *
3888
 * @param bool   $print_headers Whether or not to print headers (default = false -> does not print them)
3889
 * @param string $message
3890
 * @param int    $responseCode
3891
 */
3892
function api_not_allowed(
3893
    $print_headers = false,
3894
    $message = null,
3895
    $responseCode = 0
3896
) {
3897
    throw new Exception('You are not allowed');
3898
}
3899
3900
/**
3901
 * Gets a UNIX timestamp from a database (MySQL) datetime format string.
3902
 *
3903
 * @param $last_post_datetime standard output date in a sql query
3904
 *
3905
 * @return int timestamp
3906
 *
3907
 * @author Toon Van Hoecke <[email protected]>
3908
 *
3909
 * @version October 2003
3910
 * @desc convert sql date to unix timestamp
3911
 */
3912
function convert_sql_date($last_post_datetime)
3913
{
3914
    [$last_post_date, $last_post_time] = explode(' ', $last_post_datetime);
3915
    [$year, $month, $day] = explode('-', $last_post_date);
3916
    [$hour, $min, $sec] = explode(':', $last_post_time);
3917
3918
    return mktime((int) $hour, (int) $min, (int) $sec, (int) $month, (int) $day, (int) $year);
3919
}
3920
3921
/**
3922
 * Displays a combo box so the user can select his/her preferred language.
3923
 *
3924
 * @param string The desired name= value for the select
3925
 * @param bool Whether we use the JQuery Chozen library or not
3926
 * (in some cases, like the indexing language picker, it can alter the presentation)
3927
 *
3928
 * @deprecated
3929
 *
3930
 * @return string
3931
 */
3932
function api_get_languages_combo($name = 'language')
3933
{
3934
    $ret = '';
3935
    $platformLanguage = api_get_setting('platformLanguage');
3936
3937
    // Retrieve a complete list of all the languages.
3938
    $language_list = api_get_languages();
3939
3940
    if (count($language_list) < 2) {
3941
        return $ret;
3942
    }
3943
3944
    // The the current language of the user so that his/her language occurs as selected in the dropdown menu.
3945
    if (isset($_SESSION['user_language_choice'])) {
3946
        $default = $_SESSION['user_language_choice'];
3947
    } else {
3948
        $default = $platformLanguage;
3949
    }
3950
3951
    $ret .= '<select name="'.$name.'" id="language_chosen" class="selectpicker show-tick form-control">';
3952
    foreach ($language_list as $key => $value) {
3953
        if ($key == $default) {
3954
            $selected = ' selected="selected"';
3955
        } else {
3956
            $selected = '';
3957
        }
3958
        $ret .= sprintf('<option value=%s" %s>%s</option>', $key, $selected, $value);
3959
    }
3960
    $ret .= '</select>';
3961
3962
    return $ret;
3963
}
3964
3965
/**
3966
 * Displays a form (drop down menu) so the user can select his/her preferred language.
3967
 * The form works with or without javascript.
3968
 *
3969
 * @param  bool Hide form if only one language available (defaults to false = show the box anyway)
3970
 * @param bool $showAsButton
3971
 *
3972
 * @return string|null Display the box directly
3973
 */
3974
function api_display_language_form($hide_if_no_choice = false, $showAsButton = false)
3975
{
3976
    // Retrieve a complete list of all the languages.
3977
    $language_list = api_get_languages();
3978
    if (count($language_list['name']) <= 1 && $hide_if_no_choice) {
3979
        return; //don't show any form
3980
    }
3981
3982
    // The the current language of the user so that his/her language occurs as selected in the dropdown menu.
3983
    if (isset($_SESSION['user_language_choice'])) {
3984
        $user_selected_language = $_SESSION['user_language_choice'];
3985
    }
3986
    if (empty($user_selected_language)) {
3987
        $user_selected_language = api_get_setting('platformLanguage');
3988
    }
3989
3990
    $currentLanguageId = api_get_language_id($user_selected_language);
3991
    $currentLanguageInfo = api_get_language_info($currentLanguageId);
3992
    $countryCode = languageToCountryIsoCode($currentLanguageInfo['isocode']);
3993
    $url = api_get_self();
3994
    if ($showAsButton) {
3995
        $html = '<div class="btn-group">
3996
              <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
3997
                <span class="flag-icon flag-icon-'.$countryCode.'"></span>
3998
                '.$currentLanguageInfo['original_name'].'
3999
                <span class="caret">
4000
                </span>
4001
              </button>';
4002
    } else {
4003
        $html = '
4004
            <a href="'.$url.'" class="dropdown-toggle" data-toggle="dropdown" role="button">
4005
                <span class="flag-icon flag-icon-'.$countryCode.'"></span>
4006
                '.$currentLanguageInfo['original_name'].'
4007
                <span class="caret"></span>
4008
            </a>
4009
            ';
4010
    }
4011
4012
    $html .= '<ul class="dropdown-menu" role="menu">';
4013
    foreach ($language_list['all'] as $key => $data) {
4014
        $urlLink = $url.'?language='.$data['english_name'];
4015
        $html .= '<li><a href="'.$urlLink.'"><span class="flag-icon flag-icon-'.languageToCountryIsoCode($data['isocode']).'"></span> '.$data['original_name'].'</a></li>';
4016
    }
4017
    $html .= '</ul>';
4018
4019
    if ($showAsButton) {
4020
        $html .= '</div>';
4021
    }
4022
4023
    return $html;
4024
}
4025
4026
/**
4027
 * @param string $languageIsoCode
4028
 *
4029
 * @return string
4030
 */
4031
function languageToCountryIsoCode($languageIsoCode)
4032
{
4033
    $allow = api_get_configuration_value('language_flags_by_country');
4034
4035
    // @todo save in DB
4036
    switch ($languageIsoCode) {
4037
        case 'ar':
4038
            $country = 'ae';
4039
            break;
4040
        case 'bs':
4041
            $country = 'ba';
4042
            break;
4043
        case 'ca':
4044
            $country = 'es';
4045
            if ($allow) {
4046
                $country = 'catalan';
4047
            }
4048
            break;
4049
        case 'cs':
4050
            $country = 'cz';
4051
            break;
4052
        case 'da':
4053
            $country = 'dk';
4054
            break;
4055
        case 'el':
4056
            $country = 'ae';
4057
            break;
4058
        case 'en':
4059
            $country = 'gb';
4060
            break;
4061
        case 'eu': // Euskera
4062
            $country = 'es';
4063
            if ($allow) {
4064
                $country = 'basque';
4065
            }
4066
            break;
4067
        case 'gl': // galego
4068
            $country = 'es';
4069
            if ($allow) {
4070
                $country = 'galician';
4071
            }
4072
            break;
4073
        case 'he':
4074
            $country = 'il';
4075
            break;
4076
        case 'ja':
4077
            $country = 'jp';
4078
            break;
4079
        case 'ka':
4080
            $country = 'ge';
4081
            break;
4082
        case 'ko':
4083
            $country = 'kr';
4084
            break;
4085
        case 'ms':
4086
            $country = 'my';
4087
            break;
4088
        case 'pt-BR':
4089
            $country = 'br';
4090
            break;
4091
        case 'qu':
4092
            $country = 'pe';
4093
            break;
4094
        case 'sl':
4095
            $country = 'si';
4096
            break;
4097
        case 'sv':
4098
            $country = 'se';
4099
            break;
4100
        case 'uk': // Ukraine
4101
            $country = 'ua';
4102
            break;
4103
        case 'zh-TW':
4104
        case 'zh':
4105
            $country = 'cn';
4106
            break;
4107
        default:
4108
            $country = $languageIsoCode;
4109
            break;
4110
    }
4111
    $country = strtolower($country);
4112
4113
    return $country;
4114
}
4115
4116
/**
4117
 * Returns a list of all the languages that are made available by the admin.
4118
 *
4119
 * @return array An array with all languages. Structure of the array is
4120
 *               array['name'] = An array with the name of every language
4121
 *               array['folder'] = An array with the corresponding names of the language-folders in the filesystem
4122
 */
4123
function api_get_languages()
4124
{
4125
    $table = Database::get_main_table(TABLE_MAIN_LANGUAGE);
4126
    $sql = "SELECT * FROM $table WHERE available='1'
4127
            ORDER BY original_name ASC";
4128
    $result = Database::query($sql);
4129
    $languages = [];
4130
    while ($row = Database::fetch_array($result, 'ASSOC')) {
4131
        $languages[$row['isocode']] = $row['original_name'];
4132
    }
4133
4134
    return $languages;
4135
}
4136
4137
/**
4138
 * Returns a list of all the languages that are made available by the admin.
4139
 *
4140
 * @return array
4141
 */
4142
function api_get_languages_to_array()
4143
{
4144
    $tbl_language = Database::get_main_table(TABLE_MAIN_LANGUAGE);
4145
    $sql = "SELECT * FROM $tbl_language WHERE available='1' ORDER BY original_name ASC";
4146
    $result = Database::query($sql);
4147
    $languages = [];
4148
    while ($row = Database::fetch_array($result)) {
4149
        $languages[$row['english_name']] = $row['original_name'];
4150
    }
4151
4152
    return $languages;
4153
}
4154
4155
/**
4156
 * Returns the id (the database id) of a language.
4157
 *
4158
 * @param   string  language name (the corresponding name of the language-folder in the filesystem)
4159
 *
4160
 * @return int id of the language
4161
 */
4162
function api_get_language_id($language)
4163
{
4164
    $tbl_language = Database::get_main_table(TABLE_MAIN_LANGUAGE);
4165
    if (empty($language)) {
4166
        return null;
4167
    }
4168
    $language = Database::escape_string($language);
4169
    $sql = "SELECT id FROM $tbl_language
4170
            WHERE english_name = '$language' LIMIT 1";
4171
    $result = Database::query($sql);
4172
    $row = Database::fetch_array($result);
4173
4174
    return $row['id'];
4175
}
4176
4177
/**
4178
 * Get the language information by its id.
4179
 *
4180
 * @param int $languageId
4181
 *
4182
 * @throws Exception
4183
 *
4184
 * @return array
4185
 */
4186
function api_get_language_info($languageId)
4187
{
4188
    if (empty($languageId)) {
4189
        return [];
4190
    }
4191
4192
    $language = Database::getManager()->find(Language::class, $languageId);
4193
4194
    if (!$language) {
4195
        return [];
4196
    }
4197
4198
    return [
4199
        'id' => $language->getId(),
4200
        'original_name' => $language->getOriginalName(),
4201
        'english_name' => $language->getEnglishName(),
4202
        'isocode' => $language->getIsocode(),
4203
        'available' => $language->getAvailable(),
4204
        'parent_id' => $language->getParent() ? $language->getParent()->getId() : null,
4205
    ];
4206
}
4207
4208
/**
4209
 * @param string $code
4210
 *
4211
 * @return Language
4212
 */
4213
function api_get_language_from_iso($code)
4214
{
4215
    $em = Database::getManager();
4216
4217
    return $em->getRepository(Language::class)->findOneBy(['isocode' => $code]);
4218
}
4219
4220
/**
4221
 * Returns the name of the visual (CSS) theme to be applied on the current page.
4222
 * The returned name depends on the platform, course or user -wide settings.
4223
 *
4224
 * @return string The visual theme's name, it is the name of a folder inside web/css/themes
4225
 */
4226
function api_get_visual_theme()
4227
{
4228
    static $visual_theme;
4229
    if (!isset($visual_theme)) {
4230
        // Get style directly from DB
4231
        /*$styleFromDatabase = api_get_settings_params_simple(
4232
            [
4233
                'variable = ? AND access_url = ?' => [
4234
                    'stylesheets',
4235
                    api_get_current_access_url_id(),
4236
                ],
4237
            ]
4238
        );
4239
4240
        if ($styleFromDatabase) {
4241
            $platform_theme = $styleFromDatabase['selected_value'];
4242
        } else {
4243
            $platform_theme = api_get_setting('stylesheets');
4244
        }*/
4245
        $platform_theme = api_get_setting('stylesheets');
4246
4247
        // Platform's theme.
4248
        $visual_theme = $platform_theme;
4249
        if ('true' == api_get_setting('user_selected_theme')) {
4250
            $user_info = api_get_user_info();
4251
            if (isset($user_info['theme'])) {
4252
                $user_theme = $user_info['theme'];
4253
4254
                if (!empty($user_theme)) {
4255
                    $visual_theme = $user_theme;
4256
                    // User's theme.
4257
                }
4258
            }
4259
        }
4260
4261
        $course_id = api_get_course_id();
4262
        if (!empty($course_id)) {
4263
            if ('true' == api_get_setting('allow_course_theme')) {
4264
                $course_theme = api_get_course_setting('course_theme', $course_id);
4265
4266
                if (!empty($course_theme) && -1 != $course_theme) {
4267
                    if (!empty($course_theme)) {
4268
                        // Course's theme.
4269
                        $visual_theme = $course_theme;
4270
                    }
4271
                }
4272
4273
                $allow_lp_theme = api_get_course_setting('allow_learning_path_theme');
4274
                if (1 == $allow_lp_theme) {
4275
                    /*global $lp_theme_css, $lp_theme_config;
4276
                    // These variables come from the file lp_controller.php.
4277
                    if (!$lp_theme_config) {
4278
                        if (!empty($lp_theme_css)) {
4279
                            // LP's theme.
4280
                            $visual_theme = $lp_theme_css;
4281
                        }
4282
                    }*/
4283
                }
4284
            }
4285
        }
4286
4287
        if (empty($visual_theme)) {
4288
            $visual_theme = 'chamilo';
4289
        }
4290
4291
        /*global $lp_theme_log;
4292
        if ($lp_theme_log) {
4293
            $visual_theme = $platform_theme;
4294
        }*/
4295
    }
4296
4297
    return $visual_theme;
4298
}
4299
4300
/**
4301
 * Returns a list of CSS themes currently available in the CSS folder
4302
 * The folder must have a default.css file.
4303
 *
4304
 * @param bool $getOnlyThemeFromVirtualInstance Used by the vchamilo plugin
4305
 *
4306
 * @return array list of themes directories from the css folder
4307
 *               Note: Directory names (names of themes) in the file system should contain ASCII-characters only
4308
 */
4309
function api_get_themes($getOnlyThemeFromVirtualInstance = false)
4310
{
4311
    // This configuration value is set by the vchamilo plugin
4312
    $virtualTheme = api_get_configuration_value('virtual_css_theme_folder');
4313
4314
    $readCssFolder = function ($dir) use ($virtualTheme) {
4315
        $finder = new Finder();
4316
        $themes = $finder->directories()->in($dir)->depth(0)->sortByName();
4317
        $list = [];
4318
        /** @var Symfony\Component\Finder\SplFileInfo $theme */
4319
        foreach ($themes as $theme) {
4320
            $folder = $theme->getFilename();
4321
            // A theme folder is consider if there's a default.css file
4322
            if (!file_exists($theme->getPathname().'/default.css')) {
4323
                continue;
4324
            }
4325
            $name = ucwords(str_replace('_', ' ', $folder));
4326
            if ($folder == $virtualTheme) {
4327
                continue;
4328
            }
4329
            $list[$folder] = $name;
4330
        }
4331
4332
        return $list;
4333
    };
4334
4335
    $dir = api_get_path(SYS_CSS_PATH).'themes/';
4336
    $list = $readCssFolder($dir);
4337
4338
    if (!empty($virtualTheme)) {
4339
        $newList = $readCssFolder($dir.'/'.$virtualTheme);
4340
        if ($getOnlyThemeFromVirtualInstance) {
4341
            return $newList;
4342
        }
4343
        $list = $list + $newList;
4344
        asort($list);
4345
    }
4346
4347
    return $list;
4348
}
4349
4350
/**
4351
 * Find the largest sort value in a given user_course_category
4352
 * This function is used when we are moving a course to a different category
4353
 * and also when a user subscribes to courses (the new course is added at the end of the main category.
4354
 *
4355
 * @param int $courseCategoryId the id of the user_course_category
4356
 * @param int $userId
4357
 *
4358
 * @return int the value of the highest sort of the user_course_category
4359
 */
4360
function api_max_sort_value($courseCategoryId, $userId)
4361
{
4362
    $user = api_get_user_entity($userId);
4363
    $userCourseCategory = Database::getManager()->getRepository(UserCourseCategory::class)->find($courseCategoryId);
4364
4365
    return null === $user ? 0 : $user->getMaxSortValue($userCourseCategory);
4366
}
4367
4368
/**
4369
 * Transforms a number of seconds in hh:mm:ss format.
4370
 *
4371
 * @author Julian Prud'homme
4372
 *
4373
 * @param int    $seconds      number of seconds
4374
 * @param string $space
4375
 * @param bool   $showSeconds
4376
 * @param bool   $roundMinutes
4377
 *
4378
 * @return string the formatted time
4379
 */
4380
function api_time_to_hms($seconds, $space = ':', $showSeconds = true, $roundMinutes = false)
4381
{
4382
    // $seconds = -1 means that we have wrong data in the db.
4383
    if (-1 == $seconds) {
4384
        return
4385
            get_lang('Unknown').
4386
            Display::return_icon(
4387
                'info2.gif',
4388
                get_lang('The datas about this user were registered when the calculation of time spent on the platform wasn\'t possible.'),
4389
                ['align' => 'absmiddle', 'hspace' => '3px']
4390
            );
4391
    }
4392
4393
    // How many hours ?
4394
    $hours = floor($seconds / 3600);
4395
4396
    // How many minutes ?
4397
    $min = floor(($seconds - ($hours * 3600)) / 60);
4398
4399
    if ($roundMinutes) {
4400
        if ($min >= 45) {
4401
            $min = 45;
4402
        }
4403
4404
        if ($min >= 30 && $min <= 44) {
4405
            $min = 30;
4406
        }
4407
4408
        if ($min >= 15 && $min <= 29) {
4409
            $min = 15;
4410
        }
4411
4412
        if ($min >= 0 && $min <= 14) {
4413
            $min = 0;
4414
        }
4415
    }
4416
4417
    // How many seconds
4418
    $sec = floor($seconds - ($hours * 3600) - ($min * 60));
4419
4420
    if ($hours < 10) {
4421
        $hours = "0$hours";
4422
    }
4423
4424
    if ($sec < 10) {
4425
        $sec = "0$sec";
4426
    }
4427
4428
    if ($min < 10) {
4429
        $min = "0$min";
4430
    }
4431
4432
    $seconds = '';
4433
    if ($showSeconds) {
4434
        $seconds = $space.$sec;
4435
    }
4436
4437
    return $hours.$space.$min.$seconds;
4438
}
4439
4440
/* FILE SYSTEM RELATED FUNCTIONS */
4441
4442
/**
4443
 * Returns the permissions to be assigned to every newly created directory by the web-server.
4444
 * The return value is based on the platform administrator's setting
4445
 * "Administration > Configuration settings > Security > Permissions for new directories".
4446
 *
4447
 * @return int returns the permissions in the format "Owner-Group-Others, Read-Write-Execute", as an integer value
4448
 */
4449
function api_get_permissions_for_new_directories()
4450
{
4451
    static $permissions;
4452
    if (!isset($permissions)) {
4453
        $permissions = trim(api_get_setting('permissions_for_new_directories'));
4454
        // The default value 0777 is according to that in the platform administration panel after fresh system installation.
4455
        $permissions = octdec(!empty($permissions) ? $permissions : '0777');
4456
    }
4457
4458
    return $permissions;
4459
}
4460
4461
/**
4462
 * Returns the permissions to be assigned to every newly created directory by the web-server.
4463
 * The return value is based on the platform administrator's setting
4464
 * "Administration > Configuration settings > Security > Permissions for new files".
4465
 *
4466
 * @return int returns the permissions in the format
4467
 *             "Owner-Group-Others, Read-Write-Execute", as an integer value
4468
 */
4469
function api_get_permissions_for_new_files()
4470
{
4471
    static $permissions;
4472
    if (!isset($permissions)) {
4473
        $permissions = trim(api_get_setting('permissions_for_new_files'));
4474
        // The default value 0666 is according to that in the platform
4475
        // administration panel after fresh system installation.
4476
        $permissions = octdec(!empty($permissions) ? $permissions : '0666');
4477
    }
4478
4479
    return $permissions;
4480
}
4481
4482
/**
4483
 * Deletes a file, or a folder and its contents.
4484
 *
4485
 * @author      Aidan Lister <[email protected]>
4486
 *
4487
 * @version     1.0.3
4488
 *
4489
 * @param string $dirname Directory to delete
4490
 * @param       bool     Deletes only the content or not
4491
 * @param bool $strict if one folder/file fails stop the loop
4492
 *
4493
 * @return bool Returns TRUE on success, FALSE on failure
4494
 *
4495
 * @see http://aidanlister.com/2004/04/recursively-deleting-a-folder-in-php/
4496
 *
4497
 * @author      Yannick Warnier, adaptation for the Chamilo LMS, April, 2008
4498
 * @author      Ivan Tcholakov, a sanity check about Directory class creation has been added, September, 2009
4499
 */
4500
function rmdirr($dirname, $delete_only_content_in_folder = false, $strict = false)
4501
{
4502
    $res = true;
4503
    // A sanity check.
4504
    if (!file_exists($dirname)) {
4505
        return false;
4506
    }
4507
    $php_errormsg = '';
4508
    // Simple delete for a file.
4509
    if (is_file($dirname) || is_link($dirname)) {
4510
        $res = unlink($dirname);
4511
        if (false === $res) {
4512
            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);
4513
        }
4514
4515
        return $res;
4516
    }
4517
4518
    // Loop through the folder.
4519
    $dir = dir($dirname);
4520
    // A sanity check.
4521
    $is_object_dir = is_object($dir);
4522
    if ($is_object_dir) {
4523
        while (false !== $entry = $dir->read()) {
4524
            // Skip pointers.
4525
            if ('.' == $entry || '..' == $entry) {
4526
                continue;
4527
            }
4528
4529
            // Recurse.
4530
            if ($strict) {
4531
                $result = rmdirr("$dirname/$entry");
4532
                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...
4533
                    $res = false;
4534
                    break;
4535
                }
4536
            } else {
4537
                rmdirr("$dirname/$entry");
4538
            }
4539
        }
4540
    }
4541
4542
    // Clean up.
4543
    if ($is_object_dir) {
4544
        $dir->close();
4545
    }
4546
4547
    if (false == $delete_only_content_in_folder) {
4548
        $res = rmdir($dirname);
4549
        if (false === $res) {
4550
            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);
4551
        }
4552
    }
4553
4554
    return $res;
4555
}
4556
4557
// TODO: This function is to be simplified. File access modes to be implemented.
4558
/**
4559
 * function adapted from a php.net comment
4560
 * copy recursively a folder.
4561
 *
4562
 * @param the source folder
4563
 * @param the dest folder
4564
 * @param an array of excluded file_name (without extension)
4565
 * @param copied_files the returned array of copied files
4566
 * @param string $source
4567
 * @param string $dest
4568
 */
4569
function copyr($source, $dest, $exclude = [], $copied_files = [])
4570
{
4571
    if (empty($dest)) {
4572
        return false;
4573
    }
4574
    // Simple copy for a file
4575
    if (is_file($source)) {
4576
        $path_info = pathinfo($source);
4577
        if (!in_array($path_info['filename'], $exclude)) {
4578
            copy($source, $dest);
4579
        }
4580
4581
        return true;
4582
    } elseif (!is_dir($source)) {
4583
        //then source is not a dir nor a file, return
4584
        return false;
4585
    }
4586
4587
    // Make destination directory.
4588
    if (!is_dir($dest)) {
4589
        mkdir($dest, api_get_permissions_for_new_directories());
4590
    }
4591
4592
    // Loop through the folder.
4593
    $dir = dir($source);
4594
    while (false !== $entry = $dir->read()) {
4595
        // Skip pointers
4596
        if ('.' == $entry || '..' == $entry) {
4597
            continue;
4598
        }
4599
4600
        // Deep copy directories.
4601
        if ($dest !== "$source/$entry") {
4602
            $files = copyr("$source/$entry", "$dest/$entry", $exclude, $copied_files);
4603
        }
4604
    }
4605
    // Clean up.
4606
    $dir->close();
4607
4608
    return true;
4609
}
4610
4611
/**
4612
 * @todo: Using DIRECTORY_SEPARATOR is not recommended, this is an obsolete approach.
4613
 * Documentation header to be added here.
4614
 *
4615
 * @param string $pathname
4616
 * @param string $base_path_document
4617
 * @param int    $session_id
4618
 *
4619
 * @return mixed True if directory already exists, false if a file already exists at
4620
 *               the destination and null if everything goes according to plan
4621
 */
4622
function copy_folder_course_session(
4623
    $pathname,
4624
    $base_path_document,
4625
    $session_id,
4626
    $course_info,
4627
    $document,
4628
    $source_course_id
4629
) {
4630
    $table = Database::get_course_table(TABLE_DOCUMENT);
4631
    $session_id = intval($session_id);
4632
    $source_course_id = intval($source_course_id);
4633
4634
    // Check whether directory already exists.
4635
    if (is_dir($pathname) || empty($pathname)) {
4636
        return true;
4637
    }
4638
4639
    // Ensure that a file with the same name does not already exist.
4640
    if (is_file($pathname)) {
4641
        trigger_error('copy_folder_course_session(): File exists', E_USER_WARNING);
4642
4643
        return false;
4644
    }
4645
4646
    $course_id = $course_info['real_id'];
4647
    $folders = explode(DIRECTORY_SEPARATOR, str_replace($base_path_document.DIRECTORY_SEPARATOR, '', $pathname));
4648
    $new_pathname = $base_path_document;
4649
    $path = '';
4650
4651
    foreach ($folders as $folder) {
4652
        $new_pathname .= DIRECTORY_SEPARATOR.$folder;
4653
        $path .= DIRECTORY_SEPARATOR.$folder;
4654
4655
        if (!file_exists($new_pathname)) {
4656
            $path = Database::escape_string($path);
4657
4658
            $sql = "SELECT * FROM $table
4659
                    WHERE
4660
                        c_id = $source_course_id AND
4661
                        path = '$path' AND
4662
                        filetype = 'folder' AND
4663
                        session_id = '$session_id'";
4664
            $rs1 = Database::query($sql);
4665
            $num_rows = Database::num_rows($rs1);
4666
4667
            if (0 == $num_rows) {
4668
                mkdir($new_pathname, api_get_permissions_for_new_directories());
4669
4670
                // Insert new folder with destination session_id.
4671
                $params = [
4672
                    'c_id' => $course_id,
4673
                    'path' => $path,
4674
                    'comment' => $document->comment,
4675
                    'title' => basename($new_pathname),
4676
                    'filetype' => 'folder',
4677
                    'size' => '0',
4678
                    'session_id' => $session_id,
4679
                ];
4680
                Database::insert($table, $params);
4681
            }
4682
        }
4683
    } // en foreach
4684
}
4685
4686
// TODO: chmodr() is a better name. Some corrections are needed. Documentation header to be added here.
4687
/**
4688
 * @param string $path
4689
 */
4690
function api_chmod_R($path, $filemode)
4691
{
4692
    if (!is_dir($path)) {
4693
        return chmod($path, $filemode);
4694
    }
4695
4696
    $handler = opendir($path);
4697
    while ($file = readdir($handler)) {
4698
        if ('.' != $file && '..' != $file) {
4699
            $fullpath = "$path/$file";
4700
            if (!is_dir($fullpath)) {
4701
                if (!chmod($fullpath, $filemode)) {
4702
                    return false;
4703
                }
4704
            } else {
4705
                if (!api_chmod_R($fullpath, $filemode)) {
4706
                    return false;
4707
                }
4708
            }
4709
        }
4710
    }
4711
4712
    closedir($handler);
4713
4714
    return chmod($path, $filemode);
4715
}
4716
4717
// TODO: Where the following function has been copy/pased from? There is no information about author and license. Style, coding conventions...
4718
/**
4719
 * Parse info file format. (e.g: file.info).
4720
 *
4721
 * Files should use an ini-like format to specify values.
4722
 * White-space generally doesn't matter, except inside values.
4723
 * e.g.
4724
 *
4725
 * @verbatim
4726
 *   key = value
4727
 *   key = "value"
4728
 *   key = 'value'
4729
 *   key = "multi-line
4730
 *
4731
 *   value"
4732
 *   key = 'multi-line
4733
 *
4734
 *   value'
4735
 *   key
4736
 *   =
4737
 *   'value'
4738
 * @endverbatim
4739
 *
4740
 * Arrays are created using a GET-like syntax:
4741
 *
4742
 * @verbatim
4743
 *   key[] = "numeric array"
4744
 *   key[index] = "associative array"
4745
 *   key[index][] = "nested numeric array"
4746
 *   key[index][index] = "nested associative array"
4747
 * @endverbatim
4748
 *
4749
 * PHP constants are substituted in, but only when used as the entire value:
4750
 *
4751
 * Comments should start with a semi-colon at the beginning of a line.
4752
 *
4753
 * This function is NOT for placing arbitrary module-specific settings. Use
4754
 * variable_get() and variable_set() for that.
4755
 *
4756
 * Information stored in the module.info file:
4757
 * - name: The real name of the module for display purposes.
4758
 * - description: A brief description of the module.
4759
 * - dependencies: An array of shortnames of other modules this module depends on.
4760
 * - package: The name of the package of modules this module belongs to.
4761
 *
4762
 * Example of .info file:
4763
 * <code>
4764
 * @verbatim
4765
 *   name = Forum
4766
 *   description = Enables threaded discussions about general topics.
4767
 *   dependencies[] = taxonomy
4768
 *   dependencies[] = comment
4769
 *   package = Core - optional
4770
 *   version = VERSION
4771
 * @endverbatim
4772
 * </code>
4773
 *
4774
 * @param string $filename
4775
 *                         The file we are parsing. Accepts file with relative or absolute path.
4776
 *
4777
 * @return
4778
 *   The info array
4779
 */
4780
function api_parse_info_file($filename)
4781
{
4782
    $info = [];
4783
4784
    if (!file_exists($filename)) {
4785
        return $info;
4786
    }
4787
4788
    $data = file_get_contents($filename);
4789
    if (preg_match_all('
4790
        @^\s*                           # Start at the beginning of a line, ignoring leading whitespace
4791
        ((?:
4792
          [^=;\[\]]|                    # Key names cannot contain equal signs, semi-colons or square brackets,
4793
          \[[^\[\]]*\]                  # unless they are balanced and not nested
4794
        )+?)
4795
        \s*=\s*                         # Key/value pairs are separated by equal signs (ignoring white-space)
4796
        (?:
4797
          ("(?:[^"]|(?<=\\\\)")*")|     # Double-quoted string, which may contain slash-escaped quotes/slashes
4798
          (\'(?:[^\']|(?<=\\\\)\')*\')| # Single-quoted string, which may contain slash-escaped quotes/slashes
4799
          ([^\r\n]*?)                   # Non-quoted string
4800
        )\s*$                           # Stop at the next end of a line, ignoring trailing whitespace
4801
        @msx', $data, $matches, PREG_SET_ORDER)) {
4802
        $key = $value1 = $value2 = $value3 = '';
4803
        foreach ($matches as $match) {
4804
            // Fetch the key and value string.
4805
            $i = 0;
4806
            foreach (['key', 'value1', 'value2', 'value3'] as $var) {
4807
                $$var = isset($match[++$i]) ? $match[$i] : '';
4808
            }
4809
            $value = stripslashes(substr($value1, 1, -1)).stripslashes(substr($value2, 1, -1)).$value3;
4810
4811
            // Parse array syntax.
4812
            $keys = preg_split('/\]?\[/', rtrim($key, ']'));
4813
            $last = array_pop($keys);
4814
            $parent = &$info;
4815
4816
            // Create nested arrays.
4817
            foreach ($keys as $key) {
4818
                if ('' == $key) {
4819
                    $key = count($parent);
4820
                }
4821
                if (!isset($parent[$key]) || !is_array($parent[$key])) {
4822
                    $parent[$key] = [];
4823
                }
4824
                $parent = &$parent[$key];
4825
            }
4826
4827
            // Handle PHP constants.
4828
            if (defined($value)) {
4829
                $value = constant($value);
4830
            }
4831
4832
            // Insert actual value.
4833
            if ('' == $last) {
4834
                $last = count($parent);
4835
            }
4836
            $parent[$last] = $value;
4837
        }
4838
    }
4839
4840
    return $info;
4841
}
4842
4843
/**
4844
 * Gets Chamilo version from the configuration files.
4845
 *
4846
 * @return string A string of type "1.8.4", or an empty string if the version could not be found
4847
 */
4848
function api_get_version()
4849
{
4850
    return (string) api_get_configuration_value('system_version');
4851
}
4852
4853
/**
4854
 * Gets the software name (the name/brand of the Chamilo-based customized system).
4855
 *
4856
 * @return string
4857
 */
4858
function api_get_software_name()
4859
{
4860
    $name = api_get_configuration_value('software_name');
4861
    if (!empty($name)) {
4862
        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...
4863
    } else {
4864
        return 'Chamilo';
4865
    }
4866
}
4867
4868
function api_get_status_list()
4869
{
4870
    $list = [];
4871
    // Table of status
4872
    $list[COURSEMANAGER] = 'teacher'; // 1
4873
    $list[SESSIONADMIN] = 'session_admin'; // 3
4874
    $list[DRH] = 'drh'; // 4
4875
    $list[STUDENT] = 'user'; // 5
4876
    $list[ANONYMOUS] = 'anonymous'; // 6
4877
    $list[INVITEE] = 'invited'; // 20
4878
4879
    return $list;
4880
}
4881
4882
/**
4883
 * Checks whether status given in parameter exists in the platform.
4884
 *
4885
 * @param mixed the status (can be either int either string)
4886
 *
4887
 * @return bool if the status exists, else returns false
4888
 */
4889
function api_status_exists($status_asked)
4890
{
4891
    $list = api_get_status_list();
4892
4893
    return in_array($status_asked, $list) ? true : isset($list[$status_asked]);
4894
}
4895
4896
/**
4897
 * Checks whether status given in parameter exists in the platform. The function
4898
 * returns the status ID or false if it does not exist, but given the fact there
4899
 * is no "0" status, the return value can be checked against
4900
 * if(api_status_key()) to know if it exists.
4901
 *
4902
 * @param   mixed   The status (can be either int or string)
4903
 *
4904
 * @return mixed Status ID if exists, false otherwise
4905
 */
4906
function api_status_key($status)
4907
{
4908
    $list = api_get_status_list();
4909
4910
    return isset($list[$status]) ? $status : array_search($status, $list);
4911
}
4912
4913
/**
4914
 * Gets the status langvars list.
4915
 *
4916
 * @return string[] the list of status with their translations
4917
 */
4918
function api_get_status_langvars()
4919
{
4920
    return [
4921
        COURSEMANAGER => get_lang('Teacher'),
4922
        SESSIONADMIN => get_lang('SessionsAdmin'),
4923
        DRH => get_lang('Human Resources Manager'),
4924
        STUDENT => get_lang('Learner'),
4925
        ANONYMOUS => get_lang('Anonymous'),
4926
        STUDENT_BOSS => get_lang('RoleStudentBoss'),
4927
        INVITEE => get_lang('Invited'),
4928
    ];
4929
}
4930
4931
/**
4932
 * The function that retrieves all the possible settings for a certain config setting.
4933
 *
4934
 * @author Patrick Cool <[email protected]>, Ghent University
4935
 */
4936
function api_get_settings_options($var)
4937
{
4938
    $table_settings_options = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
4939
    $var = Database::escape_string($var);
4940
    $sql = "SELECT * FROM $table_settings_options
4941
            WHERE variable = '$var'
4942
            ORDER BY id";
4943
    $result = Database::query($sql);
4944
    $settings_options_array = [];
4945
    while ($row = Database::fetch_array($result, 'ASSOC')) {
4946
        $settings_options_array[] = $row;
4947
    }
4948
4949
    return $settings_options_array;
4950
}
4951
4952
/**
4953
 * @param array $params
4954
 */
4955
function api_set_setting_option($params)
4956
{
4957
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
4958
    if (empty($params['id'])) {
4959
        Database::insert($table, $params);
4960
    } else {
4961
        Database::update($table, $params, ['id = ? ' => $params['id']]);
4962
    }
4963
}
4964
4965
/**
4966
 * @param array $params
4967
 */
4968
function api_set_setting_simple($params)
4969
{
4970
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
4971
    $url_id = api_get_current_access_url_id();
4972
4973
    if (empty($params['id'])) {
4974
        $params['access_url'] = $url_id;
4975
        Database::insert($table, $params);
4976
    } else {
4977
        Database::update($table, $params, ['id = ? ' => [$params['id']]]);
4978
    }
4979
}
4980
4981
/**
4982
 * @param int $id
4983
 */
4984
function api_delete_setting_option($id)
4985
{
4986
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
4987
    if (!empty($id)) {
4988
        Database::delete($table, ['id = ? ' => $id]);
4989
    }
4990
}
4991
4992
/**
4993
 * Sets a platform configuration setting to a given value.
4994
 *
4995
 * @param string    The variable we want to update
4996
 * @param string    The value we want to record
4997
 * @param string    The sub-variable if any (in most cases, this will remain null)
4998
 * @param string    The category if any (in most cases, this will remain null)
4999
 * @param int       The access_url for which this parameter is valid
5000
 * @param string $cat
5001
 *
5002
 * @return bool|null
5003
 */
5004
function api_set_setting($var, $value, $subvar = null, $cat = null, $access_url = 1)
5005
{
5006
    if (empty($var)) {
5007
        return false;
5008
    }
5009
    $t_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5010
    $var = Database::escape_string($var);
5011
    $value = Database::escape_string($value);
5012
    $access_url = (int) $access_url;
5013
    if (empty($access_url)) {
5014
        $access_url = 1;
5015
    }
5016
    $select = "SELECT id FROM $t_settings WHERE variable = '$var' ";
5017
    if (!empty($subvar)) {
5018
        $subvar = Database::escape_string($subvar);
5019
        $select .= " AND subkey = '$subvar'";
5020
    }
5021
    if (!empty($cat)) {
5022
        $cat = Database::escape_string($cat);
5023
        $select .= " AND category = '$cat'";
5024
    }
5025
    if ($access_url > 1) {
5026
        $select .= " AND access_url = $access_url";
5027
    } else {
5028
        $select .= " AND access_url = 1 ";
5029
    }
5030
5031
    $res = Database::query($select);
5032
    if (Database::num_rows($res) > 0) {
5033
        // Found item for this access_url.
5034
        $row = Database::fetch_array($res);
5035
        $sql = "UPDATE $t_settings SET selected_value = '$value'
5036
                WHERE id = ".$row['id'];
5037
        Database::query($sql);
5038
    } else {
5039
        // Item not found for this access_url, we have to check if it exist with access_url = 1
5040
        $select = "SELECT * FROM $t_settings
5041
                   WHERE variable = '$var' AND access_url = 1 ";
5042
        // Just in case
5043
        if (1 == $access_url) {
5044
            if (!empty($subvar)) {
5045
                $select .= " AND subkey = '$subvar'";
5046
            }
5047
            if (!empty($cat)) {
5048
                $select .= " AND category = '$cat'";
5049
            }
5050
            $res = Database::query($select);
5051
            if (Database::num_rows($res) > 0) {
5052
                // We have a setting for access_url 1, but none for the current one, so create one.
5053
                $row = Database::fetch_array($res);
5054
                $insert = "INSERT INTO $t_settings (variable, subkey, type,category, selected_value, title, comment, scope, subkeytext, access_url)
5055
                        VALUES
5056
                        ('".$row['variable']."',".(!empty($row['subkey']) ? "'".$row['subkey']."'" : "NULL").",".
5057
                    "'".$row['type']."','".$row['category']."',".
5058
                    "'$value','".$row['title']."',".
5059
                    "".(!empty($row['comment']) ? "'".$row['comment']."'" : "NULL").",".(!empty($row['scope']) ? "'".$row['scope']."'" : "NULL").",".
5060
                    "".(!empty($row['subkeytext']) ? "'".$row['subkeytext']."'" : "NULL").",$access_url)";
5061
                Database::query($insert);
5062
            } else {
5063
                // Such a setting does not exist.
5064
                //error_log(__FILE__.':'.__LINE__.': Attempting to update setting '.$var.' ('.$subvar.') which does not exist at all', 0);
5065
            }
5066
        } else {
5067
            // Other access url.
5068
            if (!empty($subvar)) {
5069
                $select .= " AND subkey = '$subvar'";
5070
            }
5071
            if (!empty($cat)) {
5072
                $select .= " AND category = '$cat'";
5073
            }
5074
            $res = Database::query($select);
5075
5076
            if (Database::num_rows($res) > 0) {
5077
                // We have a setting for access_url 1, but none for the current one, so create one.
5078
                $row = Database::fetch_array($res);
5079
                if (1 == $row['access_url_changeable']) {
5080
                    $insert = "INSERT INTO $t_settings (variable,subkey, type,category, selected_value,title, comment,scope, subkeytext,access_url, access_url_changeable) VALUES
5081
                            ('".$row['variable']."',".
5082
                        (!empty($row['subkey']) ? "'".$row['subkey']."'" : "NULL").",".
5083
                        "'".$row['type']."','".$row['category']."',".
5084
                        "'$value','".$row['title']."',".
5085
                        "".(!empty($row['comment']) ? "'".$row['comment']."'" : "NULL").",".
5086
                        (!empty($row['scope']) ? "'".$row['scope']."'" : "NULL").",".
5087
                        "".(!empty($row['subkeytext']) ? "'".$row['subkeytext']."'" : "NULL").",$access_url,".$row['access_url_changeable'].")";
5088
                    Database::query($insert);
5089
                }
5090
            } else { // Such a setting does not exist.
5091
                //error_log(__FILE__.':'.__LINE__.': Attempting to update setting '.$var.' ('.$subvar.') which does not exist at all. The access_url is: '.$access_url.' ',0);
5092
            }
5093
        }
5094
    }
5095
}
5096
5097
/**
5098
 * Sets a whole category of settings to one specific value.
5099
 *
5100
 * @param string    Category
5101
 * @param string    Value
5102
 * @param int       Access URL. Optional. Defaults to 1
5103
 * @param array     Optional array of filters on field type
5104
 * @param string $category
5105
 * @param string $value
5106
 *
5107
 * @return bool
5108
 */
5109
function api_set_settings_category($category, $value = null, $access_url = 1, $fieldtype = [])
5110
{
5111
    if (empty($category)) {
5112
        return false;
5113
    }
5114
    $category = Database::escape_string($category);
5115
    $t_s = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5116
    $access_url = (int) $access_url;
5117
    if (empty($access_url)) {
5118
        $access_url = 1;
5119
    }
5120
    if (isset($value)) {
5121
        $value = Database::escape_string($value);
5122
        $sql = "UPDATE $t_s SET selected_value = '$value'
5123
                WHERE category = '$category' AND access_url = $access_url";
5124
        if (is_array($fieldtype) && count($fieldtype) > 0) {
5125
            $sql .= " AND ( ";
5126
            $i = 0;
5127
            foreach ($fieldtype as $type) {
5128
                if ($i > 0) {
5129
                    $sql .= ' OR ';
5130
                }
5131
                $type = Database::escape_string($type);
5132
                $sql .= " type='".$type."' ";
5133
                $i++;
5134
            }
5135
            $sql .= ")";
5136
        }
5137
        $res = Database::query($sql);
5138
5139
        return false !== $res;
5140
    } else {
5141
        $sql = "UPDATE $t_s SET selected_value = NULL
5142
                WHERE category = '$category' AND access_url = $access_url";
5143
        if (is_array($fieldtype) && count($fieldtype) > 0) {
5144
            $sql .= " AND ( ";
5145
            $i = 0;
5146
            foreach ($fieldtype as $type) {
5147
                if ($i > 0) {
5148
                    $sql .= ' OR ';
5149
                }
5150
                $type = Database::escape_string($type);
5151
                $sql .= " type='".$type."' ";
5152
                $i++;
5153
            }
5154
            $sql .= ")";
5155
        }
5156
        $res = Database::query($sql);
5157
5158
        return false !== $res;
5159
    }
5160
}
5161
5162
/**
5163
 * Gets all available access urls in an array (as in the database).
5164
 *
5165
 * @return array An array of database records
5166
 */
5167
function api_get_access_urls($from = 0, $to = 1000000, $order = 'url', $direction = 'ASC')
5168
{
5169
    $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5170
    $from = (int) $from;
5171
    $to = (int) $to;
5172
    $order = Database::escape_string($order, null, false);
5173
    $direction = Database::escape_string($direction, null, false);
5174
    $sql = "SELECT id, url, description, active, created_by, tms
5175
            FROM $table
5176
            ORDER BY $order $direction
5177
            LIMIT $to OFFSET $from";
5178
    $res = Database::query($sql);
5179
5180
    return Database::store_result($res);
5181
}
5182
5183
/**
5184
 * Gets the access url info in an array.
5185
 *
5186
 * @param int  $id            Id of the access url
5187
 * @param bool $returnDefault Set to false if you want the real URL if URL 1 is still 'http://localhost/'
5188
 *
5189
 * @return array All the info (url, description, active, created_by, tms)
5190
 *               from the access_url table
5191
 *
5192
 * @author Julio Montoya
5193
 */
5194
function api_get_access_url($id, $returnDefault = true)
5195
{
5196
    static $staticResult;
5197
    $id = (int) $id;
5198
5199
    if (isset($staticResult[$id])) {
5200
        $result = $staticResult[$id];
5201
    } else {
5202
        // Calling the Database:: library dont work this is handmade.
5203
        $table_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5204
        $sql = "SELECT url, description, active, created_by, tms
5205
                FROM $table_access_url WHERE id = '$id' ";
5206
        $res = Database::query($sql);
5207
        $result = @Database::fetch_array($res);
5208
        $staticResult[$id] = $result;
5209
    }
5210
5211
    // If the result url is 'http://localhost/' (the default) and the root_web
5212
    // (=current url) is different, and the $id is = 1 (which might mean
5213
    // api_get_current_access_url_id() returned 1 by default), then return the
5214
    // root_web setting instead of the current URL
5215
    // This is provided as an option to avoid breaking the storage of URL-specific
5216
    // homepages in home/localhost/
5217
    if (1 === $id && false === $returnDefault) {
5218
        $currentUrl = api_get_current_access_url_id();
5219
        // only do this if we are on the main URL (=1), otherwise we could get
5220
        // information on another URL instead of the one asked as parameter
5221
        if (1 === $currentUrl) {
5222
            $rootWeb = api_get_path(WEB_PATH);
5223
            $default = 'http://localhost/';
5224
            if ($result['url'] === $default && $rootWeb != $default) {
5225
                $result['url'] = $rootWeb;
5226
            }
5227
        }
5228
    }
5229
5230
    return $result;
5231
}
5232
5233
/**
5234
 * Gets all the current settings for a specific access url.
5235
 *
5236
 * @param string    The category, if any, that we want to get
5237
 * @param string    Whether we want a simple list (display a category) or
5238
 * a grouped list (group by variable as in settings.php default). Values: 'list' or 'group'
5239
 * @param int       Access URL's ID. Optional. Uses 1 by default, which is the unique URL
5240
 *
5241
 * @return array Array of database results for the current settings of the current access URL
5242
 */
5243
function &api_get_settings($cat = null, $ordering = 'list', $access_url = 1, $url_changeable = 0)
5244
{
5245
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5246
    $access_url = (int) $access_url;
5247
    $where_condition = '';
5248
    if (1 == $url_changeable) {
5249
        $where_condition = " AND access_url_changeable= '1' ";
5250
    }
5251
    if (empty($access_url) || -1 == $access_url) {
5252
        $access_url = 1;
5253
    }
5254
    $sql = "SELECT * FROM $table
5255
            WHERE access_url = $access_url  $where_condition ";
5256
5257
    if (!empty($cat)) {
5258
        $cat = Database::escape_string($cat);
5259
        $sql .= " AND category='$cat' ";
5260
    }
5261
    if ('group' == $ordering) {
5262
        $sql .= " ORDER BY id ASC";
5263
    } else {
5264
        $sql .= " ORDER BY 1,2 ASC";
5265
    }
5266
    $result = Database::query($sql);
5267
    if (null === $result) {
5268
        return [];
5269
    }
5270
    $result = Database::store_result($result, 'ASSOC');
5271
5272
    return $result;
5273
}
5274
5275
/**
5276
 * @param string $value       The value we want to record
5277
 * @param string $variable    The variable name we want to insert
5278
 * @param string $subKey      The subkey for the variable we want to insert
5279
 * @param string $type        The type for the variable we want to insert
5280
 * @param string $category    The category for the variable we want to insert
5281
 * @param string $title       The title
5282
 * @param string $comment     The comment
5283
 * @param string $scope       The scope
5284
 * @param string $subKeyText  The subkey text
5285
 * @param int    $accessUrlId The access_url for which this parameter is valid
5286
 * @param int    $visibility  The changeability of this setting for non-master urls
5287
 *
5288
 * @return int The setting ID
5289
 */
5290
function api_add_setting(
5291
    $value,
5292
    $variable,
5293
    $subKey = '',
5294
    $type = 'textfield',
5295
    $category = '',
5296
    $title = '',
5297
    $comment = '',
5298
    $scope = '',
5299
    $subKeyText = '',
5300
    $accessUrlId = 1,
5301
    $visibility = 0
5302
) {
5303
    $em = Database::getManager();
5304
5305
    $settingRepo = $em->getRepository(SettingsCurrent::class);
5306
    $accessUrlId = (int) $accessUrlId ?: 1;
5307
5308
    if (is_array($value)) {
5309
        $value = serialize($value);
5310
    } else {
5311
        $value = trim($value);
5312
    }
5313
5314
    $criteria = ['variable' => $variable, 'url' => $accessUrlId];
5315
5316
    if (!empty($subKey)) {
5317
        $criteria['subkey'] = $subKey;
5318
    }
5319
5320
    // Check if this variable doesn't exist already
5321
    /** @var SettingsCurrent $setting */
5322
    $setting = $settingRepo->findOneBy($criteria);
5323
5324
    if ($setting) {
0 ignored issues
show
introduced by
$setting is of type Chamilo\CoreBundle\Entity\SettingsCurrent, thus it always evaluated to true.
Loading history...
5325
        $setting->setSelectedValue($value);
5326
5327
        $em->persist($setting);
5328
        $em->flush();
5329
5330
        return $setting->getId();
5331
    }
5332
5333
    // Item not found for this access_url, we have to check if the whole thing is missing
5334
    // (in which case we ignore the insert) or if there *is* a record but just for access_url = 1
5335
    $setting = new SettingsCurrent();
5336
    $url = api_get_url_entity();
5337
5338
    $setting
5339
        ->setVariable($variable)
5340
        ->setSelectedValue($value)
5341
        ->setType($type)
5342
        ->setCategory($category)
5343
        ->setSubkey($subKey)
5344
        ->setTitle($title)
5345
        ->setComment($comment)
5346
        ->setScope($scope)
5347
        ->setSubkeytext($subKeyText)
5348
        ->setUrl(api_get_url_entity())
5349
        ->setAccessUrlChangeable($visibility);
5350
5351
    $em->persist($setting);
5352
    $em->flush();
5353
5354
    return $setting->getId();
5355
}
5356
5357
/**
5358
 * Checks wether a user can or can't view the contents of a course.
5359
 *
5360
 * @deprecated use CourseManager::is_user_subscribed_in_course
5361
 *
5362
 * @param int $userid User id or NULL to get it from $_SESSION
5363
 * @param int $cid    course id to check whether the user is allowed
5364
 *
5365
 * @return bool
5366
 */
5367
function api_is_course_visible_for_user($userid = null, $cid = null)
5368
{
5369
    if (null === $userid) {
5370
        $userid = api_get_user_id();
5371
    }
5372
    if (empty($userid) || strval(intval($userid)) != $userid) {
5373
        if (api_is_anonymous()) {
5374
            $userid = api_get_anonymous_id();
5375
        } else {
5376
            return false;
5377
        }
5378
    }
5379
    $cid = Database::escape_string($cid);
5380
5381
    $courseInfo = api_get_course_info($cid);
5382
    $courseId = $courseInfo['real_id'];
5383
    $is_platformAdmin = api_is_platform_admin();
5384
5385
    $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
5386
    $course_cat_table = Database::get_main_table(TABLE_MAIN_CATEGORY);
5387
5388
    $sql = "SELECT
5389
                $course_cat_table.code AS category_code,
5390
                $course_table.visibility,
5391
                $course_table.code,
5392
                $course_cat_table.code
5393
            FROM $course_table
5394
            LEFT JOIN $course_cat_table
5395
                ON $course_table.category_id = $course_cat_table.id
5396
            WHERE
5397
                $course_table.code = '$cid'
5398
            LIMIT 1";
5399
5400
    $result = Database::query($sql);
5401
5402
    if (Database::num_rows($result) > 0) {
5403
        $visibility = Database::fetch_array($result);
5404
        $visibility = $visibility['visibility'];
5405
    } else {
5406
        $visibility = 0;
5407
    }
5408
    // Shortcut permissions in case the visibility is "open to the world".
5409
    if (COURSE_VISIBILITY_OPEN_WORLD === $visibility) {
5410
        return true;
5411
    }
5412
5413
    $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
5414
5415
    $sql = "SELECT
5416
                is_tutor, status
5417
            FROM $tbl_course_user
5418
            WHERE
5419
                user_id  = '$userid' AND
5420
                relation_type <> '".COURSE_RELATION_TYPE_RRHH."' AND
5421
                c_id = $courseId
5422
            LIMIT 1";
5423
5424
    $result = Database::query($sql);
5425
5426
    if (Database::num_rows($result) > 0) {
5427
        // This user has got a recorded state for this course.
5428
        $cuData = Database::fetch_array($result);
5429
        $is_courseMember = true;
5430
        $is_courseAdmin = (1 == $cuData['status']);
5431
    }
5432
5433
    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...
5434
        // This user has no status related to this course.
5435
        // Is it the session coach or the session admin?
5436
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
5437
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
5438
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
5439
5440
        $sql = "SELECT
5441
                    session.id_coach, session_admin_id, session.id
5442
                FROM
5443
                    $tbl_session as session
5444
                INNER JOIN $tbl_session_course
5445
                    ON session_rel_course.session_id = session.id
5446
                    AND session_rel_course.c_id = '$courseId'
5447
                LIMIT 1";
5448
5449
        $result = Database::query($sql);
5450
        $row = Database::store_result($result);
5451
5452
        if ($row[0]['id_coach'] == $userid) {
5453
            $is_courseMember = true;
5454
            $is_courseAdmin = false;
5455
        } elseif ($row[0]['session_admin_id'] == $userid) {
5456
            $is_courseMember = false;
5457
            $is_courseAdmin = false;
5458
        } else {
5459
            // Check if the current user is the course coach.
5460
            $sql = "SELECT 1
5461
                    FROM $tbl_session_course
5462
                    WHERE session_rel_course.c_id = '$courseId'
5463
                    AND session_rel_course.id_coach = '$userid'
5464
                    LIMIT 1";
5465
5466
            $result = Database::query($sql);
5467
5468
            //if ($row = Database::fetch_array($result)) {
5469
            if (Database::num_rows($result) > 0) {
5470
                $is_courseMember = true;
5471
                $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
5472
5473
                $sql = "SELECT status FROM $tbl_user
5474
                        WHERE id = $userid
5475
                        LIMIT 1";
5476
5477
                $result = Database::query($sql);
5478
5479
                if (1 == Database::result($result, 0, 0)) {
5480
                    $is_courseAdmin = true;
5481
                } else {
5482
                    $is_courseAdmin = false;
5483
                }
5484
            } else {
5485
                // Check if the user is a student is this session.
5486
                $sql = "SELECT  id
5487
                        FROM $tbl_session_course_user
5488
                        WHERE
5489
                            user_id  = '$userid' AND
5490
                            c_id = '$courseId'
5491
                        LIMIT 1";
5492
5493
                if (Database::num_rows($result) > 0) {
5494
                    // This user haa got a recorded state for this course.
5495
                    while ($row = Database::fetch_array($result)) {
5496
                        $is_courseMember = true;
5497
                        $is_courseAdmin = false;
5498
                    }
5499
                }
5500
            }
5501
        }
5502
    }
5503
5504
    switch ($visibility) {
5505
        case COURSE_VISIBILITY_OPEN_WORLD:
5506
            return true;
5507
        case COURSE_VISIBILITY_OPEN_PLATFORM:
5508
            return isset($userid);
5509
        case COURSE_VISIBILITY_REGISTERED:
5510
        case COURSE_VISIBILITY_CLOSED:
5511
            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...
5512
        case COURSE_VISIBILITY_HIDDEN:
5513
            return $is_platformAdmin;
5514
    }
5515
5516
    return false;
5517
}
5518
5519
/**
5520
 * Returns whether an element (forum, message, survey ...) belongs to a session or not.
5521
 *
5522
 * @param string the tool of the element
5523
 * @param int the element id in database
5524
 * @param int the session_id to compare with element session id
5525
 *
5526
 * @return bool true if the element is in the session, false else
5527
 */
5528
function api_is_element_in_the_session($tool, $element_id, $session_id = null)
5529
{
5530
    if (is_null($session_id)) {
5531
        $session_id = api_get_session_id();
5532
    }
5533
5534
    $element_id = (int) $element_id;
5535
5536
    if (empty($element_id)) {
5537
        return false;
5538
    }
5539
5540
    // Get information to build query depending of the tool.
5541
    switch ($tool) {
5542
        case TOOL_SURVEY:
5543
            $table_tool = Database::get_course_table(TABLE_SURVEY);
5544
            $key_field = 'survey_id';
5545
            break;
5546
        case TOOL_ANNOUNCEMENT:
5547
            $table_tool = Database::get_course_table(TABLE_ANNOUNCEMENT);
5548
            $key_field = 'id';
5549
            break;
5550
        case TOOL_AGENDA:
5551
            $table_tool = Database::get_course_table(TABLE_AGENDA);
5552
            $key_field = 'id';
5553
            break;
5554
        case TOOL_GROUP:
5555
            $table_tool = Database::get_course_table(TABLE_GROUP);
5556
            $key_field = 'id';
5557
            break;
5558
        default:
5559
            return false;
5560
    }
5561
    $course_id = api_get_course_int_id();
5562
5563
    $sql = "SELECT session_id FROM $table_tool
5564
            WHERE c_id = $course_id AND $key_field =  ".$element_id;
5565
    $rs = Database::query($sql);
5566
    if ($element_session_id = Database::result($rs, 0, 0)) {
5567
        if ($element_session_id == intval($session_id)) {
5568
            // The element belongs to the session.
5569
            return true;
5570
        }
5571
    }
5572
5573
    return false;
5574
}
5575
5576
/**
5577
 * Replaces "forbidden" characters in a filename string.
5578
 *
5579
 * @param string $filename
5580
 * @param bool   $treat_spaces_as_hyphens
5581
 *
5582
 * @return string
5583
 */
5584
function api_replace_dangerous_char($filename, $treat_spaces_as_hyphens = true)
5585
{
5586
    // Some non-properly encoded file names can cause the whole file to be
5587
    // skipped when uploaded. Avoid this by detecting the encoding and
5588
    // converting to UTF-8, setting the source as ASCII (a reasonably
5589
    // limited characters set) if nothing could be found (BT#
5590
    $encoding = api_detect_encoding($filename);
5591
    if (empty($encoding)) {
5592
        $encoding = 'ASCII';
5593
        if (!api_is_valid_ascii($filename)) {
5594
            // try iconv and try non standard ASCII a.k.a CP437
5595
            // see BT#15022
5596
            if (function_exists('iconv')) {
5597
                $result = iconv('CP437', 'UTF-8', $filename);
5598
                if (api_is_valid_utf8($result)) {
5599
                    $filename = $result;
5600
                    $encoding = 'UTF-8';
5601
                }
5602
            }
5603
        }
5604
    }
5605
5606
    $filename = api_to_system_encoding($filename, $encoding);
5607
5608
    $url = URLify::filter(
5609
        $filename,
5610
        250,
5611
        '',
5612
        true,
5613
        false,
5614
        false,
5615
        false
5616
    );
5617
5618
    return $url;
5619
}
5620
5621
/**
5622
 * Fixes the $_SERVER['REQUEST_URI'] that is empty in IIS6.
5623
 *
5624
 * @author Ivan Tcholakov, 28-JUN-2006.
5625
 */
5626
function api_request_uri()
5627
{
5628
    if (!empty($_SERVER['REQUEST_URI'])) {
5629
        return $_SERVER['REQUEST_URI'];
5630
    }
5631
    $uri = $_SERVER['SCRIPT_NAME'];
5632
    if (!empty($_SERVER['QUERY_STRING'])) {
5633
        $uri .= '?'.$_SERVER['QUERY_STRING'];
5634
    }
5635
    $_SERVER['REQUEST_URI'] = $uri;
5636
5637
    return $uri;
5638
}
5639
5640
/** Gets the current access_url id of the Chamilo Platform.
5641
 * @author Julio Montoya <[email protected]>
5642
 *
5643
 * @return int access_url_id of the current Chamilo Installation
5644
 */
5645
function api_get_current_access_url_id()
5646
{
5647
    if (false === api_get_multiple_access_url()) {
5648
        return 1;
5649
    }
5650
5651
    static $id;
5652
    if (!empty($id)) {
5653
        return $id;
5654
    }
5655
5656
    $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5657
    $path = Database::escape_string(api_get_path(WEB_PATH));
5658
    $sql = "SELECT id FROM $table WHERE url = '".$path."'";
5659
    $result = Database::query($sql);
5660
    if (Database::num_rows($result) > 0) {
5661
        $id = Database::result($result, 0, 0);
5662
        if (false === $id) {
5663
            return -1;
5664
        }
5665
5666
        return (int) $id;
5667
    }
5668
5669
    $id = 1;
5670
5671
    //if the url in WEB_PATH was not found, it can only mean that there is
5672
    // either a configuration problem or the first URL has not been defined yet
5673
    // (by default it is http://localhost/). Thus the more sensible thing we can
5674
    // do is return 1 (the main URL) as the user cannot hack this value anyway
5675
    return 1;
5676
}
5677
5678
/**
5679
 * Gets the registered urls from a given user id.
5680
 *
5681
 * @author Julio Montoya <[email protected]>
5682
 *
5683
 * @param int $user_id
5684
 *
5685
 * @return array
5686
 */
5687
function api_get_access_url_from_user($user_id)
5688
{
5689
    $user_id = (int) $user_id;
5690
    $table_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
5691
    $table_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5692
    $sql = "SELECT access_url_id
5693
            FROM $table_url_rel_user url_rel_user
5694
            INNER JOIN $table_url u
5695
            ON (url_rel_user.access_url_id = u.id)
5696
            WHERE user_id = ".$user_id;
5697
    $result = Database::query($sql);
5698
    $list = [];
5699
    while ($row = Database::fetch_array($result, 'ASSOC')) {
5700
        $list[] = $row['access_url_id'];
5701
    }
5702
5703
    return $list;
5704
}
5705
5706
/**
5707
 * Checks whether the curent user is in a group or not.
5708
 *
5709
 * @param string        The group id - optional (takes it from session if not given)
5710
 * @param string        The course code - optional (no additional check by course if course code is not given)
5711
 *
5712
 * @return bool
5713
 *
5714
 * @author Ivan Tcholakov
5715
 */
5716
function api_is_in_group($groupIdParam = null, $courseCodeParam = null)
5717
{
5718
    if (!empty($courseCodeParam)) {
5719
        $courseCode = api_get_course_id();
5720
        if (!empty($courseCode)) {
5721
            if ($courseCodeParam != $courseCode) {
5722
                return false;
5723
            }
5724
        } else {
5725
            return false;
5726
        }
5727
    }
5728
5729
    $groupId = api_get_group_id();
5730
5731
    if (isset($groupId) && '' != $groupId) {
5732
        if (!empty($groupIdParam)) {
5733
            return $groupIdParam == $groupId;
5734
        } else {
5735
            return true;
5736
        }
5737
    }
5738
5739
    return false;
5740
}
5741
5742
/**
5743
 * Checks whether a secret key is valid.
5744
 *
5745
 * @param string $original_key_secret - secret key from (webservice) client
5746
 * @param string $security_key        - security key from Chamilo
5747
 *
5748
 * @return bool - true if secret key is valid, false otherwise
5749
 */
5750
function api_is_valid_secret_key($original_key_secret, $security_key)
5751
{
5752
    return $original_key_secret == sha1($security_key);
5753
}
5754
5755
/**
5756
 * Checks whether a user is into course.
5757
 *
5758
 * @param int $course_id - the course id
5759
 * @param int $user_id   - the user id
5760
 *
5761
 * @return bool
5762
 */
5763
function api_is_user_of_course($course_id, $user_id)
5764
{
5765
    $tbl_course_rel_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
5766
    $sql = 'SELECT user_id FROM '.$tbl_course_rel_user.'
5767
            WHERE
5768
                c_id ="'.intval($course_id).'" AND
5769
                user_id = "'.intval($user_id).'" AND
5770
                relation_type <> '.COURSE_RELATION_TYPE_RRHH.' ';
5771
    $result = Database::query($sql);
5772
5773
    return 1 == Database::num_rows($result);
5774
}
5775
5776
/**
5777
 * Checks whether the server's operating system is Windows (TM).
5778
 *
5779
 * @return bool - true if the operating system is Windows, false otherwise
5780
 */
5781
function api_is_windows_os()
5782
{
5783
    if (function_exists('php_uname')) {
5784
        // php_uname() exists as of PHP 4.0.2, according to the documentation.
5785
        // We expect that this function will always work for Chamilo 1.8.x.
5786
        $os = php_uname();
5787
    }
5788
    // The following methods are not needed, but let them stay, just in case.
5789
    elseif (isset($_ENV['OS'])) {
5790
        // Sometimes $_ENV['OS'] may not be present (bugs?)
5791
        $os = $_ENV['OS'];
5792
    } elseif (defined('PHP_OS')) {
5793
        // PHP_OS means on which OS PHP was compiled, this is why
5794
        // using PHP_OS is the last choice for detection.
5795
        $os = PHP_OS;
5796
    } else {
5797
        return false;
5798
    }
5799
5800
    return 'win' == strtolower(substr((string) $os, 0, 3));
5801
}
5802
5803
/**
5804
 * This function informs whether the sent request is XMLHttpRequest.
5805
 */
5806
function api_is_xml_http_request()
5807
{
5808
    return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && 'xmlhttprequest' == strtolower($_SERVER['HTTP_X_REQUESTED_WITH']);
5809
}
5810
5811
/**
5812
 * This wrapper function has been implemented for avoiding some known problems about the function getimagesize().
5813
 *
5814
 * @see http://php.net/manual/en/function.getimagesize.php
5815
 * @see http://www.dokeos.com/forum/viewtopic.php?t=12345
5816
 * @see http://www.dokeos.com/forum/viewtopic.php?t=16355
5817
 *
5818
 * @return int
5819
 */
5820
function api_getimagesize($path)
5821
{
5822
    $image = new Image($path);
0 ignored issues
show
Deprecated Code introduced by
The class Image has been deprecated. ( Ignorable by Annotation )

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

5822
    $image = /** @scrutinizer ignore-deprecated */ new Image($path);
Loading history...
5823
5824
    return $image->get_image_size();
5825
}
5826
5827
/**
5828
 * This function resizes an image, with preserving its proportions (or aspect ratio).
5829
 *
5830
 * @author Ivan Tcholakov, MAY-2009.
5831
 *
5832
 * @param int $image         System path or URL of the image
5833
 * @param int $target_width  Targeted width
5834
 * @param int $target_height Targeted height
5835
 *
5836
 * @return array Calculated new width and height
5837
 */
5838
function api_resize_image($image, $target_width, $target_height)
5839
{
5840
    $image_properties = api_getimagesize($image);
5841
5842
    return api_calculate_image_size(
5843
        $image_properties['width'],
5844
        $image_properties['height'],
5845
        $target_width,
5846
        $target_height
5847
    );
5848
}
5849
5850
/**
5851
 * This function calculates new image size, with preserving image's proportions (or aspect ratio).
5852
 *
5853
 * @author Ivan Tcholakov, MAY-2009.
5854
 * @author The initial idea has been taken from code by Patrick Cool, MAY-2004.
5855
 *
5856
 * @param int $image_width   Initial width
5857
 * @param int $image_height  Initial height
5858
 * @param int $target_width  Targeted width
5859
 * @param int $target_height Targeted height
5860
 *
5861
 * @return array Calculated new width and height
5862
 */
5863
function api_calculate_image_size(
5864
    $image_width,
5865
    $image_height,
5866
    $target_width,
5867
    $target_height
5868
) {
5869
    // Only maths is here.
5870
    $result = ['width' => $image_width, 'height' => $image_height];
5871
    if ($image_width <= 0 || $image_height <= 0) {
5872
        return $result;
5873
    }
5874
    $resize_factor_width = $target_width / $image_width;
5875
    $resize_factor_height = $target_height / $image_height;
5876
    $delta_width = $target_width - $image_width * $resize_factor_height;
5877
    $delta_height = $target_height - $image_height * $resize_factor_width;
5878
    if ($delta_width > $delta_height) {
5879
        $result['width'] = ceil($image_width * $resize_factor_height);
5880
        $result['height'] = ceil($image_height * $resize_factor_height);
5881
    } elseif ($delta_width < $delta_height) {
5882
        $result['width'] = ceil($image_width * $resize_factor_width);
5883
        $result['height'] = ceil($image_height * $resize_factor_width);
5884
    } else {
5885
        $result['width'] = ceil($target_width);
5886
        $result['height'] = ceil($target_height);
5887
    }
5888
5889
    return $result;
5890
}
5891
5892
/**
5893
 * Returns a list of Chamilo's tools or
5894
 * checks whether a given identificator is a valid Chamilo's tool.
5895
 *
5896
 * @author Isaac flores paz
5897
 *
5898
 * @param string The tool name to filter
5899
 *
5900
 * @return mixed Filtered string or array
5901
 */
5902
function api_get_tools_lists($my_tool = null)
5903
{
5904
    $tools_list = [
5905
        TOOL_DOCUMENT,
5906
        TOOL_THUMBNAIL,
5907
        TOOL_HOTPOTATOES,
5908
        TOOL_CALENDAR_EVENT,
5909
        TOOL_LINK,
5910
        TOOL_COURSE_DESCRIPTION,
5911
        TOOL_SEARCH,
5912
        TOOL_LEARNPATH,
5913
        TOOL_ANNOUNCEMENT,
5914
        TOOL_FORUM,
5915
        TOOL_THREAD,
5916
        TOOL_POST,
5917
        TOOL_DROPBOX,
5918
        TOOL_QUIZ,
5919
        TOOL_USER,
5920
        TOOL_GROUP,
5921
        TOOL_BLOGS,
5922
        TOOL_CHAT,
5923
        TOOL_STUDENTPUBLICATION,
5924
        TOOL_TRACKING,
5925
        TOOL_HOMEPAGE_LINK,
5926
        TOOL_COURSE_SETTING,
5927
        TOOL_BACKUP,
5928
        TOOL_COPY_COURSE_CONTENT,
5929
        TOOL_RECYCLE_COURSE,
5930
        TOOL_COURSE_HOMEPAGE,
5931
        TOOL_COURSE_RIGHTS_OVERVIEW,
5932
        TOOL_UPLOAD,
5933
        TOOL_COURSE_MAINTENANCE,
5934
        TOOL_SURVEY,
5935
        TOOL_WIKI,
5936
        TOOL_GLOSSARY,
5937
        TOOL_GRADEBOOK,
5938
        TOOL_NOTEBOOK,
5939
        TOOL_ATTENDANCE,
5940
        TOOL_COURSE_PROGRESS,
5941
    ];
5942
    if (empty($my_tool)) {
5943
        return $tools_list;
5944
    }
5945
5946
    return in_array($my_tool, $tools_list) ? $my_tool : '';
5947
}
5948
5949
/**
5950
 * Checks whether we already approved the last version term and condition.
5951
 *
5952
 * @param int user id
5953
 *
5954
 * @return bool true if we pass false otherwise
5955
 */
5956
function api_check_term_condition($userId)
5957
{
5958
    if ('true' === api_get_setting('allow_terms_conditions')) {
5959
        // Check if exists terms and conditions
5960
        if (0 == LegalManager::count()) {
5961
            return true;
5962
        }
5963
5964
        $extraFieldValue = new ExtraFieldValue('user');
5965
        $data = $extraFieldValue->get_values_by_handler_and_field_variable(
5966
            $userId,
5967
            'legal_accept'
5968
        );
5969
5970
        if (!empty($data) && isset($data['value']) && !empty($data['value'])) {
5971
            $result = $data['value'];
5972
            $user_conditions = explode(':', $result);
5973
            $version = $user_conditions[0];
5974
            $langId = $user_conditions[1];
5975
            $realVersion = LegalManager::get_last_version($langId);
5976
5977
            return $version >= $realVersion;
5978
        }
5979
5980
        return false;
5981
    }
5982
5983
    return false;
5984
}
5985
5986
/**
5987
 * Gets all information of a tool into course.
5988
 *
5989
 * @param int The tool id
5990
 *
5991
 * @return array
5992
 */
5993
function api_get_tool_information_by_name($name)
5994
{
5995
    $t_tool = Database::get_course_table(TABLE_TOOL_LIST);
5996
    $course_id = api_get_course_int_id();
5997
5998
    $sql = "SELECT id FROM tool
5999
            WHERE name = '".Database::escape_string($name)."' ";
6000
    $rs = Database::query($sql);
6001
    $data = Database::fetch_array($rs);
6002
    $tool = $data['id'];
6003
6004
    $sql = "SELECT * FROM $t_tool
6005
            WHERE c_id = $course_id  AND tool_id = '".$tool."' ";
6006
    $rs = Database::query($sql);
6007
6008
    return Database::fetch_array($rs, 'ASSOC');
6009
}
6010
6011
/**
6012
 * Function used to protect a "global" admin script.
6013
 * The function blocks access when the user has no global platform admin rights.
6014
 * Global admins are the admins that are registered in the main.admin table
6015
 * AND the users who have access to the "principal" portal.
6016
 * That means that there is a record in the main.access_url_rel_user table
6017
 * with his user id and the access_url_id=1.
6018
 *
6019
 * @author Julio Montoya
6020
 *
6021
 * @param int $user_id
6022
 *
6023
 * @return bool
6024
 */
6025
function api_is_global_platform_admin($user_id = null)
6026
{
6027
    $user_id = (int) $user_id;
6028
    if (empty($user_id)) {
6029
        $user_id = api_get_user_id();
6030
    }
6031
    if (api_is_platform_admin_by_id($user_id)) {
6032
        $urlList = api_get_access_url_from_user($user_id);
6033
        // The admin is registered in the first "main" site with access_url_id = 1
6034
        if (in_array(1, $urlList)) {
6035
            return true;
6036
        } else {
6037
            return false;
6038
        }
6039
    }
6040
6041
    return false;
6042
}
6043
6044
/**
6045
 * @param int  $admin_id_to_check
6046
 * @param int  $my_user_id
6047
 * @param bool $allow_session_admin
6048
 *
6049
 * @return bool
6050
 */
6051
function api_global_admin_can_edit_admin(
6052
    $admin_id_to_check,
6053
    $my_user_id = null,
6054
    $allow_session_admin = false
6055
) {
6056
    if (empty($my_user_id)) {
6057
        $my_user_id = api_get_user_id();
6058
    }
6059
6060
    $iam_a_global_admin = api_is_global_platform_admin($my_user_id);
6061
    $user_is_global_admin = api_is_global_platform_admin($admin_id_to_check);
6062
6063
    if ($iam_a_global_admin) {
6064
        // Global admin can edit everything
6065
        return true;
6066
    } else {
6067
        // If i'm a simple admin
6068
        $is_platform_admin = api_is_platform_admin_by_id($my_user_id);
6069
6070
        if ($allow_session_admin) {
6071
            $is_platform_admin = api_is_platform_admin_by_id($my_user_id) || (SESSIONADMIN == api_get_user_status($my_user_id));
6072
        }
6073
6074
        if ($is_platform_admin) {
6075
            if ($user_is_global_admin) {
6076
                return false;
6077
            } else {
6078
                return true;
6079
            }
6080
        } else {
6081
            return false;
6082
        }
6083
    }
6084
}
6085
6086
/**
6087
 * @param int  $admin_id_to_check
6088
 * @param int  $my_user_id
6089
 * @param bool $allow_session_admin
6090
 *
6091
 * @return bool|null
6092
 */
6093
function api_protect_super_admin($admin_id_to_check, $my_user_id = null, $allow_session_admin = false)
6094
{
6095
    if (api_global_admin_can_edit_admin($admin_id_to_check, $my_user_id, $allow_session_admin)) {
6096
        return true;
6097
    } else {
6098
        api_not_allowed();
6099
    }
6100
}
6101
6102
/**
6103
 * Function used to protect a global admin script.
6104
 * The function blocks access when the user has no global platform admin rights.
6105
 * See also the api_is_global_platform_admin() function wich defines who's a "global" admin.
6106
 *
6107
 * @author Julio Montoya
6108
 */
6109
function api_protect_global_admin_script()
6110
{
6111
    if (!api_is_global_platform_admin()) {
6112
        api_not_allowed();
6113
6114
        return false;
6115
    }
6116
6117
    return true;
6118
}
6119
6120
/**
6121
 * Check browser support for specific file types or features
6122
 * This function checks if the user's browser supports a file format or given
6123
 * feature, or returns the current browser and major version when
6124
 * $format=check_browser. Only a limited number of formats and features are
6125
 * checked by this method. Make sure you check its definition first.
6126
 *
6127
 * @param string $format Can be a file format (extension like svg, webm, ...) or a feature (like autocapitalize, ...)
6128
 *
6129
 * @deprecated
6130
 *
6131
 * @return bool or return text array if $format=check_browser
6132
 *
6133
 * @author Juan Carlos Raña Trabado
6134
 */
6135
function api_browser_support($format = '')
6136
{
6137
    return true;
6138
6139
    $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...
6140
    $current_browser = $browser->getBrowser();
6141
    $a_versiontemp = explode('.', $browser->getVersion());
6142
    $current_majorver = $a_versiontemp[0];
6143
6144
    static $result;
6145
6146
    if (isset($result[$format])) {
6147
        return $result[$format];
6148
    }
6149
6150
    // Native svg support
6151
    if ('svg' == $format) {
6152
        if (('Internet Explorer' == $current_browser && $current_majorver >= 9) ||
6153
            ('Firefox' == $current_browser && $current_majorver > 1) ||
6154
            ('Safari' == $current_browser && $current_majorver >= 4) ||
6155
            ('Chrome' == $current_browser && $current_majorver >= 1) ||
6156
            ('Opera' == $current_browser && $current_majorver >= 9)
6157
        ) {
6158
            $result[$format] = true;
6159
6160
            return true;
6161
        } else {
6162
            $result[$format] = false;
6163
6164
            return false;
6165
        }
6166
    } elseif ('pdf' == $format) {
6167
        // native pdf support
6168
        if ('Chrome' == $current_browser && $current_majorver >= 6) {
6169
            $result[$format] = true;
6170
6171
            return true;
6172
        } else {
6173
            $result[$format] = false;
6174
6175
            return false;
6176
        }
6177
    } elseif ('tif' == $format || 'tiff' == $format) {
6178
        //native tif support
6179
        if ('Safari' == $current_browser && $current_majorver >= 5) {
6180
            $result[$format] = true;
6181
6182
            return true;
6183
        } else {
6184
            $result[$format] = false;
6185
6186
            return false;
6187
        }
6188
    } elseif ('ogg' == $format || 'ogx' == $format || 'ogv' == $format || 'oga' == $format) {
6189
        //native ogg, ogv,oga support
6190
        if (('Firefox' == $current_browser && $current_majorver >= 3) ||
6191
            ('Chrome' == $current_browser && $current_majorver >= 3) ||
6192
            ('Opera' == $current_browser && $current_majorver >= 9)) {
6193
            $result[$format] = true;
6194
6195
            return true;
6196
        } else {
6197
            $result[$format] = false;
6198
6199
            return false;
6200
        }
6201
    } elseif ('mpg' == $format || 'mpeg' == $format) {
6202
        //native mpg support
6203
        if (('Safari' == $current_browser && $current_majorver >= 5)) {
6204
            $result[$format] = true;
6205
6206
            return true;
6207
        } else {
6208
            $result[$format] = false;
6209
6210
            return false;
6211
        }
6212
    } elseif ('mp4' == $format) {
6213
        //native mp4 support (TODO: Android, iPhone)
6214
        if ('Android' == $current_browser || 'iPhone' == $current_browser) {
6215
            $result[$format] = true;
6216
6217
            return true;
6218
        } else {
6219
            $result[$format] = false;
6220
6221
            return false;
6222
        }
6223
    } elseif ('mov' == $format) {
6224
        //native mov support( TODO:check iPhone)
6225
        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...
6226
            $result[$format] = true;
6227
6228
            return true;
6229
        } else {
6230
            $result[$format] = false;
6231
6232
            return false;
6233
        }
6234
    } elseif ('avi' == $format) {
6235
        //native avi support
6236
        if ('Safari' == $current_browser && $current_majorver >= 5) {
6237
            $result[$format] = true;
6238
6239
            return true;
6240
        } else {
6241
            $result[$format] = false;
6242
6243
            return false;
6244
        }
6245
    } elseif ('wmv' == $format) {
6246
        //native wmv support
6247
        if ('Firefox' == $current_browser && $current_majorver >= 4) {
6248
            $result[$format] = true;
6249
6250
            return true;
6251
        } else {
6252
            $result[$format] = false;
6253
6254
            return false;
6255
        }
6256
    } elseif ('webm' == $format) {
6257
        //native webm support (TODO:check IE9, Chrome9, Android)
6258
        if (('Firefox' == $current_browser && $current_majorver >= 4) ||
6259
            ('Opera' == $current_browser && $current_majorver >= 9) ||
6260
            ('Internet Explorer' == $current_browser && $current_majorver >= 9) ||
6261
            ('Chrome' == $current_browser && $current_majorver >= 9) ||
6262
            'Android' == $current_browser
6263
        ) {
6264
            $result[$format] = true;
6265
6266
            return true;
6267
        } else {
6268
            $result[$format] = false;
6269
6270
            return false;
6271
        }
6272
    } elseif ('wav' == $format) {
6273
        //native wav support (only some codecs !)
6274
        if (('Firefox' == $current_browser && $current_majorver >= 4) ||
6275
            ('Safari' == $current_browser && $current_majorver >= 5) ||
6276
            ('Opera' == $current_browser && $current_majorver >= 9) ||
6277
            ('Internet Explorer' == $current_browser && $current_majorver >= 9) ||
6278
            ('Chrome' == $current_browser && $current_majorver > 9) ||
6279
            'Android' == $current_browser ||
6280
            'iPhone' == $current_browser
6281
        ) {
6282
            $result[$format] = true;
6283
6284
            return true;
6285
        } else {
6286
            $result[$format] = false;
6287
6288
            return false;
6289
        }
6290
    } elseif ('mid' == $format || 'kar' == $format) {
6291
        //native midi support (TODO:check Android)
6292
        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...
6293
            $result[$format] = true;
6294
6295
            return true;
6296
        } else {
6297
            $result[$format] = false;
6298
6299
            return false;
6300
        }
6301
    } elseif ('wma' == $format) {
6302
        //native wma support
6303
        if ('Firefox' == $current_browser && $current_majorver >= 4) {
6304
            $result[$format] = true;
6305
6306
            return true;
6307
        } else {
6308
            $result[$format] = false;
6309
6310
            return false;
6311
        }
6312
    } elseif ('au' == $format) {
6313
        //native au support
6314
        if ('Safari' == $current_browser && $current_majorver >= 5) {
6315
            $result[$format] = true;
6316
6317
            return true;
6318
        } else {
6319
            $result[$format] = false;
6320
6321
            return false;
6322
        }
6323
    } elseif ('mp3' == $format) {
6324
        //native mp3 support (TODO:check Android, iPhone)
6325
        if (('Safari' == $current_browser && $current_majorver >= 5) ||
6326
            ('Chrome' == $current_browser && $current_majorver >= 6) ||
6327
            ('Internet Explorer' == $current_browser && $current_majorver >= 9) ||
6328
            'Android' == $current_browser ||
6329
            'iPhone' == $current_browser ||
6330
            'Firefox' == $current_browser
6331
        ) {
6332
            $result[$format] = true;
6333
6334
            return true;
6335
        } else {
6336
            $result[$format] = false;
6337
6338
            return false;
6339
        }
6340
    } elseif ('autocapitalize' == $format) {
6341
        // Help avoiding showing the autocapitalize option if the browser doesn't
6342
        // support it: this attribute is against the HTML5 standard
6343
        if ('Safari' == $current_browser || 'iPhone' == $current_browser) {
6344
            return true;
6345
        } else {
6346
            return false;
6347
        }
6348
    } elseif ("check_browser" == $format) {
6349
        $array_check_browser = [$current_browser, $current_majorver];
6350
6351
        return $array_check_browser;
6352
    } else {
6353
        $result[$format] = false;
6354
6355
        return false;
6356
    }
6357
}
6358
6359
/**
6360
 * This function checks if exist path and file browscap.ini
6361
 * In order for this to work, your browscap configuration setting in php.ini
6362
 * must point to the correct location of the browscap.ini file on your system
6363
 * http://php.net/manual/en/function.get-browser.php.
6364
 *
6365
 * @return bool
6366
 *
6367
 * @author Juan Carlos Raña Trabado
6368
 */
6369
function api_check_browscap()
6370
{
6371
    $setting = ini_get('browscap');
6372
    if ($setting) {
6373
        $browser = get_browser($_SERVER['HTTP_USER_AGENT'], true);
6374
        if (strpos($setting, 'browscap.ini') && !empty($browser)) {
6375
            return true;
6376
        }
6377
    }
6378
6379
    return false;
6380
}
6381
6382
/**
6383
 * Returns the <script> HTML tag.
6384
 */
6385
function api_get_js($file)
6386
{
6387
    return '<script type="text/javascript" src="'.api_get_path(WEB_LIBRARY_PATH).'javascript/'.$file.'"></script>'."\n";
6388
}
6389
6390
function api_get_build_js($file)
6391
{
6392
    return '<script type="text/javascript" src="'.api_get_path(WEB_PUBLIC_PATH).'build/'.$file.'"></script>'."\n";
6393
}
6394
6395
function api_get_build_css($file, $media = 'screen')
6396
{
6397
    return '<link
6398
        href="'.api_get_path(WEB_PUBLIC_PATH).'build/'.$file.'" rel="stylesheet" media="'.$media.'" type="text/css" />'."\n";
6399
}
6400
6401
/**
6402
 * Returns the <script> HTML tag.
6403
 *
6404
 * @return string
6405
 */
6406
function api_get_asset($file)
6407
{
6408
    return '<script type="text/javascript" src="'.api_get_path(WEB_PUBLIC_PATH).'build/libs/'.$file.'"></script>'."\n";
6409
}
6410
6411
/**
6412
 * Returns the <script> HTML tag.
6413
 *
6414
 * @param string $file
6415
 * @param string $media
6416
 *
6417
 * @return string
6418
 */
6419
function api_get_css_asset($file, $media = 'screen')
6420
{
6421
    return '<link href="'.api_get_path(WEB_PUBLIC_PATH).'build/libs/'.$file.'" rel="stylesheet" media="'.$media.'" type="text/css" />'."\n";
6422
}
6423
6424
/**
6425
 * Returns the <link> HTML tag.
6426
 *
6427
 * @param string $file
6428
 * @param string $media
6429
 */
6430
function api_get_css($file, $media = 'screen')
6431
{
6432
    return '<link href="'.$file.'" rel="stylesheet" media="'.$media.'" type="text/css" />'."\n";
6433
}
6434
6435
function api_get_bootstrap_and_font_awesome($returnOnlyPath = false)
6436
{
6437
    $url = api_get_path(WEB_PUBLIC_PATH).'build/css/bootstrap.css';
6438
    if ($returnOnlyPath) {
6439
        return $url;
6440
    }
6441
6442
    return '<link href="'.$url.'" rel="stylesheet" type="text/css" />'."\n";
6443
}
6444
6445
/**
6446
 * Returns the js header to include the jquery library.
6447
 */
6448
function api_get_jquery_js()
6449
{
6450
    return api_get_asset('jquery/jquery.min.js');
6451
}
6452
6453
/**
6454
 * Returns the jquery path.
6455
 *
6456
 * @return string
6457
 */
6458
function api_get_jquery_web_path()
6459
{
6460
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery/jquery.min.js';
6461
}
6462
6463
/**
6464
 * @return string
6465
 */
6466
function api_get_jquery_ui_js_web_path()
6467
{
6468
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery-ui/jquery-ui.min.js';
6469
}
6470
6471
/**
6472
 * @return string
6473
 */
6474
function api_get_jquery_ui_css_web_path()
6475
{
6476
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery-ui/themes/smoothness/jquery-ui.min.css';
6477
}
6478
6479
/**
6480
 * Returns the jquery-ui library js headers.
6481
 *
6482
 * @return string html tags
6483
 */
6484
function api_get_jquery_ui_js()
6485
{
6486
    $libraries = [];
6487
6488
    return api_get_jquery_libraries_js($libraries);
6489
}
6490
6491
function api_get_jqgrid_js()
6492
{
6493
    $routePublic = Container::getRouter()->generate('home');
6494
6495
    return api_get_css($routePublic.'build/free-jqgrid.css').PHP_EOL
6496
        .api_get_js_simple($routePublic.'build/free-jqgrid.js');
6497
}
6498
6499
/**
6500
 * Returns the jquery library js and css headers.
6501
 *
6502
 * @param   array   list of jquery libraries supported jquery-ui
6503
 * @param   bool    add the jquery library
6504
 *
6505
 * @return string html tags
6506
 */
6507
function api_get_jquery_libraries_js($libraries)
6508
{
6509
    $js = '';
6510
6511
    //Document multiple upload funcionality
6512
    if (in_array('jquery-uploadzs', $libraries)) {
6513
        $js .= api_get_asset('blueimp-load-image/js/load-image.all.min.js');
6514
        $js .= api_get_asset('blueimp-canvas-to-blob/js/canvas-to-blob.min.js');
6515
        $js .= api_get_asset('jquery-file-upload/js/jquery.iframe-transport.js');
6516
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload.js');
6517
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-process.js');
6518
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-image.js');
6519
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-audio.js');
6520
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-video.js');
6521
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-validate.js');
6522
6523
        $js .= api_get_css(api_get_path(WEB_PUBLIC_PATH).'assets/jquery-file-upload/css/jquery.fileupload.css');
6524
        $js .= api_get_css(api_get_path(WEB_PUBLIC_PATH).'assets/jquery-file-upload/css/jquery.fileupload-ui.css');
6525
    }
6526
6527
    // jquery datepicker
6528
    if (in_array('datepicker', $libraries)) {
6529
        $languaje = 'en-GB';
6530
        $platform_isocode = strtolower(api_get_language_isocode());
6531
6532
        $datapicker_langs = [
6533
            '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',
6534
        ];
6535
        if (in_array($platform_isocode, $datapicker_langs)) {
6536
            $languaje = $platform_isocode;
6537
        }
6538
6539
        $js .= api_get_js('jquery-ui/jquery-ui-i18n.min.js');
6540
        $script = '<script>
6541
        $(function(){
6542
            $.datepicker.setDefaults($.datepicker.regional["'.$languaje.'"]);
6543
            $.datepicker.regional["local"] = $.datepicker.regional["'.$languaje.'"];
6544
        });
6545
        </script>
6546
        ';
6547
        $js .= $script;
6548
    }
6549
6550
    return $js;
6551
}
6552
6553
/**
6554
 * Returns the URL to the course or session, removing the complexity of the URL
6555
 * building piece by piece.
6556
 *
6557
 * This function relies on api_get_course_info()
6558
 *
6559
 * @param string $courseCode The course code - optional (takes it from context if not given)
6560
 * @param int    $sessionId  The session ID  - optional (takes it from context if not given)
6561
 * @param int    $groupId    The group ID - optional (takes it from context if not given)
6562
 *
6563
 * @return string The URL to a course, a session, or empty string if nothing works
6564
 *                e.g. https://localhost/courses/ABC/index.php?session_id=3&gidReq=1
6565
 *
6566
 * @author  Julio Montoya <[email protected]>
6567
 */
6568
function api_get_course_url($courseCode = null, $sessionId = null, $groupId = null)
6569
{
6570
    $url = '';
6571
    // If courseCode not set, get context or []
6572
    if (empty($courseCode)) {
6573
        $courseInfo = api_get_course_info();
6574
    } else {
6575
        $courseInfo = api_get_course_info($courseCode);
6576
    }
6577
6578
    // If sessionId not set, get context or 0
6579
    if (empty($sessionId)) {
6580
        $sessionId = api_get_session_id();
6581
    }
6582
6583
    // If groupId not set, get context or 0
6584
    if (empty($groupId)) {
6585
        $groupId = api_get_group_id();
6586
    }
6587
6588
    // Build the URL
6589
    if (!empty($courseInfo)) {
6590
        // directory not empty, so we do have a course
6591
        $url = $courseInfo['course_public_url'].'?sid='.$sessionId.'&gid='.$groupId;
6592
    } else {
6593
        if (!empty($sessionId) && 'true' !== api_get_setting('session.remove_session_url')) {
6594
            // if the course was unset and the session was set, send directly to the session
6595
            $url = api_get_path(WEB_CODE_PATH).'session/index.php?session_id='.$sessionId;
6596
        }
6597
    }
6598
6599
    // if not valid combination was found, return an empty string
6600
    return $url;
6601
}
6602
6603
/**
6604
 * Check if the current portal has the $_configuration['multiple_access_urls'] parameter on.
6605
 *
6606
 * @return bool true if multi site is enabled
6607
 */
6608
function api_get_multiple_access_url()
6609
{
6610
    global $_configuration;
6611
    if (isset($_configuration['multiple_access_urls']) && $_configuration['multiple_access_urls']) {
6612
        return true;
6613
    }
6614
6615
    return false;
6616
}
6617
6618
/**
6619
 * @return bool
6620
 */
6621
function api_is_multiple_url_enabled()
6622
{
6623
    return api_get_multiple_access_url();
6624
}
6625
6626
/**
6627
 * Returns a md5 unique id.
6628
 *
6629
 * @todo add more parameters
6630
 */
6631
function api_get_unique_id()
6632
{
6633
    $id = md5(time().uniqid().api_get_user_id().api_get_course_id().api_get_session_id());
6634
6635
    return $id;
6636
}
6637
6638
/**
6639
 * @param int Course id
6640
 * @param int tool id: TOOL_QUIZ, TOOL_FORUM, TOOL_STUDENTPUBLICATION, TOOL_LEARNPATH
6641
 * @param int the item id (tool id, exercise id, lp id)
6642
 *
6643
 * @return bool
6644
 */
6645
function api_resource_is_locked_by_gradebook($item_id, $link_type, $course_code = null)
6646
{
6647
    if (api_is_platform_admin()) {
6648
        return false;
6649
    }
6650
    if ('true' == api_get_setting('gradebook_locking_enabled')) {
6651
        if (empty($course_code)) {
6652
            $course_code = api_get_course_id();
6653
        }
6654
        $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_LINK);
6655
        $item_id = (int) $item_id;
6656
        $link_type = (int) $link_type;
6657
        $course_code = Database::escape_string($course_code);
6658
        $sql = "SELECT locked FROM $table
6659
                WHERE locked = 1 AND ref_id = $item_id AND type = $link_type AND course_code = '$course_code' ";
6660
        $result = Database::query($sql);
6661
        if (Database::num_rows($result)) {
6662
            return true;
6663
        }
6664
    }
6665
6666
    return false;
6667
}
6668
6669
/**
6670
 * Blocks a page if the item was added in a gradebook.
6671
 *
6672
 * @param int       exercise id, work id, thread id,
6673
 * @param int       LINK_EXERCISE, LINK_STUDENTPUBLICATION, LINK_LEARNPATH LINK_FORUM_THREAD, LINK_ATTENDANCE
6674
 * see gradebook/lib/be/linkfactory
6675
 * @param string    course code
6676
 *
6677
 * @return false|null
6678
 */
6679
function api_block_course_item_locked_by_gradebook($item_id, $link_type, $course_code = null)
6680
{
6681
    if (api_is_platform_admin()) {
6682
        return false;
6683
    }
6684
6685
    if (api_resource_is_locked_by_gradebook($item_id, $link_type, $course_code)) {
6686
        $message = Display::return_message(get_lang('This option is not available because this activity is contained by an assessment, which is currently locked. To unlock the assessment, ask your platform administrator.'), 'warning');
6687
        api_not_allowed(true, $message);
6688
    }
6689
}
6690
6691
/**
6692
 * Checks the PHP version installed is enough to run Chamilo.
6693
 *
6694
 * @param string Include path (used to load the error page)
6695
 */
6696
function api_check_php_version()
6697
{
6698
    if (!function_exists('version_compare') ||
6699
        version_compare(phpversion(), REQUIRED_PHP_VERSION, '<')
6700
    ) {
6701
        throw new Exception('Wrong PHP version');
6702
    }
6703
}
6704
6705
/**
6706
 * Checks whether the Archive directory is present and writeable. If not,
6707
 * prints a warning message.
6708
 */
6709
function api_check_archive_dir()
6710
{
6711
    if (is_dir(api_get_path(SYS_ARCHIVE_PATH)) && !is_writable(api_get_path(SYS_ARCHIVE_PATH))) {
6712
        $message = Display::return_message(get_lang('The app/cache/ directory, used by this tool, is not writeable. Please contact your platform administrator.'), 'warning');
6713
        api_not_allowed(true, $message);
6714
    }
6715
}
6716
6717
/**
6718
 * Returns an array of global configuration settings which should be ignored
6719
 * when printing the configuration settings screens.
6720
 *
6721
 * @return array Array of strings, each identifying one of the excluded settings
6722
 */
6723
function api_get_locked_settings()
6724
{
6725
    return [
6726
        'permanently_remove_deleted_files',
6727
        'account_valid_duration',
6728
        'service_ppt2lp',
6729
        'wcag_anysurfer_public_pages',
6730
        'upload_extensions_list_type',
6731
        'upload_extensions_blacklist',
6732
        'upload_extensions_whitelist',
6733
        'upload_extensions_skip',
6734
        'upload_extensions_replace_by',
6735
        'hide_dltt_markup',
6736
        'split_users_upload_directory',
6737
        'permissions_for_new_directories',
6738
        'permissions_for_new_files',
6739
        'platform_charset',
6740
        'ldap_description',
6741
        'cas_activate',
6742
        'cas_server',
6743
        'cas_server_uri',
6744
        'cas_port',
6745
        'cas_protocol',
6746
        'cas_add_user_activate',
6747
        'update_user_info_cas_with_ldap',
6748
        'languagePriority1',
6749
        'languagePriority2',
6750
        'languagePriority3',
6751
        'languagePriority4',
6752
        'login_is_email',
6753
        'chamilo_database_version',
6754
    ];
6755
}
6756
6757
/**
6758
 * Guess the real ip for register in the database, even in reverse proxy cases.
6759
 * To be recognized, the IP has to be found in either $_SERVER['REMOTE_ADDR'] or
6760
 * in $_SERVER['HTTP_X_FORWARDED_FOR'], which is in common use with rproxies.
6761
 * Note: the result of this function is not SQL-safe. Please escape it before
6762
 * inserting in a database.
6763
 *
6764
 * @return string the user's real ip (unsafe - escape it before inserting to db)
6765
 *
6766
 * @author Jorge Frisancho Jibaja <[email protected]>, USIL - Some changes to allow the use of real IP using reverse proxy
6767
 *
6768
 * @version CEV CHANGE 24APR2012
6769
 */
6770
function api_get_real_ip()
6771
{
6772
    $ip = trim($_SERVER['REMOTE_ADDR']);
6773
    if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
6774
        if (preg_match('/,/', $_SERVER['HTTP_X_FORWARDED_FOR'])) {
6775
            @list($ip1, $ip2) = @explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
6776
        } else {
6777
            $ip1 = $_SERVER['HTTP_X_FORWARDED_FOR'];
6778
        }
6779
        $ip = trim($ip1);
6780
    }
6781
6782
    return $ip;
6783
}
6784
6785
/**
6786
 * Checks whether an IP is included inside an IP range.
6787
 *
6788
 * @param string IP address
6789
 * @param string IP range
6790
 * @param string $ip
6791
 *
6792
 * @return bool True if IP is in the range, false otherwise
6793
 *
6794
 * @author claudiu at cnixs dot com  on http://www.php.net/manual/fr/ref.network.php#55230
6795
 * @author Yannick Warnier for improvements and managment of multiple ranges
6796
 *
6797
 * @todo check for IPv6 support
6798
 */
6799
function api_check_ip_in_range($ip, $range)
6800
{
6801
    if (empty($ip) or empty($range)) {
6802
        return false;
6803
    }
6804
    $ip_ip = ip2long($ip);
6805
    // divide range param into array of elements
6806
    if (false !== strpos($range, ',')) {
6807
        $ranges = explode(',', $range);
6808
    } else {
6809
        $ranges = [$range];
6810
    }
6811
    foreach ($ranges as $range) {
0 ignored issues
show
introduced by
$range is overwriting one of the parameters of this function.
Loading history...
6812
        $range = trim($range);
6813
        if (empty($range)) {
6814
            continue;
6815
        }
6816
        if (false === strpos($range, '/')) {
6817
            if (0 === strcmp($ip, $range)) {
6818
                return true; // there is a direct IP match, return OK
6819
            }
6820
            continue; //otherwise, get to the next range
6821
        }
6822
        // the range contains a "/", so analyse completely
6823
        [$net, $mask] = explode("/", $range);
6824
6825
        $ip_net = ip2long($net);
6826
        // mask binary magic
6827
        $ip_mask = ~((1 << (32 - $mask)) - 1);
6828
6829
        $ip_ip_net = $ip_ip & $ip_mask;
6830
        if ($ip_ip_net == $ip_net) {
6831
            return true;
6832
        }
6833
    }
6834
6835
    return false;
6836
}
6837
6838
function api_check_user_access_to_legal($course_visibility)
6839
{
6840
    $course_visibility_list = [COURSE_VISIBILITY_OPEN_WORLD, COURSE_VISIBILITY_OPEN_PLATFORM];
6841
6842
    return in_array($course_visibility, $course_visibility_list) || api_is_drh();
6843
}
6844
6845
/**
6846
 * Checks if the global chat is enabled or not.
6847
 *
6848
 * @return bool
6849
 */
6850
function api_is_global_chat_enabled()
6851
{
6852
    return
6853
        !api_is_anonymous() &&
6854
        'true' === api_get_setting('allow_global_chat') &&
6855
        'true' === api_get_setting('allow_social_tool');
6856
}
6857
6858
/**
6859
 * @param int   $item_id
6860
 * @param int   $tool_id
6861
 * @param int   $group_id   id
6862
 * @param array $courseInfo
6863
 * @param int   $sessionId
6864
 * @param int   $userId
6865
 *
6866
 * @deprecated
6867
 */
6868
function api_set_default_visibility(
6869
    $item_id,
6870
    $tool_id,
6871
    $group_id = 0,
6872
    $courseInfo = [],
6873
    $sessionId = 0,
6874
    $userId = 0
6875
) {
6876
    $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
6877
    $courseId = $courseInfo['real_id'];
6878
    $courseCode = $courseInfo['code'];
6879
    $sessionId = empty($sessionId) ? api_get_session_id() : $sessionId;
6880
    $userId = empty($userId) ? api_get_user_id() : $userId;
6881
6882
    // if group is null force group_id = 0, this force is needed to create a LP folder with group = 0
6883
    if (is_null($group_id)) {
6884
        $group_id = 0;
6885
    } else {
6886
        $group_id = empty($group_id) ? api_get_group_id() : $group_id;
6887
    }
6888
6889
    $groupInfo = [];
6890
    if (!empty($group_id)) {
6891
        $groupInfo = GroupManager::get_group_properties($group_id);
6892
    }
6893
    $original_tool_id = $tool_id;
6894
6895
    switch ($tool_id) {
6896
        case TOOL_LINK:
6897
        case TOOL_LINK_CATEGORY:
6898
            $tool_id = 'links';
6899
            break;
6900
        case TOOL_DOCUMENT:
6901
            $tool_id = 'documents';
6902
            break;
6903
        case TOOL_LEARNPATH:
6904
            $tool_id = 'learning';
6905
            break;
6906
        case TOOL_ANNOUNCEMENT:
6907
            $tool_id = 'announcements';
6908
            break;
6909
        case TOOL_FORUM:
6910
        case TOOL_FORUM_CATEGORY:
6911
        case TOOL_FORUM_THREAD:
6912
            $tool_id = 'forums';
6913
            break;
6914
        case TOOL_QUIZ:
6915
            $tool_id = 'quiz';
6916
            break;
6917
    }
6918
    $setting = api_get_setting('tool_visible_by_default_at_creation');
6919
6920
    if (isset($setting[$tool_id])) {
6921
        $visibility = 'invisible';
6922
        if ('true' == $setting[$tool_id]) {
6923
            $visibility = 'visible';
6924
        }
6925
6926
        // Read the portal and course default visibility
6927
        if ('documents' === $tool_id) {
6928
            $visibility = DocumentManager::getDocumentDefaultVisibility($courseInfo);
6929
        }
6930
6931
        // Fixes default visibility for tests
6932
        switch ($original_tool_id) {
6933
            case TOOL_QUIZ:
6934
                if (empty($sessionId)) {
6935
                    $objExerciseTmp = new Exercise($courseId);
6936
                    $objExerciseTmp->read($item_id);
6937
                    if ('visible' == $visibility) {
6938
                        $objExerciseTmp->enable();
6939
                        $objExerciseTmp->save();
6940
                    } else {
6941
                        $objExerciseTmp->disable();
6942
                        $objExerciseTmp->save();
6943
                    }
6944
                }
6945
                break;
6946
        }
6947
    }
6948
}
6949
6950
/**
6951
 * @return string
6952
 */
6953
function api_get_security_key()
6954
{
6955
    return api_get_configuration_value('security_key');
0 ignored issues
show
Bug Best Practice introduced by
The expression return api_get_configura...n_value('security_key') also could return the type boolean which is incompatible with the documented return type string.
Loading history...
6956
}
6957
6958
/**
6959
 * @param int $user_id
6960
 * @param int $courseId
6961
 * @param int $session_id
6962
 *
6963
 * @return array
6964
 */
6965
function api_detect_user_roles($user_id, $courseId, $session_id = 0)
6966
{
6967
    $user_roles = [];
6968
    $courseInfo = api_get_course_info_by_id($courseId);
6969
    $course_code = $courseInfo['code'];
6970
6971
    $url_id = api_get_current_access_url_id();
6972
    if (api_is_platform_admin_by_id($user_id, $url_id)) {
6973
        $user_roles[] = PLATFORM_ADMIN;
6974
    }
6975
6976
    /*if (api_is_drh()) {
6977
        $user_roles[] = DRH;
6978
    }*/
6979
6980
    if (!empty($session_id)) {
6981
        if (SessionManager::user_is_general_coach($user_id, $session_id)) {
6982
            $user_roles[] = SESSION_GENERAL_COACH;
6983
        }
6984
    }
6985
6986
    if (!empty($course_code)) {
6987
        if (empty($session_id)) {
6988
            if (CourseManager::isCourseTeacher($user_id, $courseInfo['real_id'])) {
6989
                $user_roles[] = COURSEMANAGER;
6990
            }
6991
            if (CourseManager::get_tutor_in_course_status($user_id, $courseInfo['real_id'])) {
6992
                $user_roles[] = COURSE_TUTOR;
6993
            }
6994
6995
            if (CourseManager::is_user_subscribed_in_course($user_id, $course_code)) {
6996
                $user_roles[] = COURSE_STUDENT;
6997
            }
6998
        } else {
6999
            $user_status_in_session = SessionManager::get_user_status_in_course_session(
7000
                $user_id,
7001
                $courseId,
7002
                $session_id
7003
            );
7004
7005
            if (!empty($user_status_in_session)) {
7006
                if (0 == $user_status_in_session) {
7007
                    $user_roles[] = SESSION_STUDENT;
7008
                }
7009
                if (2 == $user_status_in_session) {
7010
                    $user_roles[] = SESSION_COURSE_COACH;
7011
                }
7012
            }
7013
7014
            /*if (api_is_course_session_coach($user_id, $course_code, $session_id)) {
7015
               $user_roles[] = SESSION_COURSE_COACH;
7016
            }*/
7017
        }
7018
    }
7019
7020
    return $user_roles;
7021
}
7022
7023
/**
7024
 * @param int $courseId
7025
 * @param int $session_id
7026
 *
7027
 * @return bool
7028
 */
7029
function api_coach_can_edit_view_results($courseId = null, $session_id = null)
7030
{
7031
    if (api_is_platform_admin()) {
7032
        return true;
7033
    }
7034
7035
    $user_id = api_get_user_id();
7036
7037
    if (empty($courseId)) {
7038
        $courseId = api_get_course_int_id();
7039
    }
7040
7041
    if (empty($session_id)) {
7042
        $session_id = api_get_session_id();
7043
    }
7044
7045
    $roles = api_detect_user_roles($user_id, $courseId, $session_id);
7046
7047
    if (in_array(SESSION_COURSE_COACH, $roles)) {
7048
        //return api_get_setting('session_tutor_reports_visibility') == 'true';
7049
        return true;
7050
    } else {
7051
        if (in_array(COURSEMANAGER, $roles)) {
7052
            return true;
7053
        }
7054
7055
        return false;
7056
    }
7057
}
7058
7059
/**
7060
 * @param string $file
7061
 *
7062
 * @return string
7063
 */
7064
function api_get_js_simple($file)
7065
{
7066
    return '<script type="text/javascript" src="'.$file.'"></script>'."\n";
7067
}
7068
7069
/**
7070
 * Modify default memory_limit and max_execution_time limits
7071
 * Needed when processing long tasks.
7072
 */
7073
function api_set_more_memory_and_time_limits()
7074
{
7075
    if (function_exists('ini_set')) {
7076
        api_set_memory_limit('256M');
7077
        ini_set('max_execution_time', 1800);
7078
    }
7079
}
7080
7081
/**
7082
 * Tries to set memory limit, if authorized and new limit is higher than current.
7083
 *
7084
 * @param string $mem New memory limit
7085
 *
7086
 * @return bool True on success, false on failure or current is higher than suggested
7087
 * @assert (null) === false
7088
 * @assert (-1) === false
7089
 * @assert (0) === true
7090
 * @assert ('1G') === true
7091
 */
7092
function api_set_memory_limit($mem)
7093
{
7094
    //if ini_set() not available, this function is useless
7095
    if (!function_exists('ini_set') || is_null($mem) || -1 == $mem) {
7096
        return false;
7097
    }
7098
7099
    $memory_limit = ini_get('memory_limit');
7100
    if (api_get_bytes_memory_limit($mem) > api_get_bytes_memory_limit($memory_limit)) {
7101
        ini_set('memory_limit', $mem);
7102
7103
        return true;
7104
    }
7105
7106
    return false;
7107
}
7108
7109
/**
7110
 * Gets memory limit in bytes.
7111
 *
7112
 * @param string The memory size (128M, 1G, 1000K, etc)
7113
 *
7114
 * @return int
7115
 * @assert (null) === false
7116
 * @assert ('1t')  === 1099511627776
7117
 * @assert ('1g')  === 1073741824
7118
 * @assert ('1m')  === 1048576
7119
 * @assert ('100k') === 102400
7120
 */
7121
function api_get_bytes_memory_limit($mem)
7122
{
7123
    $size = strtolower(substr($mem, -1));
7124
7125
    switch ($size) {
7126
        case 't':
7127
            $mem = intval(substr($mem, -1)) * 1024 * 1024 * 1024 * 1024;
7128
            break;
7129
        case 'g':
7130
            $mem = intval(substr($mem, 0, -1)) * 1024 * 1024 * 1024;
7131
            break;
7132
        case 'm':
7133
            $mem = intval(substr($mem, 0, -1)) * 1024 * 1024;
7134
            break;
7135
        case 'k':
7136
            $mem = intval(substr($mem, 0, -1)) * 1024;
7137
            break;
7138
        default:
7139
            // we assume it's integer only
7140
            $mem = intval($mem);
7141
            break;
7142
    }
7143
7144
    return $mem;
7145
}
7146
7147
/**
7148
 * Finds all the information about a user from username instead of user id.
7149
 *
7150
 * @param string $officialCode
7151
 *
7152
 * @return array $user_info user_id, lastname, firstname, username, email, ...
7153
 *
7154
 * @author Yannick Warnier <[email protected]>
7155
 */
7156
function api_get_user_info_from_official_code($officialCode)
7157
{
7158
    if (empty($officialCode)) {
7159
        return false;
7160
    }
7161
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
7162
            WHERE official_code ='".Database::escape_string($officialCode)."'";
7163
    $result = Database::query($sql);
7164
    if (Database::num_rows($result) > 0) {
7165
        $result_array = Database::fetch_array($result);
7166
7167
        return _api_format_user($result_array);
7168
    }
7169
7170
    return false;
7171
}
7172
7173
/**
7174
 * @param string $usernameInputId
7175
 * @param string $passwordInputId
7176
 *
7177
 * @return string|null
7178
 */
7179
function api_get_password_checker_js($usernameInputId, $passwordInputId)
7180
{
7181
    $checkPass = api_get_setting('allow_strength_pass_checker');
7182
    $useStrengthPassChecker = 'true' === $checkPass;
7183
7184
    if (false === $useStrengthPassChecker) {
7185
        return null;
7186
    }
7187
7188
    $translations = [
7189
        'wordLength' => get_lang('The password is too short'),
7190
        'wordNotEmail' => get_lang('Your password cannot be the same as your email'),
7191
        'wordSimilarToUsername' => get_lang('Your password cannot contain your username'),
7192
        'wordTwoCharacterClasses' => get_lang('Use different character classes'),
7193
        'wordRepetitions' => get_lang('Too many repetitions'),
7194
        'wordSequences' => get_lang('Your password contains sequences'),
7195
        'errorList' => get_lang('errors found'),
7196
        'veryWeak' => get_lang('Very weak'),
7197
        'weak' => get_lang('Weak'),
7198
        'normal' => get_lang('Normal'),
7199
        'medium' => get_lang('Medium'),
7200
        'strong' => get_lang('Strong'),
7201
        'veryStrong' => get_lang('Very strong'),
7202
    ];
7203
7204
    $js = api_get_asset('pwstrength-bootstrap/dist/pwstrength-bootstrap.js');
7205
    $js .= "<script>
7206
    var errorMessages = {
7207
        password_to_short : \"".get_lang('The password is too short')."\",
7208
        same_as_username : \"".get_lang('Your password cannot be the same as your username')."\"
7209
    };
7210
7211
    $(function() {
7212
        var lang = ".json_encode($translations).";
7213
        var options = {
7214
            onLoad : function () {
7215
                //$('#messages').text('Start typing password');
7216
            },
7217
            onKeyUp: function (evt) {
7218
                $(evt.target).pwstrength('outputErrorList');
7219
            },
7220
            errorMessages : errorMessages,
7221
            viewports: {
7222
                progress: '#password_progress',
7223
                verdict: '#password-verdict',
7224
                errors: '#password-errors'
7225
            },
7226
            usernameField: '$usernameInputId'
7227
        };
7228
        options.i18n = {
7229
            t: function (key) {
7230
                var result = lang[key];
7231
                return result === key ? '' : result; // This assumes you return the
7232
            }
7233
        };
7234
        $('".$passwordInputId."').pwstrength(options);
7235
    });
7236
    </script>";
7237
7238
    return $js;
7239
}
7240
7241
/**
7242
 * create an user extra field called 'captcha_blocked_until_date'.
7243
 *
7244
 * @param string $username
7245
 *
7246
 * @return bool
7247
 */
7248
function api_block_account_captcha($username)
7249
{
7250
    $userInfo = api_get_user_info_from_username($username);
7251
    if (empty($userInfo)) {
7252
        return false;
7253
    }
7254
    $minutesToBlock = api_get_setting('captcha_time_to_block');
7255
    $time = time() + $minutesToBlock * 60;
7256
    UserManager::update_extra_field_value(
7257
        $userInfo['user_id'],
7258
        'captcha_blocked_until_date',
7259
        api_get_utc_datetime($time)
7260
    );
7261
7262
    return true;
7263
}
7264
7265
/**
7266
 * @param string $username
7267
 *
7268
 * @return bool
7269
 */
7270
function api_clean_account_captcha($username)
7271
{
7272
    $userInfo = api_get_user_info_from_username($username);
7273
    if (empty($userInfo)) {
7274
        return false;
7275
    }
7276
    Session::erase('loginFailedCount');
7277
    UserManager::update_extra_field_value(
7278
        $userInfo['user_id'],
7279
        'captcha_blocked_until_date',
7280
        null
7281
    );
7282
7283
    return true;
7284
}
7285
7286
/**
7287
 * @param string $username
7288
 *
7289
 * @return bool
7290
 */
7291
function api_get_user_blocked_by_captcha($username)
7292
{
7293
    $userInfo = api_get_user_info_from_username($username);
7294
    if (empty($userInfo)) {
7295
        return false;
7296
    }
7297
    $data = UserManager::get_extra_user_data_by_field(
7298
        $userInfo['user_id'],
7299
        'captcha_blocked_until_date'
7300
    );
7301
    if (isset($data) && isset($data['captcha_blocked_until_date'])) {
7302
        return $data['captcha_blocked_until_date'];
7303
    }
7304
7305
    return false;
7306
}
7307
7308
/**
7309
 * Remove tags from HTML anf return the $in_number_char first non-HTML char
7310
 * Postfix the text with "..." if it has been truncated.
7311
 *
7312
 * @param string $text
7313
 * @param int    $number
7314
 *
7315
 * @return string
7316
 *
7317
 * @author hubert borderiou
7318
 */
7319
function api_get_short_text_from_html($text, $number)
7320
{
7321
    // Delete script and style tags
7322
    $text = preg_replace('/(<(script|style)\b[^>]*>).*?(<\/\2>)/is', "$1$3", $text);
7323
    $text = api_html_entity_decode($text);
7324
    $out_res = api_remove_tags_with_space($text, false);
7325
    $postfix = "...";
7326
    if (strlen($out_res) > $number) {
7327
        $out_res = substr($out_res, 0, $number).$postfix;
7328
    }
7329
7330
    return $out_res;
7331
}
7332
7333
/**
7334
 * Replace tags with a space in a text.
7335
 * If $in_double_quote_replace, replace " with '' (for HTML attribute purpose, for exemple).
7336
 *
7337
 * @return string
7338
 *
7339
 * @author hubert borderiou
7340
 */
7341
function api_remove_tags_with_space($in_html, $in_double_quote_replace = true)
7342
{
7343
    $out_res = $in_html;
7344
    if ($in_double_quote_replace) {
7345
        $out_res = str_replace('"', "''", $out_res);
7346
    }
7347
    // avoid text stuck together when tags are removed, adding a space after >
7348
    $out_res = str_replace(">", "> ", $out_res);
7349
    $out_res = strip_tags($out_res);
7350
7351
    return $out_res;
7352
}
7353
7354
/**
7355
 * If true, the drh can access all content (courses, users) inside a session.
7356
 *
7357
 * @return bool
7358
 */
7359
function api_drh_can_access_all_session_content()
7360
{
7361
    return 'true' === api_get_setting('drh_can_access_all_session_content');
7362
}
7363
7364
/**
7365
 * @param string $tool
7366
 * @param string $setting
7367
 * @param int    $defaultValue
7368
 *
7369
 * @return string
7370
 */
7371
function api_get_default_tool_setting($tool, $setting, $defaultValue)
7372
{
7373
    global $_configuration;
7374
    if (isset($_configuration[$tool]) &&
7375
        isset($_configuration[$tool]['default_settings']) &&
7376
        isset($_configuration[$tool]['default_settings'][$setting])
7377
    ) {
7378
        return $_configuration[$tool]['default_settings'][$setting];
7379
    }
7380
7381
    return $defaultValue;
7382
}
7383
7384
/**
7385
 * Checks if user can login as another user.
7386
 *
7387
 * @param int $loginAsUserId the user id to log in
7388
 * @param int $userId        my user id
7389
 *
7390
 * @return bool
7391
 */
7392
function api_can_login_as($loginAsUserId, $userId = null)
7393
{
7394
    $loginAsUserId = (int) $loginAsUserId;
7395
7396
    if (empty($loginAsUserId)) {
7397
        return false;
7398
    }
7399
7400
    if (empty($userId)) {
7401
        $userId = api_get_user_id();
7402
    }
7403
7404
    if ($loginAsUserId == $userId) {
7405
        return false;
7406
    }
7407
7408
    // Check if the user to login is an admin
7409
    if (api_is_platform_admin_by_id($loginAsUserId)) {
7410
        // Only super admins can login to admin accounts
7411
        if (!api_global_admin_can_edit_admin($loginAsUserId)) {
7412
            return false;
7413
        }
7414
    }
7415
7416
    $userInfo = api_get_user_info($loginAsUserId);
7417
    $isDrh = function () use ($loginAsUserId) {
7418
        if (api_is_drh()) {
7419
            if (api_drh_can_access_all_session_content()) {
7420
                $users = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus(
7421
                    'drh_all',
7422
                    api_get_user_id()
7423
                );
7424
                $userList = [];
7425
                if (is_array($users)) {
7426
                    foreach ($users as $user) {
7427
                        $userList[] = $user['id'];
7428
                    }
7429
                }
7430
                if (in_array($loginAsUserId, $userList)) {
7431
                    return true;
7432
                }
7433
            } else {
7434
                if (api_is_drh() &&
7435
                    UserManager::is_user_followed_by_drh($loginAsUserId, api_get_user_id())
7436
                ) {
7437
                    return true;
7438
                }
7439
            }
7440
        }
7441
7442
        return false;
7443
    };
7444
7445
    $loginAsStatusForSessionAdmins = [STUDENT];
7446
7447
    if (api_get_setting('session.allow_session_admin_login_as_teacher')) {
7448
        $loginAsStatusForSessionAdmins[] = COURSEMANAGER;
7449
    }
7450
7451
    return api_is_platform_admin() ||
7452
        (api_is_session_admin() && in_array($userInfo['status'], $loginAsStatusForSessionAdmins)) ||
7453
        $isDrh();
7454
}
7455
7456
/**
7457
 * @return bool
7458
 */
7459
function api_is_allowed_in_course()
7460
{
7461
    if (api_is_platform_admin()) {
7462
        return true;
7463
    }
7464
7465
    $user = api_get_current_user();
7466
    if ($user instanceof User) {
7467
        if ($user->hasRole('ROLE_CURRENT_SESSION_COURSE_STUDENT') ||
7468
            $user->hasRole('ROLE_CURRENT_SESSION_COURSE_TEACHER') ||
7469
            $user->hasRole('ROLE_CURRENT_COURSE_STUDENT') ||
7470
            $user->hasRole('ROLE_CURRENT_COURSE_TEACHER')
7471
        ) {
7472
            return true;
7473
        }
7474
    }
7475
7476
    return false;
7477
}
7478
7479
/**
7480
 * Return true on https install.
7481
 *
7482
 * @return bool
7483
 */
7484
function api_is_https()
7485
{
7486
    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...
7487
        'https' == $_SERVER['HTTP_X_FORWARDED_PROTO'] || !empty(api_get_configuration_value('force_https_forwarded_proto'))
7488
    ) {
7489
        $isSecured = true;
7490
    } else {
7491
        if (!empty($_SERVER['HTTPS']) && 'off' != $_SERVER['HTTPS']) {
7492
            $isSecured = true;
7493
        } else {
7494
            $isSecured = false;
7495
            // last chance
7496
            if (!empty($_SERVER['SERVER_PORT']) && 443 == $_SERVER['SERVER_PORT']) {
7497
                $isSecured = true;
7498
            }
7499
        }
7500
    }
7501
7502
    return $isSecured;
7503
}
7504
7505
/**
7506
 * Return protocol (http or https).
7507
 *
7508
 * @return string
7509
 */
7510
function api_get_protocol()
7511
{
7512
    return api_is_https() ? 'https' : 'http';
7513
}
7514
7515
/**
7516
 * Return a string where " are replaced with 2 '
7517
 * It is useful when you pass a PHP variable in a Javascript browser dialog
7518
 * e.g. : alert("<?php get_lang('Message') ?>");
7519
 * and message contains character ".
7520
 *
7521
 * @param string $in_text
7522
 *
7523
 * @return string
7524
 */
7525
function convert_double_quote_to_single($in_text)
7526
{
7527
    return api_preg_replace('/"/', "''", $in_text);
7528
}
7529
7530
/**
7531
 * Get origin.
7532
 *
7533
 * @param string
7534
 *
7535
 * @return string
7536
 */
7537
function api_get_origin()
7538
{
7539
    return isset($_REQUEST['origin']) ? Security::remove_XSS($_REQUEST['origin']) : '';
7540
}
7541
7542
/**
7543
 * Warns an user that the portal reach certain limit.
7544
 *
7545
 * @param string $limitName
7546
 */
7547
function api_warn_hosting_contact($limitName)
7548
{
7549
    $hostingParams = api_get_configuration_value(1);
7550
    $email = null;
7551
7552
    if (!empty($hostingParams)) {
7553
        if (isset($hostingParams['hosting_contact_mail'])) {
7554
            $email = $hostingParams['hosting_contact_mail'];
7555
        }
7556
    }
7557
7558
    if (!empty($email)) {
7559
        $subject = get_lang('Hosting warning reached');
7560
        $body = get_lang('Portal name').': '.api_get_path(WEB_PATH)." \n ";
7561
        $body .= get_lang('Portal\'s limit type').': '.$limitName." \n ";
7562
        if (isset($hostingParams[$limitName])) {
7563
            $body .= get_lang('Value').': '.$hostingParams[$limitName];
7564
        }
7565
        api_mail_html(null, $email, $subject, $body);
7566
    }
7567
}
7568
7569
/**
7570
 * Gets value of a variable from config/configuration.php
7571
 * Variables that are not set in the configuration.php file but set elsewhere:
7572
 * - virtual_css_theme_folder (vchamilo plugin)
7573
 * - access_url (global.inc.php)
7574
 * - apc/apc_prefix (global.inc.php).
7575
 *
7576
 * @param string $variable
7577
 *
7578
 * @return bool|mixed
7579
 */
7580
function api_get_configuration_value($variable)
7581
{
7582
    global $_configuration;
7583
    // Check the current url id, id = 1 by default
7584
    $urlId = isset($_configuration['access_url']) ? (int) $_configuration['access_url'] : 1;
7585
7586
    $variable = trim($variable);
7587
7588
    // Check if variable exists
7589
    if (isset($_configuration[$variable])) {
7590
        if (is_array($_configuration[$variable])) {
7591
            // Check if it exists for the sub portal
7592
            if (array_key_exists($urlId, $_configuration[$variable])) {
7593
                return $_configuration[$variable][$urlId];
7594
            } else {
7595
                // Try to found element with id = 1 (master portal)
7596
                if (array_key_exists(1, $_configuration[$variable])) {
7597
                    return $_configuration[$variable][1];
7598
                }
7599
            }
7600
        }
7601
7602
        return $_configuration[$variable];
7603
    }
7604
7605
    return false;
7606
}
7607
7608
/**
7609
 * Retreives and returns a value in a hierarchical configuration array
7610
 * api_get_configuration_sub_value('a/b/c') returns api_get_configuration_value('a')['b']['c'].
7611
 *
7612
 * @param string $path      the successive array keys, separated by the separator
7613
 * @param mixed  $default   value to be returned if not found, null by default
7614
 * @param string $separator '/' by default
7615
 * @param array  $array     the active configuration array by default
7616
 *
7617
 * @return mixed the found value or $default
7618
 */
7619
function api_get_configuration_sub_value($path, $default = null, $separator = '/', $array = null)
7620
{
7621
    $pos = strpos($path, $separator);
7622
    if (false === $pos) {
7623
        if (is_null($array)) {
7624
            return api_get_configuration_value($path);
7625
        }
7626
        if (is_array($array) && array_key_exists($path, $array)) {
7627
            return $array[$path];
7628
        }
7629
7630
        return $default;
7631
    }
7632
    $key = substr($path, 0, $pos);
7633
    if (is_null($array)) {
7634
        $newArray = api_get_configuration_value($key);
7635
    } elseif (is_array($array) && array_key_exists($key, $array)) {
7636
        $newArray = $array[$key];
7637
    } else {
7638
        return $default;
7639
    }
7640
    if (is_array($newArray)) {
7641
        $newPath = substr($path, $pos + 1);
7642
7643
        return api_get_configuration_sub_value($newPath, $default, $separator, $newArray);
7644
    }
7645
7646
    return $default;
7647
}
7648
7649
/**
7650
 * Retrieves and returns a value in a hierarchical configuration array
7651
 * api_array_sub_value($array, 'a/b/c') returns $array['a']['b']['c'].
7652
 *
7653
 * @param array  $array     the recursive array that contains the value to be returned (or not)
7654
 * @param string $path      the successive array keys, separated by the separator
7655
 * @param mixed  $default   the value to be returned if not found
7656
 * @param string $separator the separator substring
7657
 *
7658
 * @return mixed the found value or $default
7659
 */
7660
function api_array_sub_value($array, $path, $default = null, $separator = '/')
7661
{
7662
    $pos = strpos($path, $separator);
7663
    if (false === $pos) {
7664
        if (is_array($array) && array_key_exists($path, $array)) {
7665
            return $array[$path];
7666
        }
7667
7668
        return $default;
7669
    }
7670
    $key = substr($path, 0, $pos);
7671
    if (is_array($array) && array_key_exists($key, $array)) {
7672
        $newArray = $array[$key];
7673
    } else {
7674
        return $default;
7675
    }
7676
    if (is_array($newArray)) {
7677
        $newPath = substr($path, $pos + 1);
7678
7679
        return api_array_sub_value($newArray, $newPath, $default);
7680
    }
7681
7682
    return $default;
7683
}
7684
7685
/**
7686
 * Returns supported image extensions in the portal.
7687
 *
7688
 * @param bool $supportVectors Whether vector images should also be accepted or not
7689
 *
7690
 * @return array Supported image extensions in the portal
7691
 */
7692
function api_get_supported_image_extensions($supportVectors = true)
7693
{
7694
    // jpg can also be called jpeg, jpe, jfif and jif. See https://en.wikipedia.org/wiki/JPEG#JPEG_filename_extensions
7695
    $supportedImageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'jpe', 'jfif', 'jif'];
7696
    if ($supportVectors) {
7697
        array_push($supportedImageExtensions, 'svg');
7698
    }
7699
    if (version_compare(PHP_VERSION, '5.5.0', '>=')) {
7700
        array_push($supportedImageExtensions, 'webp');
7701
    }
7702
7703
    return $supportedImageExtensions;
7704
}
7705
7706
/**
7707
 * This setting changes the registration status for the campus.
7708
 *
7709
 * @author Patrick Cool <[email protected]>, Ghent University
7710
 *
7711
 * @version August 2006
7712
 *
7713
 * @param bool $listCampus Whether we authorize
7714
 *
7715
 * @todo the $_settings should be reloaded here. => write api function for this and use this in global.inc.php also.
7716
 */
7717
function api_register_campus($listCampus = true)
7718
{
7719
    $tbl_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
7720
7721
    $sql = "UPDATE $tbl_settings SET selected_value='true' WHERE variable='registered'";
7722
    Database::query($sql);
7723
7724
    if (!$listCampus) {
7725
        $sql = "UPDATE $tbl_settings SET selected_value='true' WHERE variable='donotlistcampus'";
7726
        Database::query($sql);
7727
    }
7728
}
7729
7730
/**
7731
 * Checks whether current user is a student boss.
7732
 *
7733
 * @global array $_user
7734
 *
7735
 * @return bool
7736
 */
7737
function api_is_student_boss()
7738
{
7739
    $_user = api_get_user_info();
7740
7741
    return isset($_user['status']) && STUDENT_BOSS == $_user['status'];
7742
}
7743
7744
/**
7745
 * Check whether the user type should be exclude.
7746
 * Such as invited or anonymous users.
7747
 *
7748
 * @param bool $checkDB Optional. Whether check the user status
7749
 * @param int  $userId  Options. The user id
7750
 *
7751
 * @return bool
7752
 */
7753
function api_is_excluded_user_type($checkDB = false, $userId = 0)
7754
{
7755
    if ($checkDB) {
7756
        $userId = empty($userId) ? api_get_user_id() : (int) $userId;
7757
7758
        if (0 == $userId) {
7759
            return true;
7760
        }
7761
7762
        $userInfo = api_get_user_info($userId);
7763
7764
        switch ($userInfo['status']) {
7765
            case INVITEE:
7766
            case ANONYMOUS:
7767
                return true;
7768
            default:
7769
                return false;
7770
        }
7771
    }
7772
7773
    $isInvited = api_is_invitee();
7774
    $isAnonymous = api_is_anonymous();
7775
7776
    if ($isInvited || $isAnonymous) {
7777
        return true;
7778
    }
7779
7780
    return false;
7781
}
7782
7783
/**
7784
 * Get the user status to ignore in reports.
7785
 *
7786
 * @param string $format Optional. The result type (array or string)
7787
 *
7788
 * @return array|string
7789
 */
7790
function api_get_users_status_ignored_in_reports($format = 'array')
7791
{
7792
    $excludedTypes = [
7793
        INVITEE,
7794
        ANONYMOUS,
7795
    ];
7796
7797
    if ('string' == $format) {
7798
        return implode(', ', $excludedTypes);
7799
    }
7800
7801
    return $excludedTypes;
7802
}
7803
7804
/**
7805
 * Set the Site Use Cookie Warning for 1 year.
7806
 */
7807
function api_set_site_use_cookie_warning_cookie()
7808
{
7809
    setcookie('ChamiloUsesCookies', 'ok', time() + 31556926);
7810
}
7811
7812
/**
7813
 * Return true if the Site Use Cookie Warning Cookie warning exists.
7814
 *
7815
 * @return bool
7816
 */
7817
function api_site_use_cookie_warning_cookie_exist()
7818
{
7819
    return isset($_COOKIE['ChamiloUsesCookies']);
7820
}
7821
7822
/**
7823
 * Given a number of seconds, format the time to show hours, minutes and seconds.
7824
 *
7825
 * @param int    $time         The time in seconds
7826
 * @param string $originFormat Optional. PHP o JS
7827
 *
7828
 * @return string (00h00'00")
7829
 */
7830
function api_format_time($time, $originFormat = 'php')
7831
{
7832
    $h = get_lang('h');
7833
    $hours = $time / 3600;
7834
    $mins = ($time % 3600) / 60;
7835
    $secs = ($time % 60);
7836
7837
    if ($time < 0) {
7838
        $hours = 0;
7839
        $mins = 0;
7840
        $secs = 0;
7841
    }
7842
7843
    if ('js' == $originFormat) {
7844
        $formattedTime = trim(sprintf("%02d : %02d : %02d", $hours, $mins, $secs));
7845
    } else {
7846
        $formattedTime = trim(sprintf("%02d$h%02d'%02d\"", $hours, $mins, $secs));
7847
    }
7848
7849
    return $formattedTime;
7850
}
7851
7852
/**
7853
 * Create a new empty directory with index.html file.
7854
 *
7855
 * @param string $name            The new directory name
7856
 * @param string $parentDirectory Directory parent directory name
7857
 *
7858
 * @deprecated use Resources
7859
 *
7860
 * @return bool Return true if the directory was create. Otherwise return false
7861
 */
7862
function api_create_protected_dir($name, $parentDirectory)
7863
{
7864
    $isCreated = false;
7865
7866
    if (!is_writable($parentDirectory)) {
7867
        return false;
7868
    }
7869
7870
    $fullPath = $parentDirectory.api_replace_dangerous_char($name);
7871
7872
    if (mkdir($fullPath, api_get_permissions_for_new_directories(), true)) {
7873
        $fp = fopen($fullPath.'/index.html', 'w');
7874
7875
        if ($fp) {
0 ignored issues
show
introduced by
$fp is of type false|resource, thus it always evaluated to false.
Loading history...
7876
            if (fwrite($fp, '<html><head></head><body></body></html>')) {
7877
                $isCreated = true;
7878
            }
7879
        }
7880
7881
        fclose($fp);
7882
    }
7883
7884
    return $isCreated;
7885
}
7886
7887
/**
7888
 * Sends an email
7889
 * Sender name and email can be specified, if not specified
7890
 * name and email of the platform admin are used.
7891
 *
7892
 * @param string    name of recipient
7893
 * @param string    email of recipient
7894
 * @param string    email subject
7895
 * @param string    email body
7896
 * @param string    sender name
7897
 * @param string    sender e-mail
7898
 * @param array     extra headers in form $headers = array($name => $value) to allow parsing
7899
 * @param array     data file (path and filename)
7900
 * @param bool      True for attaching a embedded file inside content html (optional)
7901
 * @param array     Additional parameters
7902
 *
7903
 * @return bool true if mail was sent
7904
 */
7905
function api_mail_html(
7906
    $recipientName,
7907
    $recipientEmail,
7908
    $subject,
7909
    $body,
7910
    $senderName = '',
7911
    $senderEmail = '',
7912
    $extra_headers = [],
7913
    $data_file = [],
7914
    $embeddedImage = false,
7915
    $additionalParameters = []
7916
) {
7917
    if (!api_valid_email($recipientEmail)) {
7918
        return false;
7919
    }
7920
7921
    // Default values
7922
    $notification = new Notification();
7923
    $defaultEmail = $notification->getDefaultPlatformSenderEmail();
7924
    $defaultName = $notification->getDefaultPlatformSenderName();
7925
7926
    // If the parameter is set don't use the admin.
7927
    $senderName = !empty($senderName) ? $senderName : $defaultName;
7928
    $senderEmail = !empty($senderEmail) ? $senderEmail : $defaultEmail;
7929
7930
    // Reply to first
7931
    $replyToName = '';
7932
    $replyToEmail = '';
7933
    if (isset($extra_headers['reply_to'])) {
7934
        $replyToEmail = $extra_headers['reply_to']['mail'];
7935
        $replyToName = $extra_headers['reply_to']['name'];
7936
    }
7937
7938
    try {
7939
        $message = new TemplatedEmail();
7940
        $message->subject($subject);
7941
7942
        $list = api_get_configuration_value('send_all_emails_to');
7943
        if (!empty($list) && isset($list['emails'])) {
7944
            foreach ($list['emails'] as $email) {
7945
                $message->cc($email);
7946
            }
7947
        }
7948
7949
        // Attachment
7950
        if (!empty($data_file)) {
7951
            foreach ($data_file as $file_attach) {
7952
                if (!empty($file_attach['path']) && !empty($file_attach['filename'])) {
7953
                    $message->attachFromPath($file_attach['path'], $file_attach['filename']);
7954
                }
7955
            }
7956
        }
7957
7958
        $noReply = api_get_setting('noreply_email_address');
7959
        $automaticEmailText = '';
7960
        if (!empty($noReply)) {
7961
            $automaticEmailText = '<br />'.get_lang('This is an automatic email message. Please do not reply to it.');
7962
        }
7963
7964
        $params = [
7965
            'mail_header_style' => api_get_configuration_value('mail_header_style'),
7966
            'mail_content_style' => api_get_configuration_value('mail_content_style'),
7967
            'link' => $additionalParameters['link'] ?? '',
7968
            'automatic_email_text' => $automaticEmailText,
7969
            'content' => $body,
7970
            'theme' => api_get_visual_theme(),
7971
        ];
7972
7973
        if (!empty($senderEmail)) {
7974
            $message->from(new Address($senderEmail, $senderName));
7975
        }
7976
7977
        if (!empty($recipientEmail)) {
7978
            $message->to(new Address($recipientEmail, $recipientName));
7979
        }
7980
7981
        if (!empty($replyToEmail)) {
7982
            $message->replyTo(new Address($replyToEmail, $replyToName));
7983
        }
7984
7985
        $message
7986
            ->htmlTemplate('ChamiloCoreBundle:Mailer:Default/default.html.twig')
7987
            ->textTemplate('ChamiloCoreBundle:Mailer:Default/default.text.twig')
7988
        ;
7989
        $message->context($params);
7990
        Container::getMailer()->send($message);
7991
7992
        return true;
7993
    } catch (Exception $e) {
7994
        error_log($e->getMessage());
7995
    }
7996
7997
    if (!empty($additionalParameters)) {
7998
        $plugin = new AppPlugin();
7999
        $smsPlugin = $plugin->getSMSPluginLibrary();
8000
        if ($smsPlugin) {
0 ignored issues
show
introduced by
$smsPlugin is of type SmsPluginLibraryInterface, thus it always evaluated to true.
Loading history...
8001
            $smsPlugin->send($additionalParameters);
8002
        }
8003
    }
8004
8005
    return 1;
8006
}
8007
8008
/**
8009
 * @param string $tool       Possible values: GroupManager::GROUP_TOOL_*
8010
 * @param bool   $showHeader
8011
 */
8012
function api_protect_course_group($tool, $showHeader = true)
8013
{
8014
    $groupId = api_get_group_id();
8015
    if (!empty($groupId)) {
8016
        if (api_is_platform_admin()) {
8017
            return true;
8018
        }
8019
8020
        if (api_is_allowed_to_edit(false, true, true)) {
8021
            return true;
8022
        }
8023
8024
        $userId = api_get_user_id();
8025
        $sessionId = api_get_session_id();
8026
        if (!empty($sessionId)) {
8027
            if (api_is_coach($sessionId, api_get_course_int_id())) {
8028
                return true;
8029
            }
8030
8031
            if (api_is_drh()) {
8032
                if (SessionManager::isUserSubscribedAsHRM($sessionId, $userId)) {
8033
                    return true;
8034
                }
8035
            }
8036
        }
8037
8038
        $groupInfo = GroupManager::get_group_properties($groupId);
8039
8040
        // Group doesn't exists
8041
        if (empty($groupInfo)) {
8042
            api_not_allowed($showHeader);
8043
        }
8044
8045
        // Check group access
8046
        $allow = GroupManager::user_has_access(
8047
            $userId,
8048
            $groupInfo['iid'],
8049
            $tool
8050
        );
8051
8052
        if (!$allow) {
8053
            api_not_allowed($showHeader);
8054
        }
8055
    }
8056
8057
    return false;
8058
}
8059
8060
/**
8061
 * Check if a date is in a date range.
8062
 *
8063
 * @param datetime $startDate
8064
 * @param datetime $endDate
8065
 * @param datetime $currentDate
8066
 *
8067
 * @return bool true if date is in rage, false otherwise
8068
 */
8069
function api_is_date_in_date_range($startDate, $endDate, $currentDate = null)
8070
{
8071
    $startDate = strtotime(api_get_local_time($startDate));
8072
    $endDate = strtotime(api_get_local_time($endDate));
8073
    $currentDate = strtotime(api_get_local_time($currentDate));
8074
8075
    if ($currentDate >= $startDate && $currentDate <= $endDate) {
8076
        return true;
8077
    }
8078
8079
    return false;
8080
}
8081
8082
/**
8083
 * Eliminate the duplicates of a multidimensional array by sending the key.
8084
 *
8085
 * @param array $array multidimensional array
8086
 * @param int   $key   key to find to compare
8087
 *
8088
 * @return array
8089
 */
8090
function api_unique_multidim_array($array, $key)
8091
{
8092
    $temp_array = [];
8093
    $i = 0;
8094
    $key_array = [];
8095
8096
    foreach ($array as $val) {
8097
        if (!in_array($val[$key], $key_array)) {
8098
            $key_array[$i] = $val[$key];
8099
            $temp_array[$i] = $val;
8100
        }
8101
        $i++;
8102
    }
8103
8104
    return $temp_array;
8105
}
8106
8107
/**
8108
 * Limit the access to Session Admins when the limit_session_admin_role
8109
 * configuration variable is set to true.
8110
 */
8111
function api_protect_limit_for_session_admin()
8112
{
8113
    $limitAdmin = api_get_setting('limit_session_admin_role');
8114
    if (api_is_session_admin() && 'true' === $limitAdmin) {
8115
        api_not_allowed(true);
8116
    }
8117
}
8118
8119
/**
8120
 * Limits that a session admin has access to list users.
8121
 * When limit_session_admin_list_users configuration variable is set to true.
8122
 */
8123
function api_protect_session_admin_list_users()
8124
{
8125
    $limitAdmin = api_get_configuration_value('limit_session_admin_list_users');
8126
8127
    if (api_is_session_admin() && true === $limitAdmin) {
8128
        api_not_allowed(true);
8129
    }
8130
}
8131
8132
/**
8133
 * @return bool
8134
 */
8135
function api_is_student_view_active()
8136
{
8137
    $studentView = Session::read('studentview');
8138
8139
    return 'studentview' === $studentView;
8140
}
8141
8142
/**
8143
 * Adds a file inside the upload/$type/id.
8144
 *
8145
 * @param string $type
8146
 * @param array  $file
8147
 * @param int    $itemId
8148
 * @param string $cropParameters
8149
 *
8150
 * @return array|bool
8151
 */
8152
function api_upload_file($type, $file, $itemId, $cropParameters = '')
8153
{
8154
    throw new Exception('api_upload_file not implemented');
8155
    $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...
8156
    if ($upload) {
8157
        $name = api_replace_dangerous_char($file['name']);
8158
8159
        // No "dangerous" files
8160
        $name = disable_dangerous_file($name);
8161
8162
        $pathId = '/'.substr((string) $itemId, 0, 1).'/'.$itemId.'/';
8163
        $path = api_get_path(SYS_UPLOAD_PATH).$type.$pathId;
8164
8165
        if (!is_dir($path)) {
8166
            mkdir($path, api_get_permissions_for_new_directories(), true);
8167
        }
8168
8169
        $pathToSave = $path.$name;
8170
        $result = moveUploadedFile($file, $pathToSave);
8171
8172
        if ($result) {
8173
            if (!empty($cropParameters)) {
8174
                $image = new Image($pathToSave);
0 ignored issues
show
Deprecated Code introduced by
The class Image has been deprecated. ( Ignorable by Annotation )

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

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