Passed
Push — master ( b61354...af9f4d )
by Julito
19:31
created

api_unserialize_content()   B

Complexity

Conditions 7
Paths 12

Size

Total Lines 78
Code Lines 67

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 67
nc 12
nop 3
dl 0
loc 78
rs 7.7866
c 0
b 0
f 0

2 Methods

Rating   Name   Duplication   Size   Complexity  
A api_get_language_list_for_flag() 0 15 3
A api_create_zip() 0 8 1

How to fix   Long Method   

Long Method

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

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

Commonly applied refactorings include:

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

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

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

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

// Bar.php
namespace OtherDir;

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

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

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

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

// Bar.php
namespace OtherDir;

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

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

Loading history...
1180
        $tpl = new Template(null, true, true, false, true, false, true, 0);
1181
        $tpl->assign('hide_login_link', 1);
1182
1183
        //api_not_allowed(true, get_lang('AccountInactive'));
1184
        // we were not in a course, return to home page
1185
        $msg = Display::return_message(
1186
            get_lang('AccountInactive'),
1187
            'error',
1188
            false
1189
        );
1190
1191
        $msg .= '<p class="text-center">
1192
                 <a class="btn btn-default" href="'.$homeUrl.'">'.get_lang('BackHome').'</a></p>';
1193
1194
        if (api_is_anonymous()) {
1195
            /*$form = api_get_not_allowed_login_form();
1196
            $msg .= '<div class="well">';
1197
            $msg .= $form->returnForm();
1198
            $msg .= '</div>';*/
1199
        }
1200
1201
        $tpl->assign('content', $msg);
1202
        $tpl->display_one_col_template();
1203
        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...
1204
    }
1205
1206
    return $data;
1207
}
1208
1209
/**
1210
 * Function used to protect a teacher script.
1211
 * The function blocks access when the user has no teacher rights.
1212
 *
1213
 * @return bool True if the current user can access the script, false otherwise
1214
 *
1215
 * @author Yoselyn Castillo
1216
 */
1217
function api_protect_teacher_script()
1218
{
1219
    if (!api_is_allowed_to_edit()) {
1220
        api_not_allowed(true);
1221
1222
        return false;
1223
    }
1224
1225
    return true;
1226
}
1227
1228
/**
1229
 * Function used to prevent anonymous users from accessing a script.
1230
 *
1231
 * @param bool $printHeaders
1232
 *
1233
 * @return bool
1234
 */
1235
function api_block_anonymous_users($printHeaders = true)
1236
{
1237
    $isAuth = Container::getAuthorizationChecker()->isGranted('IS_AUTHENTICATED_FULLY');
1238
1239
    if (false === $isAuth) {
1240
        api_not_allowed($printHeaders);
1241
1242
        return false;
1243
    }
1244
1245
    api_block_inactive_user();
1246
1247
    return true;
1248
1249
    /*$user = api_get_user_info();
1250
    if (!(isset($user['user_id']) && $user['user_id']) || api_is_anonymous($user['user_id'], true)) {
1251
        api_not_allowed($printHeaders);
1252
1253
        return false;
1254
    }
1255
    api_block_inactive_user();
1256
1257
    return true;*/
1258
}
1259
1260
/**
1261
 * Returns a rough evaluation of the browser's name and version based on very
1262
 * simple regexp.
1263
 *
1264
 * @return array with the navigator name and version ['name' => '...', 'version' => '...']
1265
 */
1266
function api_get_navigator()
1267
{
1268
    $navigator = 'Unknown';
1269
    $version = 0;
1270
1271
    if (!isset($_SERVER['HTTP_USER_AGENT'])) {
1272
        return ['name' => 'Unknown', 'version' => '0.0.0'];
1273
    }
1274
1275
    if (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Opera')) {
1276
        $navigator = 'Opera';
1277
        [, $version] = explode('Opera', $_SERVER['HTTP_USER_AGENT']);
1278
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Edge')) {
1279
        $navigator = 'Edge';
1280
        [, $version] = explode('Edge', $_SERVER['HTTP_USER_AGENT']);
1281
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE')) {
1282
        $navigator = 'Internet Explorer';
1283
        [, $version] = explode('MSIE ', $_SERVER['HTTP_USER_AGENT']);
1284
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Chrome')) {
1285
        $navigator = 'Chrome';
1286
        [, $version] = explode('Chrome', $_SERVER['HTTP_USER_AGENT']);
1287
    } elseif (false !== stripos($_SERVER['HTTP_USER_AGENT'], 'Safari')) {
1288
        $navigator = 'Safari';
1289
        if (false !== stripos($_SERVER['HTTP_USER_AGENT'], 'Version/')) {
1290
            // If this Safari does have the "Version/" string in its user agent
1291
            // then use that as a version indicator rather than what's after
1292
            // "Safari/" which is rather a "build number" or something
1293
            [, $version] = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1294
        } else {
1295
            [, $version] = explode('Safari/', $_SERVER['HTTP_USER_AGENT']);
1296
        }
1297
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Firefox')) {
1298
        $navigator = 'Firefox';
1299
        [, $version] = explode('Firefox', $_SERVER['HTTP_USER_AGENT']);
1300
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Netscape')) {
1301
        $navigator = 'Netscape';
1302
        if (false !== stripos($_SERVER['HTTP_USER_AGENT'], 'Netscape/')) {
1303
            [, $version] = explode('Netscape', $_SERVER['HTTP_USER_AGENT']);
1304
        } else {
1305
            [, $version] = explode('Navigator', $_SERVER['HTTP_USER_AGENT']);
1306
        }
1307
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Konqueror')) {
1308
        $navigator = 'Konqueror';
1309
        [, $version] = explode('Konqueror', $_SERVER['HTTP_USER_AGENT']);
1310
    } elseif (false !== stripos($_SERVER['HTTP_USER_AGENT'], 'applewebkit')) {
1311
        $navigator = 'AppleWebKit';
1312
        [, $version] = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1313
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Gecko')) {
1314
        $navigator = 'Mozilla';
1315
        [, $version] = explode('; rv:', $_SERVER['HTTP_USER_AGENT']);
1316
    }
1317
1318
    // Now cut extra stuff around (mostly *after*) the version number
1319
    $version = preg_replace('/^([\/\s])?([\d\.]+)?.*/', '\2', $version);
1320
1321
    if (false === strpos($version, '.')) {
1322
        $version = number_format(doubleval($version), 1);
1323
    }
1324
1325
    return ['name' => $navigator, 'version' => $version];
1326
}
1327
1328
/**
1329
 * @return true if user self registration is allowed, false otherwise
1330
 */
1331
function api_is_self_registration_allowed()
1332
{
1333
    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...
1334
}
1335
1336
/**
1337
 * This function returns the id of the user which is stored in the $_user array.
1338
 *
1339
 * example: The function can be used to check if a user is logged in
1340
 *          if (api_get_user_id())
1341
 *
1342
 * @return int the id of the current user, 0 if is empty
1343
 */
1344
function api_get_user_id()
1345
{
1346
    $userInfo = Session::read('_user');
1347
    if ($userInfo && isset($userInfo['user_id'])) {
1348
        return (int) $userInfo['user_id'];
1349
    }
1350
1351
    return 0;
1352
}
1353
1354
/**
1355
 * Gets the list of courses a specific user is subscribed to.
1356
 *
1357
 * @param int       User ID
1358
 * @param bool $fetch_session Whether to get session courses or not - NOT YET IMPLEMENTED
1359
 *
1360
 * @return array Array of courses in the form [0]=>('code'=>xxx,'db'=>xxx,'dir'=>xxx,'status'=>d)
1361
 *
1362
 * @deprecated use CourseManager::get_courses_list_by_user_id()
1363
 */
1364
function api_get_user_courses($userId, $fetch_session = true)
1365
{
1366
    // Get out if not integer
1367
    if ($userId != strval(intval($userId))) {
1368
        return [];
1369
    }
1370
1371
    $t_course = Database::get_main_table(TABLE_MAIN_COURSE);
1372
    $t_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
1373
1374
    $sql = "SELECT cc.id as real_id, cc.code code, cc.directory dir, cu.status status
1375
            FROM $t_course cc, $t_course_user cu
1376
            WHERE
1377
                cc.id = cu.c_id AND
1378
                cu.user_id = $userId AND
1379
                cu.relation_type <> ".COURSE_RELATION_TYPE_RRHH;
1380
    $result = Database::query($sql);
1381
    if (false === $result) {
1382
        return [];
1383
    }
1384
1385
    $courses = [];
1386
    while ($row = Database::fetch_array($result)) {
1387
        // we only need the database name of the course
1388
        $courses[] = $row;
1389
    }
1390
1391
    return $courses;
1392
}
1393
1394
/**
1395
 * Formats user information into a standard array
1396
 * This function should be only used inside api_get_user_info().
1397
 *
1398
 * @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...
1399
 * @param bool $add_password
1400
 * @param bool $loadAvatars  turn off to improve performance
1401
 *
1402
 * @return array Standard user array
1403
 */
1404
function _api_format_user($user, $add_password = false, $loadAvatars = true)
1405
{
1406
    $result = [];
1407
1408
    if (!isset($user['id'])) {
1409
        return [];
1410
    }
1411
1412
    $result['firstname'] = null;
1413
    $result['lastname'] = null;
1414
1415
    if (isset($user['firstname']) && isset($user['lastname'])) {
1416
        // with only lowercase
1417
        $result['firstname'] = $user['firstname'];
1418
        $result['lastname'] = $user['lastname'];
1419
    } elseif (isset($user['firstName']) && isset($user['lastName'])) {
1420
        // with uppercase letters
1421
        $result['firstname'] = isset($user['firstName']) ? $user['firstName'] : null;
1422
        $result['lastname'] = isset($user['lastName']) ? $user['lastName'] : null;
1423
    }
1424
1425
    if (isset($user['email'])) {
1426
        $result['mail'] = isset($user['email']) ? $user['email'] : null;
1427
        $result['email'] = isset($user['email']) ? $user['email'] : null;
1428
    } else {
1429
        $result['mail'] = isset($user['mail']) ? $user['mail'] : null;
1430
        $result['email'] = isset($user['mail']) ? $user['mail'] : null;
1431
    }
1432
1433
    $result['complete_name'] = api_get_person_name($result['firstname'], $result['lastname']);
1434
    $result['complete_name_with_username'] = $result['complete_name'];
1435
1436
    if (!empty($user['username']) && 'false' === api_get_setting('profile.hide_username_with_complete_name')) {
1437
        $result['complete_name_with_username'] = $result['complete_name'].' ('.$user['username'].')';
1438
    }
1439
1440
    $showEmail = 'true' === api_get_setting('show_email_addresses');
1441
    if (!empty($user['email'])) {
1442
        $result['complete_name_with_email_forced'] = $result['complete_name'].' ('.$user['email'].')';
1443
        if ($showEmail) {
1444
            $result['complete_name_with_email'] = $result['complete_name'].' ('.$user['email'].')';
1445
        }
1446
    } else {
1447
        $result['complete_name_with_email'] = $result['complete_name'];
1448
        $result['complete_name_with_email_forced'] = $result['complete_name'];
1449
    }
1450
1451
    // Kept for historical reasons
1452
    $result['firstName'] = $result['firstname'];
1453
    $result['lastName'] = $result['lastname'];
1454
1455
    $attributes = [
1456
        'phone',
1457
        'address',
1458
        'picture_uri',
1459
        'official_code',
1460
        'status',
1461
        'active',
1462
        'auth_source',
1463
        'username',
1464
        'theme',
1465
        'language',
1466
        'creator_id',
1467
        'registration_date',
1468
        'hr_dept_id',
1469
        'expiration_date',
1470
        'last_login',
1471
        'user_is_online',
1472
    ];
1473
1474
    if ('true' === api_get_setting('extended_profile')) {
1475
        $attributes[] = 'competences';
1476
        $attributes[] = 'diplomas';
1477
        $attributes[] = 'teach';
1478
        $attributes[] = 'openarea';
1479
    }
1480
1481
    foreach ($attributes as $attribute) {
1482
        $result[$attribute] = isset($user[$attribute]) ? $user[$attribute] : null;
1483
    }
1484
1485
    $user_id = (int) $user['id'];
1486
    // Maintain the user_id index for backwards compatibility
1487
    $result['user_id'] = $result['id'] = $user_id;
1488
1489
    $hasCertificates = Certificate::getCertificateByUser($user_id);
1490
    $result['has_certificates'] = 0;
1491
    if (!empty($hasCertificates)) {
1492
        $result['has_certificates'] = 1;
1493
    }
1494
1495
    $result['icon_status'] = '';
1496
    $result['icon_status_medium'] = '';
1497
    $result['is_admin'] = UserManager::is_admin($user_id);
1498
1499
    // Getting user avatar.
1500
    if ($loadAvatars) {
1501
        $result['avatar'] = '';
1502
        $result['avatar_no_query'] = '';
1503
        $result['avatar_small'] = '';
1504
        $result['avatar_medium'] = '';
1505
1506
        /*if (!isset($user['avatar'])) {
1507
            $originalFile = UserManager::getUserPicture(
1508
                $user_id,
1509
                USER_IMAGE_SIZE_ORIGINAL,
1510
                null,
1511
                $result
1512
            );
1513
            $result['avatar'] = $originalFile;
1514
            $avatarString = explode('?', $result['avatar']);
1515
            $result['avatar_no_query'] = reset($avatarString);
1516
        } else {
1517
            $result['avatar'] = $user['avatar'];
1518
            $avatarString = explode('?', $user['avatar']);
1519
            $result['avatar_no_query'] = reset($avatarString);
1520
        }
1521
1522
        if (!isset($user['avatar_small'])) {
1523
            $smallFile = UserManager::getUserPicture(
1524
                $user_id,
1525
                USER_IMAGE_SIZE_SMALL,
1526
                null,
1527
                $result
1528
            );
1529
            $result['avatar_small'] = $smallFile;
1530
        } else {
1531
            $result['avatar_small'] = $user['avatar_small'];
1532
        }
1533
1534
        if (!isset($user['avatar_medium'])) {
1535
            $mediumFile = UserManager::getUserPicture(
1536
                $user_id,
1537
                USER_IMAGE_SIZE_MEDIUM,
1538
                null,
1539
                $result
1540
            );
1541
            $result['avatar_medium'] = $mediumFile;
1542
        } else {
1543
            $result['avatar_medium'] = $user['avatar_medium'];
1544
        }*/
1545
1546
        $urlImg = api_get_path(WEB_IMG_PATH);
1547
        $iconStatus = '';
1548
        $iconStatusMedium = '';
1549
        $label = '';
1550
        switch ($result['status']) {
1551
            case STUDENT:
1552
                if ($result['has_certificates']) {
1553
                    $iconStatus = $urlImg.'icons/svg/identifier_graduated.svg';
1554
                    $label = get_lang('Graduated');
1555
                } else {
1556
                    $iconStatus = $urlImg.'icons/svg/identifier_student.svg';
1557
                    $label = get_lang('Student');
1558
                }
1559
                break;
1560
            case COURSEMANAGER:
1561
                if ($result['is_admin']) {
1562
                    $iconStatus = $urlImg.'icons/svg/identifier_admin.svg';
1563
                    $label = get_lang('Admin');
1564
                } else {
1565
                    $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1566
                    $label = get_lang('Teacher');
1567
                }
1568
                break;
1569
            case STUDENT_BOSS:
1570
                $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1571
                $label = get_lang('StudentBoss');
1572
                break;
1573
        }
1574
1575
        if (!empty($iconStatus)) {
1576
            $iconStatusMedium = '<img src="'.$iconStatus.'" width="32px" height="32px">';
1577
            $iconStatus = '<img src="'.$iconStatus.'" width="22px" height="22px">';
1578
        }
1579
1580
        $result['icon_status'] = $iconStatus;
1581
        $result['icon_status_label'] = $label;
1582
        $result['icon_status_medium'] = $iconStatusMedium;
1583
    }
1584
1585
    if (isset($user['user_is_online'])) {
1586
        $result['user_is_online'] = true == $user['user_is_online'] ? 1 : 0;
1587
    }
1588
    if (isset($user['user_is_online_in_chat'])) {
1589
        $result['user_is_online_in_chat'] = (int) $user['user_is_online_in_chat'];
1590
    }
1591
1592
    if ($add_password) {
1593
        $result['password'] = $user['password'];
1594
    }
1595
1596
    if (isset($result['profile_completed'])) {
1597
        $result['profile_completed'] = $user['profile_completed'];
1598
    }
1599
1600
    $result['profile_url'] = api_get_path(WEB_CODE_PATH).'social/profile.php?u='.$user_id;
1601
1602
    // Send message link
1603
    $sendMessage = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&user_id='.$user_id;
1604
    $result['complete_name_with_message_link'] = Display::url(
1605
        $result['complete_name_with_username'],
1606
        $sendMessage,
1607
        ['class' => 'ajax']
1608
    );
1609
1610
    if (isset($user['extra'])) {
1611
        $result['extra'] = $user['extra'];
1612
    }
1613
1614
    return $result;
1615
}
1616
1617
/**
1618
 * Finds all the information about a user.
1619
 * If no parameter is passed you find all the information about the current user.
1620
 *
1621
 * @param int  $user_id
1622
 * @param bool $checkIfUserOnline
1623
 * @param bool $showPassword
1624
 * @param bool $loadExtraData
1625
 * @param bool $loadOnlyVisibleExtraData Get the user extra fields that are visible
1626
 * @param bool $loadAvatars              turn off to improve performance and if avatars are not needed
1627
 * @param bool $updateCache              update apc cache if exists
1628
 *
1629
 * @return mixed $user_info user_id, lastname, firstname, username, email, etc or false on error
1630
 *
1631
 * @author Patrick Cool <[email protected]>
1632
 * @author Julio Montoya
1633
 *
1634
 * @version 21 September 2004
1635
 */
1636
function api_get_user_info(
1637
    $user_id = 0,
1638
    $checkIfUserOnline = false,
1639
    $showPassword = false,
1640
    $loadExtraData = false,
1641
    $loadOnlyVisibleExtraData = false,
1642
    $loadAvatars = true,
1643
    $updateCache = false
1644
) {
1645
    // Make sure user_id is safe
1646
    $user_id = (int) $user_id;
1647
    $user = false;
1648
    if (empty($user_id)) {
1649
        $userFromSession = Session::read('_user');
1650
        if (isset($userFromSession) && !empty($userFromSession)) {
1651
            return $userFromSession;
1652
            /*
1653
            return _api_format_user(
1654
                $userFromSession,
1655
                $showPassword,
1656
                $loadAvatars
1657
            );*/
1658
        }
1659
1660
        return false;
1661
    }
1662
1663
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1664
            WHERE id = $user_id";
1665
    $result = Database::query($sql);
1666
    if (Database::num_rows($result) > 0) {
1667
        $result_array = Database::fetch_array($result);
1668
        $result_array['user_is_online_in_chat'] = 0;
1669
        if ($checkIfUserOnline) {
1670
            $use_status_in_platform = user_is_online($user_id);
1671
            $result_array['user_is_online'] = $use_status_in_platform;
1672
            $user_online_in_chat = 0;
1673
            if ($use_status_in_platform) {
1674
                $user_status = UserManager::get_extra_user_data_by_field(
1675
                    $user_id,
1676
                    'user_chat_status',
1677
                    false,
1678
                    true
1679
                );
1680
                if (1 == (int) $user_status['user_chat_status']) {
1681
                    $user_online_in_chat = 1;
1682
                }
1683
            }
1684
            $result_array['user_is_online_in_chat'] = $user_online_in_chat;
1685
        }
1686
1687
        if ($loadExtraData) {
1688
            $fieldValue = new ExtraFieldValue('user');
1689
            $result_array['extra'] = $fieldValue->getAllValuesForAnItem(
1690
                $user_id,
1691
                $loadOnlyVisibleExtraData
1692
            );
1693
        }
1694
        $user = _api_format_user($result_array, $showPassword, $loadAvatars);
1695
    }
1696
1697
    return $user;
1698
}
1699
1700
function api_get_user_info_from_entity(
1701
    User $user,
1702
    $checkIfUserOnline = false,
1703
    $showPassword = false,
1704
    $loadExtraData = false,
1705
    $loadOnlyVisibleExtraData = false,
1706
    $loadAvatars = true,
1707
    $loadCertificate = false
1708
) {
1709
    if (!$user instanceof UserInterface) {
1710
        return false;
1711
    }
1712
1713
    // Make sure user_id is safe
1714
    $user_id = (int) $user->getId();
1715
1716
    if (empty($user_id)) {
1717
        $userFromSession = Session::read('_user');
1718
1719
        if (isset($userFromSession) && !empty($userFromSession)) {
1720
            return $userFromSession;
1721
        }
1722
1723
        return false;
1724
    }
1725
1726
    $result = [];
1727
    $result['user_is_online_in_chat'] = 0;
1728
    if ($checkIfUserOnline) {
1729
        $use_status_in_platform = user_is_online($user_id);
1730
        $result['user_is_online'] = $use_status_in_platform;
1731
        $user_online_in_chat = 0;
1732
        if ($use_status_in_platform) {
1733
            $user_status = UserManager::get_extra_user_data_by_field(
1734
                $user_id,
1735
                'user_chat_status',
1736
                false,
1737
                true
1738
            );
1739
            if (1 == (int) $user_status['user_chat_status']) {
1740
                $user_online_in_chat = 1;
1741
            }
1742
        }
1743
        $result['user_is_online_in_chat'] = $user_online_in_chat;
1744
    }
1745
1746
    if ($loadExtraData) {
1747
        $fieldValue = new ExtraFieldValue('user');
1748
        $result['extra'] = $fieldValue->getAllValuesForAnItem(
1749
            $user_id,
1750
            $loadOnlyVisibleExtraData
1751
        );
1752
    }
1753
1754
    $result['username'] = $user->getUsername();
1755
    $result['status'] = $user->getStatus();
1756
    $result['firstname'] = $user->getFirstname();
1757
    $result['lastname'] = $user->getLastname();
1758
    $result['email'] = $result['mail'] = $user->getEmail();
1759
    $result['complete_name'] = api_get_person_name($result['firstname'], $result['lastname']);
1760
    $result['complete_name_with_username'] = $result['complete_name'];
1761
1762
    if (!empty($result['username']) && 'false' === api_get_setting('profile.hide_username_with_complete_name')) {
1763
        $result['complete_name_with_username'] = $result['complete_name'].' ('.$result['username'].')';
1764
    }
1765
1766
    $showEmail = 'true' === api_get_setting('show_email_addresses');
1767
    if (!empty($result['email'])) {
1768
        $result['complete_name_with_email_forced'] = $result['complete_name'].' ('.$result['email'].')';
1769
        if ($showEmail) {
1770
            $result['complete_name_with_email'] = $result['complete_name'].' ('.$result['email'].')';
1771
        }
1772
    } else {
1773
        $result['complete_name_with_email'] = $result['complete_name'];
1774
        $result['complete_name_with_email_forced'] = $result['complete_name'];
1775
    }
1776
1777
    // Kept for historical reasons
1778
    $result['firstName'] = $result['firstname'];
1779
    $result['lastName'] = $result['lastname'];
1780
1781
    $attributes = [
1782
        'picture_uri',
1783
        'last_login',
1784
        'user_is_online',
1785
    ];
1786
1787
    $result['phone'] = $user->getPhone();
1788
    $result['address'] = $user->getAddress();
1789
    $result['official_code'] = $user->getOfficialCode();
1790
    $result['active'] = $user->getActive();
1791
    $result['auth_source'] = $user->getAuthSource();
1792
    $result['language'] = $user->getLocale();
1793
    $result['creator_id'] = $user->getCreatorId();
1794
    $result['registration_date'] = $user->getRegistrationDate()->format('Y-m-d H:i:s');
1795
    $result['hr_dept_id'] = $user->getHrDeptId();
1796
    $result['expiration_date'] = '';
1797
    if ($user->getExpirationDate()) {
1798
        $result['expiration_date'] = $user->getExpirationDate()->format('Y-m-d H:i:s');
1799
    }
1800
1801
    $result['last_login'] = null;
1802
    if ($user->getLastLogin()) {
1803
        $result['last_login'] = $user->getLastLogin()->format('Y-m-d H:i:s');
1804
    }
1805
1806
    $result['competences'] = $user->getCompetences();
1807
    $result['diplomas'] = $user->getDiplomas();
1808
    $result['teach'] = $user->getTeach();
1809
    $result['openarea'] = $user->getOpenarea();
1810
    $user_id = (int) $user->getId();
1811
1812
    // Maintain the user_id index for backwards compatibility
1813
    $result['user_id'] = $result['id'] = $user_id;
1814
1815
    if ($loadCertificate) {
1816
        $hasCertificates = Certificate::getCertificateByUser($user_id);
1817
        $result['has_certificates'] = 0;
1818
        if (!empty($hasCertificates)) {
1819
            $result['has_certificates'] = 1;
1820
        }
1821
    }
1822
1823
    $result['icon_status'] = '';
1824
    $result['icon_status_medium'] = '';
1825
    $result['is_admin'] = UserManager::is_admin($user_id);
1826
1827
    // Getting user avatar.
1828
    if ($loadAvatars) {
1829
        $result['avatar'] = '';
1830
        $result['avatar_no_query'] = '';
1831
        $result['avatar_small'] = '';
1832
        $result['avatar_medium'] = '';
1833
1834
        /*if (!isset($user['avatar'])) {
1835
            $originalFile = UserManager::getUserPicture(
1836
                $user_id,
1837
                USER_IMAGE_SIZE_ORIGINAL,
1838
                null,
1839
                $result
1840
            );
1841
            $result['avatar'] = $originalFile;
1842
            $avatarString = explode('?', $result['avatar']);
1843
            $result['avatar_no_query'] = reset($avatarString);
1844
        } else {
1845
            $result['avatar'] = $user['avatar'];
1846
            $avatarString = explode('?', $user['avatar']);
1847
            $result['avatar_no_query'] = reset($avatarString);
1848
        }
1849
1850
        if (!isset($user['avatar_small'])) {
1851
            $smallFile = UserManager::getUserPicture(
1852
                $user_id,
1853
                USER_IMAGE_SIZE_SMALL,
1854
                null,
1855
                $result
1856
            );
1857
            $result['avatar_small'] = $smallFile;
1858
        } else {
1859
            $result['avatar_small'] = $user['avatar_small'];
1860
        }
1861
1862
        if (!isset($user['avatar_medium'])) {
1863
            $mediumFile = UserManager::getUserPicture(
1864
                $user_id,
1865
                USER_IMAGE_SIZE_MEDIUM,
1866
                null,
1867
                $result
1868
            );
1869
            $result['avatar_medium'] = $mediumFile;
1870
        } else {
1871
            $result['avatar_medium'] = $user['avatar_medium'];
1872
        }*/
1873
1874
        //$urlImg = api_get_path(WEB_IMG_PATH);
1875
        $urlImg = '/';
1876
        $iconStatus = '';
1877
        $iconStatusMedium = '';
1878
1879
        switch ($user->getStatus()) {
1880
            case STUDENT:
1881
                if (isset($result['has_certificates']) && $result['has_certificates']) {
1882
                    $iconStatus = $urlImg.'icons/svg/identifier_graduated.svg';
1883
                } else {
1884
                    $iconStatus = $urlImg.'icons/svg/identifier_student.svg';
1885
                }
1886
                break;
1887
            case COURSEMANAGER:
1888
                if ($result['is_admin']) {
1889
                    $iconStatus = $urlImg.'icons/svg/identifier_admin.svg';
1890
                } else {
1891
                    $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1892
                }
1893
                break;
1894
            case STUDENT_BOSS:
1895
                $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1896
                break;
1897
        }
1898
1899
        if (!empty($iconStatus)) {
1900
            $iconStatusMedium = '<img src="'.$iconStatus.'" width="32px" height="32px">';
1901
            $iconStatus = '<img src="'.$iconStatus.'" width="22px" height="22px">';
1902
        }
1903
1904
        $result['icon_status'] = $iconStatus;
1905
        $result['icon_status_medium'] = $iconStatusMedium;
1906
    }
1907
1908
    if (isset($result['user_is_online'])) {
1909
        $result['user_is_online'] = true == $result['user_is_online'] ? 1 : 0;
1910
    }
1911
    if (isset($result['user_is_online_in_chat'])) {
1912
        $result['user_is_online_in_chat'] = $result['user_is_online_in_chat'];
1913
    }
1914
1915
    $result['password'] = '';
1916
    if ($showPassword) {
1917
        $result['password'] = $user->getPassword();
1918
    }
1919
1920
    if (isset($result['profile_completed'])) {
1921
        $result['profile_completed'] = $result['profile_completed'];
1922
    }
1923
1924
    $result['profile_url'] = api_get_path(WEB_CODE_PATH).'social/profile.php?u='.$user_id;
1925
1926
    // Send message link
1927
    $sendMessage = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&user_id='.$user_id;
1928
    $result['complete_name_with_message_link'] = Display::url(
1929
        $result['complete_name_with_username'],
1930
        $sendMessage,
1931
        ['class' => 'ajax']
1932
    );
1933
1934
    if (isset($result['extra'])) {
1935
        $result['extra'] = $result['extra'];
1936
    }
1937
1938
    return $result;
1939
}
1940
1941
function api_get_lp_entity(int $id): ?CLp
1942
{
1943
    return Database::getManager()->getRepository(CLp::class)->find($id);
1944
}
1945
1946
function api_get_user_entity(int $userId = 0): ?User
1947
{
1948
    $userId = $userId ?: api_get_user_id();
1949
    $repo = UserManager::getRepository();
1950
1951
    return $repo->find($userId);
1952
}
1953
1954
function api_get_current_user(): ?User
1955
{
1956
    $isLoggedIn = Container::$container->get('security.authorization_checker')->isGranted('IS_AUTHENTICATED_REMEMBERED');
0 ignored issues
show
Bug introduced by
The method get() does not exist on null. ( Ignorable by Annotation )

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

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

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

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

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

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

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