Passed
Push — master ( a3e8e4...079342 )
by Julito
13:52
created

api_get_status_list()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

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

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

Loading history...
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']) && $toolInfo['visibility'] == 0) {
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
    }
1072
1073
    if (!$is_visible) {
1074
        api_not_allowed($print_headers);
1075
1076
        return false;
1077
    }
1078
1079
    return true;
1080
}
1081
1082
/**
1083
 * Function used to protect an admin script.
1084
 *
1085
 * The function blocks access when the user has no platform admin rights
1086
 * with an error message printed on default output
1087
 *
1088
 * @param bool Whether to allow session admins as well
1089
 * @param bool Whether to allow HR directors as well
1090
 * @param string An optional message (already passed through get_lang)
1091
 *
1092
 * @return bool True if user is allowed, false otherwise.
1093
 *              The function also outputs an error message in case not allowed
1094
 *
1095
 * @author Roan Embrechts (original author)
1096
 */
1097
function api_protect_admin_script($allow_sessions_admins = false, $allow_drh = false, $message = null)
1098
{
1099
    if (!api_is_platform_admin($allow_sessions_admins, $allow_drh)) {
1100
        api_not_allowed(true, $message);
1101
1102
        return false;
1103
    }
1104
1105
    return true;
1106
}
1107
1108
/**
1109
 * Function used to protect a teacher script.
1110
 * The function blocks access when the user has no teacher rights.
1111
 *
1112
 * @return bool True if the current user can access the script, false otherwise
1113
 *
1114
 * @author Yoselyn Castillo
1115
 */
1116
function api_protect_teacher_script()
1117
{
1118
    if (!api_is_allowed_to_edit()) {
1119
        api_not_allowed(true);
1120
1121
        return false;
1122
    }
1123
1124
    return true;
1125
}
1126
1127
/**
1128
 * Function used to prevent anonymous users from accessing a script.
1129
 *
1130
 * @param bool|true $printHeaders
1131
 *
1132
 * @author Roan Embrechts
1133
 *
1134
 * @return bool
1135
 */
1136
function api_block_anonymous_users($printHeaders = true)
1137
{
1138
    $user = api_get_user_info();
1139
    if (!(isset($user['user_id']) && $user['user_id']) || api_is_anonymous($user['user_id'], true)) {
1140
        api_not_allowed($printHeaders);
1141
1142
        return false;
1143
    }
1144
1145
    return true;
1146
}
1147
1148
/**
1149
 * Returns a rough evaluation of the browser's name and version based on very
1150
 * simple regexp.
1151
 *
1152
 * @return array with the navigator name and version ['name' => '...', 'version' => '...']
1153
 */
1154
function api_get_navigator()
1155
{
1156
    $navigator = 'Unknown';
1157
    $version = 0;
1158
1159
    if (!isset($_SERVER['HTTP_USER_AGENT'])) {
1160
        return ['name' => 'Unknown', 'version' => '0.0.0'];
1161
    }
1162
1163
    if (strpos($_SERVER['HTTP_USER_AGENT'], 'Opera') !== false) {
1164
        $navigator = 'Opera';
1165
        list(, $version) = explode('Opera', $_SERVER['HTTP_USER_AGENT']);
1166
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Edge') !== false) {
1167
        $navigator = 'Edge';
1168
        list(, $version) = explode('Edge', $_SERVER['HTTP_USER_AGENT']);
1169
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== false) {
1170
        $navigator = 'Internet Explorer';
1171
        list(, $version) = explode('MSIE ', $_SERVER['HTTP_USER_AGENT']);
1172
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Chrome') !== false) {
1173
        $navigator = 'Chrome';
1174
        list(, $version) = explode('Chrome', $_SERVER['HTTP_USER_AGENT']);
1175
    } elseif (stripos($_SERVER['HTTP_USER_AGENT'], 'Safari') !== false) {
1176
        $navigator = 'Safari';
1177
        if (stripos($_SERVER['HTTP_USER_AGENT'], 'Version/') !== false) {
1178
            // If this Safari does have the "Version/" string in its user agent
1179
            // then use that as a version indicator rather than what's after
1180
            // "Safari/" which is rather a "build number" or something
1181
            list(, $version) = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1182
        } else {
1183
            list(, $version) = explode('Safari/', $_SERVER['HTTP_USER_AGENT']);
1184
        }
1185
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Firefox') !== false) {
1186
        $navigator = 'Firefox';
1187
        list(, $version) = explode('Firefox', $_SERVER['HTTP_USER_AGENT']);
1188
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Netscape') !== false) {
1189
        $navigator = 'Netscape';
1190
        if (stripos($_SERVER['HTTP_USER_AGENT'], 'Netscape/') !== false) {
1191
            list(, $version) = explode('Netscape', $_SERVER['HTTP_USER_AGENT']);
1192
        } else {
1193
            list(, $version) = explode('Navigator', $_SERVER['HTTP_USER_AGENT']);
1194
        }
1195
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Konqueror') !== false) {
1196
        $navigator = 'Konqueror';
1197
        list(, $version) = explode('Konqueror', $_SERVER['HTTP_USER_AGENT']);
1198
    } elseif (stripos($_SERVER['HTTP_USER_AGENT'], 'applewebkit') !== false) {
1199
        $navigator = 'AppleWebKit';
1200
        list(, $version) = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1201
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Gecko') !== false) {
1202
        $navigator = 'Mozilla';
1203
        list(, $version) = explode('; rv:', $_SERVER['HTTP_USER_AGENT']);
1204
    }
1205
1206
    // Now cut extra stuff around (mostly *after*) the version number
1207
    $version = preg_replace('/^([\/\s])?([\d\.]+)?.*/', '\2', $version);
1208
1209
    if (strpos($version, '.') === false) {
1210
        $version = number_format(doubleval($version), 1);
1211
    }
1212
    $return = ['name' => $navigator, 'version' => $version];
1213
1214
    return $return;
1215
}
1216
1217
/**
1218
 * @return true if user self registration is allowed, false otherwise
1219
 */
1220
function api_is_self_registration_allowed()
1221
{
1222
    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...
1223
}
1224
1225
/**
1226
 * This function returns the id of the user which is stored in the $_user array.
1227
 *
1228
 * example: The function can be used to check if a user is logged in
1229
 *          if (api_get_user_id())
1230
 *
1231
 * @return int the id of the current user, 0 if is empty
1232
 */
1233
function api_get_user_id()
1234
{
1235
    $userInfo = Session::read('_user');
1236
    if ($userInfo && isset($userInfo['user_id'])) {
1237
        return (int) $userInfo['user_id'];
1238
    }
1239
1240
    return 0;
1241
}
1242
1243
/**
1244
 * Gets the list of courses a specific user is subscribed to.
1245
 *
1246
 * @param int       User ID
1247
 * @param bool $fetch_session Whether to get session courses or not - NOT YET IMPLEMENTED
1248
 *
1249
 * @return array Array of courses in the form [0]=>('code'=>xxx,'db'=>xxx,'dir'=>xxx,'status'=>d)
1250
 *
1251
 * @deprecated use CourseManager::get_courses_list_by_user_id()
1252
 */
1253
function api_get_user_courses($userId, $fetch_session = true)
0 ignored issues
show
Unused Code introduced by
The parameter $fetch_session is not used and could be removed. ( Ignorable by Annotation )

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

1253
function api_get_user_courses($userId, /** @scrutinizer ignore-unused */ $fetch_session = true)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1254
{
1255
    // Get out if not integer
1256
    if ($userId != strval(intval($userId))) {
1257
        return [];
1258
    }
1259
1260
    $t_course = Database::get_main_table(TABLE_MAIN_COURSE);
1261
    $t_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
1262
1263
    $sql = "SELECT cc.id as real_id, cc.code code, cc.directory dir, cu.status status
1264
            FROM $t_course cc, $t_course_user cu
1265
            WHERE
1266
                cc.id = cu.c_id AND
1267
                cu.user_id = $userId AND
1268
                cu.relation_type <> ".COURSE_RELATION_TYPE_RRHH;
1269
    $result = Database::query($sql);
1270
    if ($result === false) {
1271
        return [];
1272
    }
1273
1274
    $courses = [];
1275
    while ($row = Database::fetch_array($result)) {
1276
        // we only need the database name of the course
1277
        $courses[] = $row;
1278
    }
1279
1280
    return $courses;
1281
}
1282
1283
/**
1284
 * Formats user information into a standard array
1285
 * This function should be only used inside api_get_user_info().
1286
 *
1287
 * @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...
1288
 * @param bool $add_password
1289
 * @param bool $loadAvatars  turn off to improve performance
1290
 *
1291
 * @return array Standard user array
1292
 */
1293
function _api_format_user($user, $add_password = false, $loadAvatars = true)
1294
{
1295
    $result = [];
1296
1297
    if (!isset($user['user_id'])) {
1298
        return [];
1299
    }
1300
1301
    $result['firstname'] = null;
1302
    $result['lastname'] = null;
1303
1304
    if (isset($user['firstname']) && isset($user['lastname'])) {
1305
        // with only lowercase
1306
        $result['firstname'] = $user['firstname'];
1307
        $result['lastname'] = $user['lastname'];
1308
    } elseif (isset($user['firstName']) && isset($user['lastName'])) {
1309
        // with uppercase letters
1310
        $result['firstname'] = isset($user['firstName']) ? $user['firstName'] : null;
1311
        $result['lastname'] = isset($user['lastName']) ? $user['lastName'] : null;
1312
    }
1313
1314
    if (isset($user['email'])) {
1315
        $result['mail'] = isset($user['email']) ? $user['email'] : null;
1316
        $result['email'] = isset($user['email']) ? $user['email'] : null;
1317
    } else {
1318
        $result['mail'] = isset($user['mail']) ? $user['mail'] : null;
1319
        $result['email'] = isset($user['mail']) ? $user['mail'] : null;
1320
    }
1321
1322
    $result['complete_name'] = api_get_person_name($result['firstname'], $result['lastname']);
1323
    $result['complete_name_with_username'] = $result['complete_name'];
1324
1325
    if (!empty($user['username']) && api_get_setting('profile.hide_username_with_complete_name') === 'false') {
1326
        $result['complete_name_with_username'] = $result['complete_name'].' ('.$user['username'].')';
1327
    }
1328
1329
    $showEmail = api_get_setting('show_email_addresses') === 'true';
1330
    if (!empty($user['email'])) {
1331
        $result['complete_name_with_email_forced'] = $result['complete_name'].' ('.$user['email'].')';
1332
        if ($showEmail) {
1333
            $result['complete_name_with_email'] = $result['complete_name'].' ('.$user['email'].')';
1334
        }
1335
    } else {
1336
        $result['complete_name_with_email'] = $result['complete_name'];
1337
        $result['complete_name_with_email_forced'] = $result['complete_name'];
1338
    }
1339
1340
    // Kept for historical reasons
1341
    $result['firstName'] = $result['firstname'];
1342
    $result['lastName'] = $result['lastname'];
1343
1344
    $attributes = [
1345
        'phone',
1346
        'address',
1347
        'picture_uri',
1348
        'official_code',
1349
        'status',
1350
        'active',
1351
        'auth_source',
1352
        'username',
1353
        'theme',
1354
        'language',
1355
        'creator_id',
1356
        'registration_date',
1357
        'hr_dept_id',
1358
        'expiration_date',
1359
        'last_login',
1360
        'user_is_online',
1361
    ];
1362
1363
    if (api_get_setting('extended_profile') === 'true') {
1364
        $attributes[] = 'competences';
1365
        $attributes[] = 'diplomas';
1366
        $attributes[] = 'teach';
1367
        $attributes[] = 'openarea';
1368
    }
1369
1370
    foreach ($attributes as $attribute) {
1371
        $result[$attribute] = isset($user[$attribute]) ? $user[$attribute] : null;
1372
    }
1373
1374
    $user_id = (int) $user['user_id'];
1375
    // Maintain the user_id index for backwards compatibility
1376
    $result['user_id'] = $result['id'] = $user_id;
1377
1378
    $hasCertificates = Certificate::getCertificateByUser($user_id);
1379
    $result['has_certificates'] = 0;
1380
    if (!empty($hasCertificates)) {
1381
        $result['has_certificates'] = 1;
1382
    }
1383
1384
    $result['icon_status'] = '';
1385
    $result['icon_status_medium'] = '';
1386
1387
    $result['is_admin'] = UserManager::is_admin($user_id);
1388
1389
    // Getting user avatar.
1390
    if ($loadAvatars) {
1391
        $result['avatar'] = '';
1392
        $result['avatar_no_query'] = '';
1393
        $result['avatar_small'] = '';
1394
        $result['avatar_medium'] = '';
1395
1396
        if (!isset($user['avatar'])) {
1397
            $originalFile = UserManager::getUserPicture(
1398
                $user_id,
1399
                USER_IMAGE_SIZE_ORIGINAL,
1400
                null,
1401
                $result
1402
            );
1403
            $result['avatar'] = $originalFile;
1404
            $avatarString = explode('?', $result['avatar']);
1405
            $result['avatar_no_query'] = reset($avatarString);
1406
        } else {
1407
            $result['avatar'] = $user['avatar'];
1408
            $avatarString = explode('?', $user['avatar']);
1409
            $result['avatar_no_query'] = reset($avatarString);
1410
        }
1411
1412
        if (!isset($user['avatar_small'])) {
1413
            $smallFile = UserManager::getUserPicture(
1414
                $user_id,
1415
                USER_IMAGE_SIZE_SMALL,
1416
                null,
1417
                $result
1418
            );
1419
            $result['avatar_small'] = $smallFile;
1420
        } else {
1421
            $result['avatar_small'] = $user['avatar_small'];
1422
        }
1423
1424
        if (!isset($user['avatar_medium'])) {
1425
            $mediumFile = UserManager::getUserPicture(
1426
                $user_id,
1427
                USER_IMAGE_SIZE_MEDIUM,
1428
                null,
1429
                $result
1430
            );
1431
            $result['avatar_medium'] = $mediumFile;
1432
        } else {
1433
            $result['avatar_medium'] = $user['avatar_medium'];
1434
        }
1435
1436
        $urlImg = api_get_path(WEB_IMG_PATH);
1437
        $iconStatus = '';
1438
        $iconStatusMedium = '';
1439
1440
        switch ($result['status']) {
1441
            case STUDENT:
1442
                if ($result['has_certificates']) {
1443
                    $iconStatus = $urlImg.'icons/svg/identifier_graduated.svg';
1444
                } else {
1445
                    $iconStatus = $urlImg.'icons/svg/identifier_student.svg';
1446
                }
1447
                break;
1448
            case COURSEMANAGER:
1449
                if ($result['is_admin']) {
1450
                    $iconStatus = $urlImg.'icons/svg/identifier_admin.svg';
1451
                } else {
1452
                    $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1453
                }
1454
                break;
1455
            case STUDENT_BOSS:
1456
                $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1457
                break;
1458
        }
1459
1460
        if (!empty($iconStatus)) {
1461
            $iconStatusMedium = '<img src="'.$iconStatus.'" width="32px" height="32px">';
1462
            $iconStatus = '<img src="'.$iconStatus.'" width="22px" height="22px">';
1463
        }
1464
1465
        $result['icon_status'] = $iconStatus;
1466
        $result['icon_status_medium'] = $iconStatusMedium;
1467
    }
1468
1469
    if (isset($user['user_is_online'])) {
1470
        $result['user_is_online'] = $user['user_is_online'] == true ? 1 : 0;
1471
    }
1472
    if (isset($user['user_is_online_in_chat'])) {
1473
        $result['user_is_online_in_chat'] = (int) $user['user_is_online_in_chat'];
1474
    }
1475
1476
    if ($add_password) {
1477
        $result['password'] = $user['password'];
1478
    }
1479
1480
    if (isset($result['profile_completed'])) {
1481
        $result['profile_completed'] = $user['profile_completed'];
1482
    }
1483
1484
    $result['profile_url'] = api_get_path(WEB_CODE_PATH).'social/profile.php?u='.$user_id;
1485
1486
    // Send message link
1487
    $sendMessage = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&user_id='.$user_id;
1488
    $result['complete_name_with_message_link'] = Display::url(
1489
        $result['complete_name_with_username'],
1490
        $sendMessage,
1491
        ['class' => 'ajax']
1492
    );
1493
1494
    if (isset($user['extra'])) {
1495
        $result['extra'] = $user['extra'];
1496
    }
1497
1498
    return $result;
1499
}
1500
1501
/**
1502
 * Finds all the information about a user.
1503
 * If no parameter is passed you find all the information about the current user.
1504
 *
1505
 * @param int  $user_id
1506
 * @param bool $checkIfUserOnline
1507
 * @param bool $showPassword
1508
 * @param bool $loadExtraData
1509
 * @param bool $loadOnlyVisibleExtraData Get the user extra fields that are visible
1510
 * @param bool $loadAvatars              turn off to improve performance and if avatars are not needed
1511
 * @param bool $updateCache              update apc cache if exists
1512
 *
1513
 * @return mixed $user_info user_id, lastname, firstname, username, email, etc or false on error
1514
 *
1515
 * @author Patrick Cool <[email protected]>
1516
 * @author Julio Montoya
1517
 *
1518
 * @version 21 September 2004
1519
 */
1520
function api_get_user_info(
1521
    $user_id = 0,
1522
    $checkIfUserOnline = false,
1523
    $showPassword = false,
1524
    $loadExtraData = false,
1525
    $loadOnlyVisibleExtraData = false,
1526
    $loadAvatars = true,
1527
    $updateCache = false
1528
) {
1529
    $apcVar = null;
1530
    $user = false;
1531
    $cacheAvailable = api_get_configuration_value('apc');
1532
1533
    if (empty($user_id)) {
1534
        $userFromSession = Session::read('_user');
1535
1536
        if (isset($userFromSession)) {
1537
            if ($cacheAvailable === true &&
1538
                (
1539
                    empty($userFromSession['is_anonymous']) &&
1540
                    (isset($userFromSession['status']) && $userFromSession['status'] != ANONYMOUS)
1541
                )
1542
            ) {
1543
                $apcVar = api_get_configuration_value('apc_prefix').'userinfo_'.$userFromSession['user_id'];
1544
                if (apcu_exists($apcVar)) {
1545
                    if ($updateCache) {
1546
                        apcu_store($apcVar, $userFromSession, 60);
1547
                    }
1548
                    $user = apcu_fetch($apcVar);
1549
                } else {
1550
                    $user = _api_format_user(
1551
                        $userFromSession,
1552
                        $showPassword,
1553
                        $loadAvatars
1554
                    );
1555
                    apcu_store($apcVar, $user, 60);
1556
                }
1557
            } else {
1558
                $user = _api_format_user(
1559
                    $userFromSession,
1560
                    $showPassword,
1561
                    $loadAvatars
1562
                );
1563
            }
1564
1565
            return $user;
1566
        }
1567
1568
        return false;
1569
    }
1570
1571
    // Make sure user_id is safe
1572
    $user_id = (int) $user_id;
1573
1574
    // Re-use user information if not stale and already stored in APCu
1575
    if ($cacheAvailable === true) {
1576
        $apcVar = api_get_configuration_value('apc_prefix').'userinfo_'.$user_id;
1577
        if (apcu_exists($apcVar) && $updateCache == false && $checkIfUserOnline == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

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

Loading history...
1578
            $user = apcu_fetch($apcVar);
1579
1580
            return $user;
1581
        }
1582
    }
1583
1584
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1585
            WHERE id = $user_id";
1586
    $result = Database::query($sql);
1587
    if (Database::num_rows($result) > 0) {
1588
        $result_array = Database::fetch_array($result);
1589
        $result_array['user_is_online_in_chat'] = 0;
1590
        if ($checkIfUserOnline) {
1591
            $use_status_in_platform = user_is_online($user_id);
1592
            $result_array['user_is_online'] = $use_status_in_platform;
1593
            $user_online_in_chat = 0;
1594
            if ($use_status_in_platform) {
1595
                $user_status = UserManager::get_extra_user_data_by_field(
1596
                    $user_id,
1597
                    'user_chat_status',
1598
                    false,
1599
                    true
1600
                );
1601
                if ((int) $user_status['user_chat_status'] == 1) {
1602
                    $user_online_in_chat = 1;
1603
                }
1604
            }
1605
            $result_array['user_is_online_in_chat'] = $user_online_in_chat;
1606
        }
1607
1608
        if ($loadExtraData) {
1609
            $fieldValue = new ExtraFieldValue('user');
1610
            $result_array['extra'] = $fieldValue->getAllValuesForAnItem(
1611
                $user_id,
1612
                $loadOnlyVisibleExtraData
1613
            );
1614
        }
1615
        $user = _api_format_user($result_array, $showPassword, $loadAvatars);
1616
    }
1617
1618
    if ($cacheAvailable === true) {
1619
        apcu_store($apcVar, $user, 60);
1620
    }
1621
1622
    return $user;
1623
}
1624
1625
/**
1626
 * @param int $userId
1627
 *
1628
 * @return User
1629
 */
1630
function api_get_user_entity($userId)
1631
{
1632
    $userId = (int) $userId;
1633
    $repo = UserManager::getRepository();
1634
1635
    /** @var User $user */
1636
    $user = $repo->find($userId);
1637
1638
    return $user;
1639
}
1640
1641
/**
1642
 * @return User|null
1643
 */
1644
function api_get_current_user()
1645
{
1646
    $isLoggedIn = Container::$container->get('security.authorization_checker')->isGranted('IS_AUTHENTICATED_REMEMBERED');
1647
    if ($isLoggedIn === false) {
1648
        return null;
1649
    }
1650
1651
    $token = Container::$container->get('security.token_storage')->getToken();
1652
1653
    if (null !== $token) {
1654
        return $token->getUser();
1655
    }
1656
1657
    return null;
1658
}
1659
1660
/**
1661
 * Finds all the information about a user from username instead of user id.
1662
 *
1663
 * @param string $username
1664
 *
1665
 * @return mixed $user_info array user_id, lastname, firstname, username, email or false on error
1666
 *
1667
 * @author Yannick Warnier <[email protected]>
1668
 */
1669
function api_get_user_info_from_username($username = '')
1670
{
1671
    if (empty($username)) {
1672
        return false;
1673
    }
1674
    $username = trim($username);
1675
1676
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1677
            WHERE username='".Database::escape_string($username)."'";
1678
    $result = Database::query($sql);
1679
    if (Database::num_rows($result) > 0) {
1680
        $resultArray = Database::fetch_array($result);
1681
1682
        return _api_format_user($resultArray);
1683
    }
1684
1685
    return false;
1686
}
1687
1688
/**
1689
 * Get first user with an email.
1690
 *
1691
 * @param string $email
1692
 *
1693
 * @return array|bool
1694
 */
1695
function api_get_user_info_from_email($email = '')
1696
{
1697
    if (empty($email)) {
1698
        return false;
1699
    }
1700
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1701
            WHERE email ='".Database::escape_string($email)."' LIMIT 1";
1702
    $result = Database::query($sql);
1703
    if (Database::num_rows($result) > 0) {
1704
        $resultArray = Database::fetch_array($result);
1705
1706
        return _api_format_user($resultArray);
1707
    }
1708
1709
    return false;
1710
}
1711
1712
/**
1713
 * @return string
1714
 */
1715
function api_get_course_id()
1716
{
1717
    return Session::read('_cid', null);
1718
}
1719
1720
/**
1721
 * Returns the current course id (integer).
1722
 *
1723
 * @param string $code Optional course code
1724
 *
1725
 * @return int
1726
 */
1727
function api_get_course_int_id($code = null)
1728
{
1729
    if (!empty($code)) {
1730
        $code = Database::escape_string($code);
1731
        $row = Database::select(
1732
            'id',
1733
            Database::get_main_table(TABLE_MAIN_COURSE),
1734
            ['where' => ['code = ?' => [$code]]],
1735
            'first'
1736
        );
1737
1738
        if (is_array($row) && isset($row['id'])) {
1739
            return $row['id'];
1740
        } else {
1741
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type integer.
Loading history...
1742
        }
1743
    }
1744
1745
    return Session::read('_real_cid', 0);
1746
}
1747
1748
/**
1749
 * Returns the current course directory.
1750
 *
1751
 * This function relies on api_get_course_info()
1752
 *
1753
 * @param string    The course code - optional (takes it from session if not given)
1754
 *
1755
 * @return string The directory where the course is located inside the Chamilo "courses" directory
1756
 *
1757
 * @author Yannick Warnier <[email protected]>
1758
 */
1759
function api_get_course_path($course_code = null)
1760
{
1761
    $info = !empty($course_code) ? api_get_course_info($course_code) : api_get_course_info();
1762
1763
    return $info['path'];
1764
}
1765
1766
/**
1767
 * Gets a course setting from the current course_setting table. Try always using integer values.
1768
 *
1769
 * @param string $settingName The name of the setting we want from the table
1770
 * @param array  $courseInfo
1771
 * @param bool   $force       force checking the value in the database
1772
 *
1773
 * @return mixed The value of that setting in that table. Return -1 if not found.
1774
 */
1775
function api_get_course_setting($settingName, $courseInfo = [], $force = false)
1776
{
1777
    if (empty($courseInfo)) {
1778
        $courseInfo = api_get_course_info();
1779
    }
1780
1781
    if (empty($courseInfo) || empty($settingName)) {
1782
        return -1;
1783
    }
1784
1785
    $courseId = isset($courseInfo['real_id']) && !empty($courseInfo['real_id']) ? $courseInfo['real_id'] : 0;
1786
1787
    if (empty($courseId)) {
1788
        return -1;
1789
    }
1790
1791
    static $courseSettingInfo = [];
1792
1793
    if ($force) {
1794
        $courseSettingInfo = [];
1795
    }
1796
1797
    if (!isset($courseSettingInfo[$courseId])) {
1798
        $table = Database::get_course_table(TABLE_COURSE_SETTING);
1799
        $settingName = Database::escape_string($settingName);
1800
1801
        $sql = "SELECT variable, value FROM $table
1802
                WHERE c_id = $courseId ";
1803
        $res = Database::query($sql);
1804
        if (Database::num_rows($res) > 0) {
1805
            $result = Database::store_result($res, 'ASSOC');
1806
            $courseSettingInfo[$courseId] = array_column($result, 'value', 'variable');
1807
1808
            if (isset($courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'])) {
1809
                $value = $courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'];
1810
                if (!is_null($value)) {
1811
                    $result = explode(',', $value);
1812
                    $courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'] = $result;
1813
                }
1814
            }
1815
        }
1816
    }
1817
1818
    if (isset($courseSettingInfo[$courseId]) && isset($courseSettingInfo[$courseId][$settingName])) {
1819
        return $courseSettingInfo[$courseId][$settingName];
1820
    }
1821
1822
    return -1;
1823
}
1824
1825
/**
1826
 * Gets an anonymous user ID.
1827
 *
1828
 * For some tools that need tracking, like the learnpath tool, it is necessary
1829
 * to have a usable user-id to enable some kind of tracking, even if not
1830
 * perfect. An anonymous ID is taken from the users table by looking for a
1831
 * status of "6" (anonymous).
1832
 *
1833
 * @return int User ID of the anonymous user, or O if no anonymous user found
1834
 */
1835
function api_get_anonymous_id()
1836
{
1837
    // Find if another anon is connected now
1838
    $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
1839
    $tableU = Database::get_main_table(TABLE_MAIN_USER);
1840
    $ip = Database::escape_string(api_get_real_ip());
1841
    $max = (int) api_get_configuration_value('max_anonymous_users');
1842
    if ($max >= 2) {
1843
        $sql = "SELECT * FROM $table as TEL
1844
                JOIN $tableU as U
1845
                ON U.user_id = TEL.login_user_id
1846
                WHERE TEL.user_ip = '$ip'
1847
                    AND U.status = ".ANONYMOUS."
1848
                    AND U.user_id != 2 ";
1849
1850
        $result = Database::query($sql);
1851
        if (empty(Database::num_rows($result))) {
1852
            $login = uniqid('anon_');
1853
            $anonList = UserManager::get_user_list(['status' => ANONYMOUS], ['registration_date ASC']);
1854
            if (count($anonList) >= $max) {
1855
                foreach ($anonList as $userToDelete) {
1856
                    UserManager::delete_user($userToDelete['user_id']);
1857
                    break;
1858
                }
1859
            }
1860
            $userId = UserManager::create_user(
1861
                $login,
1862
                'anon',
1863
                ANONYMOUS,
1864
                ' anonymous@localhost',
1865
                $login,
1866
                $login
1867
            );
1868
1869
            return $userId;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $userId returns the type false which is incompatible with the documented return type integer.
Loading history...
1870
        } else {
1871
            $row = Database::fetch_array($result, 'ASSOC');
1872
1873
            return $row['user_id'];
1874
        }
1875
    }
1876
1877
    $table = Database::get_main_table(TABLE_MAIN_USER);
1878
    $sql = "SELECT user_id
1879
            FROM $table
1880
            WHERE status = ".ANONYMOUS." ";
1881
    $res = Database::query($sql);
1882
    if (Database::num_rows($res) > 0) {
1883
        $row = Database::fetch_array($res, 'ASSOC');
1884
1885
        return $row['user_id'];
1886
    }
1887
1888
    // No anonymous user was found.
1889
    return 0;
1890
}
1891
1892
/**
1893
 * @param string $courseCode
1894
 * @param int    $sessionId
1895
 * @param int    $groupId
1896
 *
1897
 * @return string
1898
 */
1899
function api_get_cidreq_params($courseCode, $sessionId = 0, $groupId = 0)
1900
{
1901
    $courseCode = !empty($courseCode) ? htmlspecialchars($courseCode) : '';
1902
    $sessionId = !empty($sessionId) ? (int) $sessionId : 0;
1903
    $groupId = !empty($groupId) ? (int) $groupId : 0;
1904
1905
    $url = 'cidReq='.$courseCode;
1906
    $url .= '&id_session='.$sessionId;
1907
    $url .= '&gidReq='.$groupId;
1908
1909
    return $url;
1910
}
1911
1912
/**
1913
 * Returns the current course url part including session, group, and gradebook params.
1914
 *
1915
 * @param bool   $addSessionId
1916
 * @param bool   $addGroupId
1917
 * @param string $origin
1918
 *
1919
 * @return string Course & session references to add to a URL
1920
 */
1921
function api_get_cidreq($addSessionId = true, $addGroupId = true, $origin = '')
1922
{
1923
    $courseId = api_get_course_int_id();
1924
    $url = empty($courseId) ? '' : 'cid='.$courseId;
1925
    $origin = empty($origin) ? api_get_origin() : Security::remove_XSS($origin);
1926
1927
    if ($addSessionId) {
1928
        if (!empty($url)) {
1929
            $url .= api_get_session_id() == 0 ? '&sid=0' : '&sid='.api_get_session_id();
1930
        }
1931
    }
1932
1933
    if ($addGroupId) {
1934
        if (!empty($url)) {
1935
            $url .= api_get_group_id() == 0 ? '&gid=0' : '&gid='.api_get_group_id();
1936
        }
1937
    }
1938
1939
    if (!empty($url)) {
1940
        $url .= '&gradebook='.(int) api_is_in_gradebook();
1941
        $url .= '&origin='.$origin;
1942
    }
1943
1944
    return $url;
1945
}
1946
1947
/**
1948
 * Get if we visited a gradebook page.
1949
 *
1950
 * @return bool
1951
 */
1952
function api_is_in_gradebook()
1953
{
1954
    return Session::read('in_gradebook', false);
1955
}
1956
1957
/**
1958
 * Set that we are in a page inside a gradebook.
1959
 */
1960
function api_set_in_gradebook()
1961
{
1962
    Session::write('in_gradebook', true);
1963
}
1964
1965
/**
1966
 * Remove gradebook session.
1967
 */
1968
function api_remove_in_gradebook()
1969
{
1970
    Session::erase('in_gradebook');
1971
}
1972
1973
/**
1974
 * Returns the current course info array see api_format_course_array()
1975
 * If the course_code is given, the returned array gives info about that
1976
 * particular course, if none given it gets the course info from the session.
1977
 *
1978
 * @param string $course_code
1979
 *
1980
 * @return array
1981
 */
1982
function api_get_course_info($course_code = null)
1983
{
1984
    if (!empty($course_code)) {
1985
        $course = Container::getCourseRepository()->findOneByCode($course_code);
1986
        if (empty($course)) {
1987
            return [];
1988
        }
1989
1990
        $courseInfo = api_format_course_array($course);
1991
1992
        return $courseInfo;
1993
    }
1994
1995
    /*$course_code = Database::escape_string($course_code);
1996
    $courseId = api_get_course_int_id($course_code);
1997
    if (empty($courseId)) {
1998
        return [];
1999
    }
2000
2001
    $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
2002
    $course_cat_table = Database::get_main_table(TABLE_MAIN_CATEGORY);
2003
    $sql = "SELECT
2004
                course.*,
2005
                course_category.code faCode,
2006
                course_category.name faName
2007
            FROM $course_table
2008
            LEFT JOIN $course_cat_table
2009
            ON course.category_code = course_category.code
2010
            WHERE course.id = $courseId";
2011
    $result = Database::query($sql);
2012
    $courseInfo = [];
2013
    if (Database::num_rows($result) > 0) {
2014
        $data = Database::fetch_array($result);
2015
        $courseInfo = api_format_course_array($data);
2016
    }
2017
2018
    return $courseInfo;*/
2019
2020
    $course = Session::read('_course');
2021
    if ($course == '-1') {
2022
        $course = [];
2023
    }
2024
2025
    return $course;
2026
}
2027
2028
/**
2029
 * @param int $courseId
2030
 *
2031
 * @return Course
2032
 */
2033
function api_get_course_entity($courseId = 0)
2034
{
2035
    if (empty($courseId)) {
2036
        $courseId = api_get_course_int_id();
2037
    }
2038
2039
    return CourseManager::getManager()->find($courseId);
0 ignored issues
show
Deprecated Code introduced by
The function CourseManager::getManager() has been deprecated. ( Ignorable by Annotation )

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

2039
    return /** @scrutinizer ignore-deprecated */ CourseManager::getManager()->find($courseId);
Loading history...
2040
}
2041
2042
/**
2043
 * @param int $id
2044
 *
2045
 * @return SessionEntity|null
2046
 */
2047
function api_get_session_entity($id = 0)
2048
{
2049
    if (empty($id)) {
2050
        $id = api_get_session_id();
2051
    }
2052
2053
    if (empty($id)) {
2054
        return null;
2055
    }
2056
2057
    return Database::getManager()->getRepository('ChamiloCoreBundle:Session')->find($id);
2058
}
2059
2060
/**
2061
 * @param int $id
2062
 *
2063
 * @return CGroupInfo
2064
 */
2065
function api_get_group_entity($id = 0)
2066
{
2067
    if (empty($id)) {
2068
        $id = api_get_group_id();
2069
    }
2070
2071
    return Database::getManager()->getRepository('ChamiloCourseBundle:CGroupInfo')->find($id);
2072
}
2073
2074
/**
2075
 * @param int $id
2076
 *
2077
 * @return AccessUrl
2078
 */
2079
function api_get_url_entity($id = 0)
2080
{
2081
    if (empty($id)) {
2082
        $id = api_get_current_access_url_id();
2083
    }
2084
2085
    return Container::getAccessUrlRepository()->find($id);
2086
}
2087
2088
/**
2089
 * Returns the current course info array.
2090
2091
 * Now if the course_code is given, the returned array gives info about that
2092
 * particular course, not specially the current one.
2093
 *
2094
 * @param int $id Numeric ID of the course
2095
 *
2096
 * @return array The course info as an array formatted by api_format_course_array, including category.name
2097
 */
2098
function api_get_course_info_by_id($id = 0)
2099
{
2100
    $id = (int) $id;
2101
    if (empty($id)) {
2102
        $course = Session::read('_course', []);
2103
2104
        return $course;
2105
    }
2106
2107
    $course = Container::getCourseRepository()->find($id);
2108
    if (empty($course)) {
2109
        return [];
2110
    }
2111
2112
    return api_format_course_array($course);
2113
}
2114
2115
/**
2116
 * Reformat the course array (output by api_get_course_info()) in order, mostly,
2117
 * to switch from 'code' to 'id' in the array.
2118
 *
2119
 * @return array
2120
 *
2121
 * @todo eradicate the false "id"=code field of the $_course array and use the int id
2122
 */
2123
function api_format_course_array(Course $course)
2124
{
2125
    if (empty($course)) {
2126
        return [];
2127
    }
2128
2129
    $category = $course->getCategory();
2130
2131
    $courseData = [];
2132
    $courseData['categoryCode'] = '';
2133
    $courseData['categoryName'] = '';
2134
    $courseData['category_id'] = 0;
2135
    if ($category) {
0 ignored issues
show
introduced by
$category is of type Chamilo\CoreBundle\Entity\CourseCategory, thus it always evaluated to true.
Loading history...
2136
        $courseData['categoryCode'] = $category->getCode();
2137
        $courseData['categoryName'] = $category->getName();
2138
        $courseData['category_id'] = $category->getId();
2139
    }
2140
2141
    $courseData['id'] = $courseData['real_id'] = $course->getId();
2142
2143
    // Added
2144
    $courseData['code'] = $courseData['sysCode'] = $course->getCode();
2145
    $courseData['name'] = $courseData['title'] = $course->getTitle();
2146
    $courseData['official_code'] = $courseData['visual_code'] = $course->getVisualCode();
2147
    $courseData['path'] = $courseData['directory'] = $course->getDirectory(); // Use as key in path.
2148
    $courseData['creation_date'] = $course->getCreationDate()->format('Y-m-d H:i:s');
2149
    $courseData['titular'] = $course->getTutorName();
2150
    $courseData['language'] = $courseData['course_language'] = $course->getCourseLanguage();
2151
    $courseData['extLink']['url'] = $courseData['department_url'] = $course->getDepartmentUrl();
2152
    $courseData['extLink']['name'] = $courseData['department_name'] = $course->getDepartmentName();
2153
2154
    $courseData['visibility'] = $course->getVisibility();
2155
    $courseData['subscribe_allowed'] = $courseData['subscribe'] = $course->getSubscribe();
2156
    $courseData['unsubscribe'] = $course->getUnsubscribe();
2157
    $courseData['activate_legal'] = $course->getActivateLegal();
2158
    $courseData['legal'] = $course->getLegal();
2159
    $courseData['show_score'] = $course->getShowScore(); //used in the work tool
2160
2161
    $coursePath = api_get_path(WEB_COURSE_PATH);
2162
    $webCourseHome = $coursePath.$courseData['real_id'].'/home';
2163
2164
    // Course password
2165
    $courseData['registration_code'] = $course->getRegistrationCode();
2166
    $courseData['disk_quota'] = $course->getDiskQuota();
2167
    $courseData['course_public_url'] = $webCourseHome;
2168
    $courseData['about_url'] = $coursePath.$courseData['real_id'].'/about';
2169
    $courseData['add_teachers_to_sessions_courses'] = $course->isAddTeachersToSessionsCourses();
2170
    $courseData['entity'] = $course;
2171
2172
    $image = Display::return_icon(
2173
        'course.png',
2174
        null,
2175
        null,
2176
        ICON_SIZE_BIG,
2177
        null,
2178
        true,
2179
        false
2180
    );
2181
2182
    $illustration = Container::getIllustrationRepository()->getIllustrationUrl($course);
2183
    if (!empty($illustration)) {
2184
        $image = $illustration;
2185
    }
2186
2187
    $courseData['course_image'] = $image.'?filter=course_picture_small';
2188
2189
    // Course large image
2190
    /*$courseData['course_image_large_source'] = '';
2191
    if (file_exists($courseSys.'/course-pic.png')) {
2192
        $url_image = $webCourseHome.'/course-pic.png';
2193
        $courseData['course_image_large_source'] = $courseSys.'/course-pic.png';
2194
    } else {
2195
        $url_image = Display::return_icon(
2196
            'session_default.png',
2197
            null,
2198
            null,
2199
            null,
2200
            null,
2201
            true,
2202
            true
2203
        );
2204
    }*/
2205
2206
    $courseData['course_image_large'] = $image.'?filter=course_picture_medium';
2207
2208
    return $courseData;
2209
}
2210
2211
/**
2212
 * Returns a difficult to guess password.
2213
 *
2214
 * @param int $length the length of the password
2215
 *
2216
 * @return string the generated password
2217
 */
2218
function api_generate_password($length = 8)
2219
{
2220
    if ($length < 2) {
2221
        $length = 2;
2222
    }
2223
2224
    $charactersLowerCase = 'abcdefghijkmnopqrstuvwxyz';
2225
    $charactersUpperCase = 'ABCDEFGHJKLMNPQRSTUVWXYZ';
2226
    $minNumbers = 2;
2227
    $length = $length - $minNumbers;
2228
    $minLowerCase = round($length / 2);
2229
    $minUpperCase = $length - $minLowerCase;
2230
2231
    $password = '';
2232
    $passwordRequirements = api_get_configuration_value('password_requirements');
2233
2234
    $factory = new RandomLib\Factory();
2235
    $generator = $factory->getGenerator(new SecurityLib\Strength(SecurityLib\Strength::MEDIUM));
2236
2237
    if (!empty($passwordRequirements)) {
2238
        $length = $passwordRequirements['min']['length'];
2239
        $minNumbers = $passwordRequirements['min']['numeric'];
2240
        $minLowerCase = $passwordRequirements['min']['lowercase'];
2241
        $minUpperCase = $passwordRequirements['min']['uppercase'];
2242
2243
        $rest = $length - $minNumbers - $minLowerCase - $minUpperCase;
2244
        // Add the rest to fill the length requirement
2245
        if ($rest > 0) {
2246
            $password .= $generator->generateString($rest, $charactersLowerCase.$charactersUpperCase);
2247
        }
2248
    }
2249
2250
    // Min digits default 2
2251
    for ($i = 0; $i < $minNumbers; $i++) {
2252
        $password .= $generator->generateInt(2, 9);
2253
    }
2254
2255
    // Min lowercase
2256
    $password .= $generator->generateString($minLowerCase, $charactersLowerCase);
2257
2258
    // Min uppercase
2259
    $password .= $generator->generateString($minUpperCase, $charactersUpperCase);
2260
    $password = str_shuffle($password);
2261
2262
    return $password;
2263
}
2264
2265
/**
2266
 * Checks a password to see wether it is OK to use.
2267
 *
2268
 * @param string $password
2269
 *
2270
 * @return bool if the password is acceptable, false otherwise
2271
 *              Notes about what a password "OK to use" is:
2272
 *              1. The password should be at least 5 characters long.
2273
 *              2. Only English letters (uppercase or lowercase, it doesn't matter) and digits are allowed.
2274
 *              3. The password should contain at least 3 letters.
2275
 *              4. It should contain at least 2 digits.
2276
 *              Settings will change if the configuration value is set: password_requirements
2277
 */
2278
function api_check_password($password)
2279
{
2280
    $passwordRequirements = Security::getPasswordRequirements();
2281
2282
    $minLength = $passwordRequirements['min']['length'];
2283
    $minNumbers = $passwordRequirements['min']['numeric'];
2284
    // Optional
2285
    $minLowerCase = $passwordRequirements['min']['lowercase'];
2286
    $minUpperCase = $passwordRequirements['min']['uppercase'];
2287
2288
    $minLetters = $minLowerCase + $minUpperCase;
2289
    $passwordLength = api_strlen($password);
2290
2291
    $conditions = [
2292
        'min_length' => $passwordLength >= $minLength,
2293
    ];
2294
2295
    $digits = 0;
2296
    $lowerCase = 0;
2297
    $upperCase = 0;
2298
2299
    for ($i = 0; $i < $passwordLength; $i++) {
2300
        $currentCharacterCode = api_ord(api_substr($password, $i, 1));
2301
        if ($currentCharacterCode >= 65 && $currentCharacterCode <= 90) {
2302
            $upperCase++;
2303
        }
2304
2305
        if ($currentCharacterCode >= 97 && $currentCharacterCode <= 122) {
2306
            $lowerCase++;
2307
        }
2308
        if ($currentCharacterCode >= 48 && $currentCharacterCode <= 57) {
2309
            $digits++;
2310
        }
2311
    }
2312
2313
    // Min number of digits
2314
    $conditions['min_numeric'] = $digits >= $minNumbers;
2315
2316
    if (!empty($minUpperCase)) {
2317
        // Uppercase
2318
        $conditions['min_uppercase'] = $upperCase >= $minUpperCase;
2319
    }
2320
2321
    if (!empty($minLowerCase)) {
2322
        // Lowercase
2323
        $conditions['min_lowercase'] = $upperCase >= $minLowerCase;
2324
    }
2325
2326
    // Min letters
2327
    $letters = $upperCase + $lowerCase;
2328
    $conditions['min_letters'] = $letters >= $minLetters;
2329
2330
    $isPasswordOk = true;
2331
    foreach ($conditions as $condition) {
2332
        if ($condition === false) {
2333
            $isPasswordOk = false;
2334
            break;
2335
        }
2336
    }
2337
2338
    if ($isPasswordOk === false) {
2339
        $output = get_lang('The new password does not match the minimum security requirements').'<br />';
2340
        $output .= Security::getPasswordRequirementsToString($conditions);
2341
2342
        Display::addFlash(Display::return_message($output, 'warning', false));
2343
    }
2344
2345
    return $isPasswordOk;
2346
}
2347
2348
/**
2349
 * Returns the status string corresponding to the status code.
2350
 *
2351
 * @author Noel Dieschburg
2352
 *
2353
 * @param the int status code
2354
 *
2355
 * @return string
2356
 */
2357
function get_status_from_code($status_code)
2358
{
2359
    switch ($status_code) {
2360
        case STUDENT:
2361
            return get_lang('Student', '');
2362
        case COURSEMANAGER:
2363
            return get_lang('Teacher', '');
2364
        case SESSIONADMIN:
2365
            return get_lang('SessionsAdmin', '');
2366
        case DRH:
2367
            return get_lang('Drh', '');
2368
    }
2369
}
2370
2371
/**
2372
 * Gets the current Chamilo (not PHP/cookie) session ID.
2373
 *
2374
 * @return int O if no active session, the session ID otherwise
2375
 */
2376
function api_get_session_id()
2377
{
2378
    return (int) Session::read('sid', 0);
2379
}
2380
2381
/**
2382
 * Gets the current Chamilo (not social network) group ID.
2383
 *
2384
 * @return int O if no active session, the session ID otherwise
2385
 */
2386
function api_get_group_id()
2387
{
2388
    return Session::read('gid', 0);
2389
}
2390
2391
/**
2392
 * Gets the current or given session name.
2393
 *
2394
 * @param   int     Session ID (optional)
2395
 *
2396
 * @return string The session name, or null if not found
2397
 */
2398
function api_get_session_name($session_id = 0)
2399
{
2400
    if (empty($session_id)) {
2401
        $session_id = api_get_session_id();
2402
        if (empty($session_id)) {
2403
            return null;
2404
        }
2405
    }
2406
    $t = Database::get_main_table(TABLE_MAIN_SESSION);
2407
    $s = "SELECT name FROM $t WHERE id = ".(int) $session_id;
2408
    $r = Database::query($s);
2409
    $c = Database::num_rows($r);
2410
    if ($c > 0) {
2411
        //technically, there can be only one, but anyway we take the first
2412
        $rec = Database::fetch_array($r);
2413
2414
        return $rec['name'];
2415
    }
2416
2417
    return null;
2418
}
2419
2420
/**
2421
 * Gets the session info by id.
2422
 *
2423
 * @param int $id Session ID
2424
 *
2425
 * @return array information of the session
2426
 */
2427
function api_get_session_info($id)
2428
{
2429
    return SessionManager::fetch($id);
2430
}
2431
2432
/**
2433
 * Gets the session visibility by session id.
2434
 *
2435
 * @param int  $session_id
2436
 * @param int  $courseId
2437
 * @param bool $ignore_visibility_for_admins
2438
 *
2439
 * @return int
2440
 *             0 = session still available,
2441
 *             SESSION_VISIBLE_READ_ONLY = 1,
2442
 *             SESSION_VISIBLE = 2,
2443
 *             SESSION_INVISIBLE = 3
2444
 */
2445
function api_get_session_visibility(
2446
    $session_id,
2447
    $courseId = null,
2448
    $ignore_visibility_for_admins = true
2449
) {
2450
    if (api_is_platform_admin()) {
2451
        if ($ignore_visibility_for_admins) {
2452
            return SESSION_AVAILABLE;
2453
        }
2454
    }
2455
2456
    $now = time();
2457
    if (empty($session_id)) {
2458
        return 0; // Means that the session is still available.
2459
    }
2460
2461
    $session_id = (int) $session_id;
2462
    $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
2463
2464
    $result = Database::query("SELECT * FROM $tbl_session WHERE id = $session_id");
2465
2466
    if (Database::num_rows($result) <= 0) {
2467
        return SESSION_INVISIBLE;
2468
    }
2469
2470
    $row = Database::fetch_array($result, 'ASSOC');
2471
    $visibility = $original_visibility = $row['visibility'];
2472
2473
    // I don't care the session visibility.
2474
    if (empty($row['access_start_date']) && empty($row['access_end_date'])) {
2475
        // Session duration per student.
2476
        if (isset($row['duration']) && !empty($row['duration'])) {
2477
            $duration = $row['duration'] * 24 * 60 * 60;
2478
            $courseAccess = CourseManager::getFirstCourseAccessPerSessionAndUser($session_id, api_get_user_id());
2479
2480
            // If there is a session duration but there is no previous
2481
            // access by the user, then the session is still available
2482
            if (count($courseAccess) == 0) {
2483
                return SESSION_AVAILABLE;
2484
            }
2485
2486
            $currentTime = time();
2487
            $firstAccess = isset($courseAccess['login_course_date'])
2488
                ? api_strtotime($courseAccess['login_course_date'], 'UTC')
2489
                : 0;
2490
            $userDurationData = SessionManager::getUserSession(
2491
                api_get_user_id(),
2492
                $session_id
2493
            );
2494
            $userDuration = isset($userDurationData['duration'])
2495
                ? (intval($userDurationData['duration']) * 24 * 60 * 60)
2496
                : 0;
2497
2498
            $totalDuration = $firstAccess + $duration + $userDuration;
2499
2500
            return $totalDuration > $currentTime ? SESSION_AVAILABLE : SESSION_VISIBLE_READ_ONLY;
2501
        }
2502
2503
        return SESSION_AVAILABLE;
2504
    }
2505
2506
    // If start date was set.
2507
    if (!empty($row['access_start_date'])) {
2508
        $visibility = $now > api_strtotime($row['access_start_date'], 'UTC') ? SESSION_AVAILABLE : SESSION_INVISIBLE;
2509
    }
2510
2511
    // If the end date was set.
2512
    if (!empty($row['access_end_date'])) {
2513
        // Only if date_start said that it was ok
2514
        if ($visibility === SESSION_AVAILABLE) {
2515
            $visibility = $now < api_strtotime($row['access_end_date'], 'UTC')
2516
                ? SESSION_AVAILABLE // Date still available
2517
                : $row['visibility']; // Session ends
2518
        }
2519
    }
2520
2521
    // If I'm a coach the visibility can change in my favor depending in the coach dates.
2522
    $isCoach = api_is_coach($session_id, $courseId);
2523
2524
    if ($isCoach) {
2525
        // Test start date.
2526
        if (!empty($row['coach_access_start_date'])) {
2527
            $start = api_strtotime($row['coach_access_start_date'], 'UTC');
2528
            $visibility = $start < $now ? SESSION_AVAILABLE : SESSION_INVISIBLE;
2529
        }
2530
2531
        // Test end date.
2532
        if (!empty($row['coach_access_end_date'])) {
2533
            if ($visibility === SESSION_AVAILABLE) {
2534
                $endDateCoach = api_strtotime($row['coach_access_end_date'], 'UTC');
2535
                $visibility = $endDateCoach >= $now ? SESSION_AVAILABLE : $row['visibility'];
2536
            }
2537
        }
2538
    }
2539
2540
    return $visibility;
2541
}
2542
2543
/**
2544
 * This function returns a (star) session icon if the session is not null and
2545
 * the user is not a student.
2546
 *
2547
 * @param int $sessionId
2548
 * @param int $statusId  User status id - if 5 (student), will return empty
2549
 *
2550
 * @return string Session icon
2551
 */
2552
function api_get_session_image($sessionId, $statusId)
2553
{
2554
    $sessionId = (int) $sessionId;
2555
    $image = '';
2556
    if ($statusId != STUDENT) {
2557
        // Check whether is not a student
2558
        if ($sessionId > 0) {
2559
            $image = '&nbsp;&nbsp;'.Display::return_icon(
2560
                'star.png',
2561
                get_lang('Session-specific resource'),
2562
                ['align' => 'absmiddle'],
2563
                ICON_SIZE_SMALL
2564
            );
2565
        }
2566
    }
2567
2568
    return $image;
2569
}
2570
2571
/**
2572
 * This function add an additional condition according to the session of the course.
2573
 *
2574
 * @param int    $session_id        session id
2575
 * @param bool   $and               optional, true if more than one condition false if the only condition in the query
2576
 * @param bool   $with_base_content optional, true to accept content with session=0 as well,
2577
 *                                  false for strict session condition
2578
 * @param string $session_field
2579
 *
2580
 * @return string condition of the session
2581
 */
2582
function api_get_session_condition(
2583
    $session_id,
2584
    $and = true,
2585
    $with_base_content = false,
2586
    $session_field = 'session_id'
2587
) {
2588
    $session_id = (int) $session_id;
2589
2590
    if (empty($session_field)) {
2591
        $session_field = 'session_id';
2592
    }
2593
    // Condition to show resources by session
2594
    $condition_add = $and ? ' AND ' : ' WHERE ';
2595
2596
    if ($with_base_content) {
2597
        $condition_session = $condition_add." ( $session_field = $session_id OR $session_field = 0 OR $session_field IS NULL) ";
2598
    } else {
2599
        if (empty($session_id)) {
2600
            $condition_session = $condition_add." ($session_field = $session_id OR $session_field IS NULL)";
2601
        } else {
2602
            $condition_session = $condition_add." $session_field = $session_id ";
2603
        }
2604
    }
2605
2606
    return $condition_session;
2607
}
2608
2609
/**
2610
 * Returns the value of a setting from the web-adjustable admin config settings.
2611
 *
2612
 * WARNING true/false are stored as string, so when comparing you need to check e.g.
2613
 * if (api_get_setting('show_navigation_menu') == 'true') //CORRECT
2614
 * instead of
2615
 * if (api_get_setting('show_navigation_menu') == true) //INCORRECT
2616
 *
2617
 * @param string $variable The variable name
2618
 *
2619
 * @return string
2620
 */
2621
function api_get_setting($variable)
2622
{
2623
    $settingsManager = Container::getSettingsManager();
2624
    if (empty($settingsManager)) {
2625
        return '';
2626
    }
2627
    $variable = trim($variable);
2628
2629
    switch ($variable) {
2630
        /*case 'header_extra_content':
2631
            $filename = api_get_path(SYS_PATH).api_get_home_path().'header_extra_content.txt';
2632
            if (file_exists($filename)) {
2633
                $value = file_get_contents($filename);
2634
2635
                return $value;
2636
            } else {
2637
                return '';
2638
            }
2639
            break;
2640
        case 'footer_extra_content':
2641
            $filename = api_get_path(SYS_PATH).api_get_home_path().'footer_extra_content.txt';
2642
            if (file_exists($filename)) {
2643
                $value = file_get_contents($filename);
2644
2645
                return $value;
2646
            } else {
2647
                return '';
2648
            }
2649
            break;*/
2650
        case 'server_type':
2651
            $test = ['dev', 'test'];
2652
            $environment = Container::getEnvironment();
2653
            if (in_array($environment, $test)) {
2654
                return 'test';
2655
            }
2656
2657
            return 'prod';
2658
        case 'stylesheets':
2659
            $variable = 'platform.theme';
2660
        // deprecated settings
2661
        // no break
2662
        case 'openid_authentication':
2663
        case 'service_ppt2lp':
2664
        case 'formLogin_hide_unhide_label':
2665
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type string.
Loading history...
2666
            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...
2667
        case 'tool_visible_by_default_at_creation':
2668
            $values = $settingsManager->getSetting($variable);
2669
            $newResult = [];
2670
            foreach ($values as $parameter) {
2671
                $newResult[$parameter] = 'true';
2672
            }
2673
2674
            return $newResult;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $newResult returns the type array which is incompatible with the documented return type string.
Loading history...
2675
            break;
2676
        default:
2677
            return $settingsManager->getSetting($variable);
2678
            break;
2679
    }
2680
2681
    global $_setting;
0 ignored issues
show
Unused Code introduced by
GlobalNode 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...
2682
    /*if ($variable == 'header_extra_content') {
2683
        $filename = api_get_home_path().'header_extra_content.txt';
2684
        if (file_exists($filename)) {
2685
            $value = file_get_contents($filename);
2686
2687
            return $value;
2688
        } else {
2689
            return '';
2690
        }
2691
    }
2692
    if ($variable == 'footer_extra_content') {
2693
        $filename = api_get_home_path().'footer_extra_content.txt';
2694
        if (file_exists($filename)) {
2695
            $value = file_get_contents($filename);
2696
2697
            return $value;
2698
        } else {
2699
            return '';
2700
        }
2701
    }*/
2702
    $value = null;
2703
    if (is_null($key)) {
2704
        $value = ((isset($_setting[$variable]) && $_setting[$variable] != '') ? $_setting[$variable] : null);
2705
    } else {
2706
        if (isset($_setting[$variable][$key])) {
2707
            $value = $_setting[$variable][$key];
2708
        }
2709
    }
2710
2711
    return $value;
2712
}
2713
2714
/**
2715
 * @param string $variable
2716
 * @param string $option
2717
 *
2718
 * @return bool
2719
 */
2720
function api_get_setting_in_list($variable, $option)
2721
{
2722
    $value = api_get_setting($variable);
2723
2724
    return in_array($option, $value);
2725
}
2726
2727
/**
2728
 * @param string $plugin
2729
 * @param string $variable
2730
 *
2731
 * @return string
2732
 */
2733
function api_get_plugin_setting($plugin, $variable)
2734
{
2735
    $variableName = $plugin.'_'.$variable;
2736
2737
    $params = [
2738
        'category = ? AND subkey = ? AND variable = ?' => [
2739
            'Plugins',
2740
            $plugin,
2741
            $variableName,
2742
        ],
2743
    ];
2744
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2745
    $result = Database::select(
2746
        'selected_value',
2747
        $table,
2748
        ['where' => $params],
2749
        'one'
2750
    );
2751
    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...
2752
        $value = $result['selected_value'];
2753
        $serializedValue = @unserialize($result['selected_value'], []);
2754
        if ($serializedValue !== false) {
2755
            $value = $serializedValue;
2756
        }
2757
2758
        return $value;
2759
    }
2760
2761
    return null;
2762
    /// Old code
2763
2764
    $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...
2765
    $result = api_get_setting($variableName);
2766
2767
    if (isset($result[$plugin])) {
2768
        $value = $result[$plugin];
2769
2770
        $unserialized = UnserializeApi::unserialize('not_allowed_classes', $value, true);
2771
2772
        if (false !== $unserialized) {
2773
            $value = $unserialized;
2774
        }
2775
2776
        return $value;
2777
    }
2778
2779
    return null;
2780
}
2781
2782
/**
2783
 * Returns the value of a setting from the web-adjustable admin config settings.
2784
 */
2785
function api_get_settings_params($params)
2786
{
2787
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2788
    $result = Database::select('*', $table, ['where' => $params]);
2789
2790
    return $result;
2791
}
2792
2793
/**
2794
 * @param array $params example: [id = ? => '1']
2795
 *
2796
 * @return array
2797
 */
2798
function api_get_settings_params_simple($params)
2799
{
2800
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2801
    $result = Database::select('*', $table, ['where' => $params], 'one');
2802
2803
    return $result;
2804
}
2805
2806
/**
2807
 * Returns the value of a setting from the web-adjustable admin config settings.
2808
 */
2809
function api_delete_settings_params($params)
2810
{
2811
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2812
    $result = Database::delete($table, $params);
2813
2814
    return $result;
2815
}
2816
2817
/**
2818
 * Returns an escaped version of $_SERVER['PHP_SELF'] to avoid XSS injection.
2819
 *
2820
 * @return string Escaped version of $_SERVER['PHP_SELF']
2821
 */
2822
function api_get_self()
2823
{
2824
    return htmlentities($_SERVER['PHP_SELF']);
2825
}
2826
2827
/* USER PERMISSIONS */
2828
2829
/**
2830
 * Checks whether current user is a platform administrator.
2831
 *
2832
 * @param bool $allowSessionAdmins Whether session admins should be considered admins or not
2833
 * @param bool $allowDrh           Whether HR directors should be considered admins or not
2834
 *
2835
 * @return bool true if the user has platform admin rights,
2836
 *              false otherwise
2837
 *
2838
 * @see usermanager::is_admin(user_id) for a user-id specific function
2839
 */
2840
function api_is_platform_admin($allowSessionAdmins = false, $allowDrh = false)
2841
{
2842
    $currentUser = api_get_current_user();
2843
2844
    if ($currentUser === null) {
2845
        return false;
2846
    }
2847
2848
    $isAdmin = Session::read('is_platformAdmin');
2849
    if ($isAdmin) {
2850
        return true;
2851
    }
2852
    $user = api_get_user_info();
2853
2854
    return
2855
        isset($user['status']) &&
2856
        (
2857
            ($allowSessionAdmins && $user['status'] == SESSIONADMIN) ||
2858
            ($allowDrh && $user['status'] == DRH)
2859
        );
2860
}
2861
2862
/**
2863
 * Checks whether the user given as user id is in the admin table.
2864
 *
2865
 * @param int $user_id If none provided, will use current user
2866
 * @param int $url     URL ID. If provided, also check if the user is active on given URL
2867
 *
2868
 * @return bool True if the user is admin, false otherwise
2869
 */
2870
function api_is_platform_admin_by_id($user_id = null, $url = null)
2871
{
2872
    $user_id = (int) $user_id;
2873
    if (empty($user_id)) {
2874
        $user_id = api_get_user_id();
2875
    }
2876
    $admin_table = Database::get_main_table(TABLE_MAIN_ADMIN);
2877
    $sql = "SELECT * FROM $admin_table WHERE user_id = $user_id";
2878
    $res = Database::query($sql);
2879
    $is_admin = Database::num_rows($res) === 1;
2880
    if (!$is_admin || !isset($url)) {
2881
        return $is_admin;
2882
    }
2883
    // We get here only if $url is set
2884
    $url = (int) $url;
2885
    $url_user_table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
2886
    $sql = "SELECT * FROM $url_user_table
2887
            WHERE access_url_id = $url AND user_id = $user_id";
2888
    $res = Database::query($sql);
2889
    $result = Database::num_rows($res) === 1;
2890
2891
    return $result;
2892
}
2893
2894
/**
2895
 * Returns the user's numeric status ID from the users table.
2896
 *
2897
 * @param int $user_id If none provided, will use current user
2898
 *
2899
 * @return int User's status (1 for teacher, 5 for student, etc)
2900
 */
2901
function api_get_user_status($user_id = null)
2902
{
2903
    $user_id = (int) $user_id;
2904
    if (empty($user_id)) {
2905
        $user_id = api_get_user_id();
2906
    }
2907
    $table = Database::get_main_table(TABLE_MAIN_USER);
2908
    $sql = "SELECT status FROM $table WHERE user_id = $user_id ";
2909
    $result = Database::query($sql);
2910
    $status = null;
2911
    if (Database::num_rows($result)) {
2912
        $row = Database::fetch_array($result);
2913
        $status = $row['status'];
2914
    }
2915
2916
    return $status;
2917
}
2918
2919
/**
2920
 * Checks whether current user is allowed to create courses.
2921
 *
2922
 * @return bool true if the user has course creation rights,
2923
 *              false otherwise
2924
 */
2925
function api_is_allowed_to_create_course()
2926
{
2927
    if (api_is_platform_admin()) {
2928
        return true;
2929
    }
2930
2931
    // Teachers can only create courses
2932
    if (api_is_teacher()) {
2933
        if (api_get_setting('allow_users_to_create_courses') === 'true') {
2934
            return true;
2935
        } else {
2936
            return false;
2937
        }
2938
    }
2939
2940
    return Session::read('is_allowedCreateCourse');
2941
}
2942
2943
/**
2944
 * Checks whether the current user is a course administrator.
2945
 *
2946
 * @return bool True if current user is a course administrator
2947
 */
2948
function api_is_course_admin()
2949
{
2950
    if (api_is_platform_admin()) {
2951
        return true;
2952
    }
2953
2954
    $user = api_get_current_user();
2955
    if ($user) {
2956
        if (
2957
            $user->hasRole('ROLE_CURRENT_SESSION_COURSE_TEACHER') ||
2958
            $user->hasRole('ROLE_CURRENT_COURSE_TEACHER')
2959
        ) {
2960
            return true;
2961
        }
2962
    }
2963
2964
    return false;
2965
    //return Session::read('is_courseAdmin');
2966
}
2967
2968
/**
2969
 * Checks whether the current user is a course coach
2970
 * Based on the presence of user in session.id_coach (session general coach).
2971
 *
2972
 * @return bool True if current user is a course coach
2973
 */
2974
function api_is_session_general_coach()
2975
{
2976
    return Session::read('is_session_general_coach');
2977
}
2978
2979
/**
2980
 * Checks whether the current user is a course tutor
2981
 * Based on the presence of user in session_rel_course_rel_user.user_id with status = 2.
2982
 *
2983
 * @return bool True if current user is a course tutor
2984
 */
2985
function api_is_course_tutor()
2986
{
2987
    return Session::read('is_courseTutor');
2988
}
2989
2990
/**
2991
 * @param int $user_id
2992
 * @param int $courseId
2993
 * @param int $session_id
2994
 *
2995
 * @return bool
2996
 */
2997
function api_is_course_session_coach($user_id, $courseId, $session_id)
2998
{
2999
    $session_table = Database::get_main_table(TABLE_MAIN_SESSION);
3000
    $session_rel_course_rel_user_table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3001
3002
    $user_id = (int) $user_id;
3003
    $session_id = (int) $session_id;
3004
    $courseId = (int) $courseId;
3005
3006
    $sql = "SELECT DISTINCT session.id
3007
            FROM $session_table
3008
            INNER JOIN $session_rel_course_rel_user_table session_rc_ru
3009
            ON session.id = session_rc_ru.session_id
3010
            WHERE
3011
                session_rc_ru.user_id = '".$user_id."'  AND
3012
                session_rc_ru.c_id = '$courseId' AND
3013
                session_rc_ru.status = 2 AND
3014
                session_rc_ru.session_id = '$session_id'";
3015
    $result = Database::query($sql);
3016
3017
    return Database::num_rows($result) > 0;
3018
}
3019
3020
/**
3021
 * Checks whether the current user is a course or session coach.
3022
 *
3023
 * @param int $session_id
3024
 * @param int $courseId
3025
 * @param bool  Check whether we are in student view and, if we are, return false
3026
 *
3027
 * @return bool True if current user is a course or session coach
3028
 */
3029
function api_is_coach($session_id = 0, $courseId = null, $check_student_view = true)
3030
{
3031
    $userId = api_get_user_id();
3032
3033
    if (!empty($session_id)) {
3034
        $session_id = (int) $session_id;
3035
    } else {
3036
        $session_id = api_get_session_id();
3037
    }
3038
3039
    // The student preview was on
3040
    if ($check_student_view && api_is_student_view_active()) {
3041
        return false;
3042
    }
3043
3044
    if (!empty($courseId)) {
3045
        $courseId = (int) $courseId;
3046
    } else {
3047
        $courseId = api_get_course_int_id();
3048
    }
3049
3050
    $session_table = Database::get_main_table(TABLE_MAIN_SESSION);
3051
    $session_rel_course_rel_user_table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3052
    $sessionIsCoach = [];
3053
3054
    if (!empty($courseId)) {
3055
        $sql = "SELECT DISTINCT s.id, name, access_start_date, access_end_date
3056
                FROM $session_table s
3057
                INNER JOIN $session_rel_course_rel_user_table session_rc_ru
3058
                ON session_rc_ru.session_id = s.id AND session_rc_ru.user_id = '".$userId."'
3059
                WHERE
3060
                    session_rc_ru.c_id = '$courseId' AND
3061
                    session_rc_ru.status = 2 AND
3062
                    session_rc_ru.session_id = '$session_id'";
3063
        $result = Database::query($sql);
3064
        $sessionIsCoach = Database::store_result($result);
3065
    }
3066
3067
    if (!empty($session_id)) {
3068
        $sql = "SELECT DISTINCT id, name, access_start_date, access_end_date
3069
                FROM $session_table
3070
                WHERE session.id_coach = $userId AND id = $session_id
3071
                ORDER BY access_start_date, access_end_date, name";
3072
        $result = Database::query($sql);
3073
        if (!empty($sessionIsCoach)) {
3074
            $sessionIsCoach = array_merge(
3075
                $sessionIsCoach,
3076
                Database::store_result($result)
3077
            );
3078
        } else {
3079
            $sessionIsCoach = Database::store_result($result);
3080
        }
3081
    }
3082
3083
    return count($sessionIsCoach) > 0;
3084
}
3085
3086
/**
3087
 * Checks whether the current user is a session administrator.
3088
 *
3089
 * @return bool True if current user is a course administrator
3090
 */
3091
function api_is_session_admin()
3092
{
3093
    $user = api_get_user_info();
3094
3095
    return isset($user['status']) && $user['status'] == SESSIONADMIN;
3096
}
3097
3098
/**
3099
 * Checks whether the current user is a human resources manager.
3100
 *
3101
 * @return bool True if current user is a human resources manager
3102
 */
3103
function api_is_drh()
3104
{
3105
    $user = api_get_user_info();
3106
3107
    return isset($user['status']) && $user['status'] == DRH;
3108
}
3109
3110
/**
3111
 * Checks whether the current user is a student.
3112
 *
3113
 * @return bool True if current user is a human resources manager
3114
 */
3115
function api_is_student()
3116
{
3117
    $user = api_get_user_info();
3118
3119
    return isset($user['status']) && $user['status'] == STUDENT;
3120
}
3121
3122
/**
3123
 * Checks whether the current user has the status 'teacher'.
3124
 *
3125
 * @return bool True if current user is a human resources manager
3126
 */
3127
function api_is_teacher()
3128
{
3129
    $user = api_get_user_info();
3130
3131
    return isset($user['status']) && $user['status'] == COURSEMANAGER;
3132
}
3133
3134
/**
3135
 * Checks whether the current user is a invited user.
3136
 *
3137
 * @return bool
3138
 */
3139
function api_is_invitee()
3140
{
3141
    $user = api_get_user_info();
3142
3143
    return isset($user['status']) && $user['status'] == INVITEE;
3144
}
3145
3146
/**
3147
 * This function checks whether a session is assigned into a category.
3148
 *
3149
 * @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...
3150
 * @param string    - category name
3151
 *
3152
 * @return bool - true if is found, otherwise false
3153
 */
3154
function api_is_session_in_category($session_id, $category_name)
3155
{
3156
    $session_id = (int) $session_id;
3157
    $category_name = Database::escape_string($category_name);
3158
    $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
3159
    $tbl_session_category = Database::get_main_table(TABLE_MAIN_SESSION_CATEGORY);
3160
3161
    $sql = "SELECT 1
3162
            FROM $tbl_session
3163
            WHERE $session_id IN (
3164
                SELECT s.id FROM $tbl_session s, $tbl_session_category sc
3165
                WHERE
3166
                  s.session_category_id = sc.id AND
3167
                  sc.name LIKE '%$category_name'
3168
            )";
3169
    $rs = Database::query($sql);
3170
3171
    if (Database::num_rows($rs) > 0) {
3172
        return true;
3173
    } else {
3174
        return false;
3175
    }
3176
}
3177
3178
/**
3179
 * Displays the title of a tool.
3180
 * Normal use: parameter is a string:
3181
 * api_display_tool_title("My Tool").
3182
 *
3183
 * Optionally, there can be a subtitle below
3184
 * the normal title, and / or a supra title above the normal title.
3185
 *
3186
 * e.g. supra title:
3187
 * group
3188
 * GROUP PROPERTIES
3189
 *
3190
 * e.g. subtitle:
3191
 * AGENDA
3192
 * calender & events tool
3193
 *
3194
 * @author Hugues Peeters <[email protected]>
3195
 *
3196
 * @param mixed $title_element - it could either be a string or an array
3197
 *                             containing 'supraTitle', 'mainTitle',
3198
 *                             'subTitle'
3199
 */
3200
function api_display_tool_title($title_element)
3201
{
3202
    if (is_string($title_element)) {
3203
        $tit = $title_element;
3204
        unset($title_element);
3205
        $title_element['mainTitle'] = $tit;
3206
    }
3207
    echo '<h3>';
3208
    if (!empty($title_element['supraTitle'])) {
3209
        echo '<small>'.$title_element['supraTitle'].'</small><br />';
3210
    }
3211
    if (!empty($title_element['mainTitle'])) {
3212
        echo $title_element['mainTitle'];
3213
    }
3214
    if (!empty($title_element['subTitle'])) {
3215
        echo '<br /><small>'.$title_element['subTitle'].'</small>';
3216
    }
3217
    echo '</h3>';
3218
}
3219
3220
/**
3221
 * Displays options for switching between student view and course manager view.
3222
 *
3223
 * Changes in version 1.2 (Patrick Cool)
3224
 * Student view switch now behaves as a real switch. It maintains its current state until the state
3225
 * is changed explicitly
3226
 *
3227
 * Changes in version 1.1 (Patrick Cool)
3228
 * student view now works correctly in subfolders of the document tool
3229
 * student view works correctly in the new links tool
3230
 *
3231
 * Example code for using this in your tools:
3232
 * //if ($is_courseAdmin && api_get_setting('student_view_enabled') == 'true') {
3233
 * //   display_tool_view_option($isStudentView);
3234
 * //}
3235
 * //and in later sections, use api_is_allowed_to_edit()
3236
 *
3237
 * @author Roan Embrechts
3238
 * @author Patrick Cool
3239
 * @author Julio Montoya, changes added in Chamilo
3240
 *
3241
 * @version 1.2
3242
 *
3243
 * @todo rewrite code so it is easier to understand
3244
 */
3245
function api_display_tool_view_option()
3246
{
3247
    if (api_get_setting('student_view_enabled') != 'true') {
3248
        return '';
3249
    }
3250
3251
    $sourceurl = '';
3252
    $is_framed = false;
3253
    // Exceptions apply for all multi-frames pages
3254
    if (strpos($_SERVER['REQUEST_URI'], 'chat/chat_banner.php') !== false) {
3255
        // The chat is a multiframe bit that doesn't work too well with the student_view, so do not show the link
3256
        return '';
3257
    }
3258
3259
    // Uncomment to remove student view link from document view page
3260
    if (strpos($_SERVER['REQUEST_URI'], 'lp/lp_header.php') !== false) {
3261
        if (empty($_GET['lp_id'])) {
3262
            return '';
3263
        }
3264
        $sourceurl = substr($_SERVER['REQUEST_URI'], 0, strpos($_SERVER['REQUEST_URI'], '?'));
3265
        $sourceurl = str_replace(
3266
            'lp/lp_header.php',
3267
            'lp/lp_controller.php?'.api_get_cidreq().'&action=view&lp_id='.intval($_GET['lp_id']).'&isStudentView='.($_SESSION['studentview'] == 'studentview' ? 'false' : 'true'),
3268
            $sourceurl
3269
        );
3270
        //showinframes doesn't handle student view anyway...
3271
        //return '';
3272
        $is_framed = true;
3273
    }
3274
3275
    // Check whether the $_SERVER['REQUEST_URI'] contains already url parameters (thus a questionmark)
3276
    if (!$is_framed) {
3277
        if (strpos($_SERVER['REQUEST_URI'], '?') === false) {
3278
            $sourceurl = api_get_self().'?'.api_get_cidreq();
3279
        } else {
3280
            $sourceurl = $_SERVER['REQUEST_URI'];
3281
        }
3282
    }
3283
3284
    $output_string = '';
3285
    if (!empty($_SESSION['studentview'])) {
3286
        if ($_SESSION['studentview'] == 'studentview') {
3287
            // We have to remove the isStudentView=true from the $sourceurl
3288
            $sourceurl = str_replace('&isStudentView=true', '', $sourceurl);
3289
            $sourceurl = str_replace('&isStudentView=false', '', $sourceurl);
3290
            $output_string .= '<a class="btn btn-primary btn-sm" href="'.$sourceurl.'&isStudentView=false" target="_self">'.
3291
                Display::returnFontAwesomeIcon('eye').' '.get_lang('Switch to teacher view').'</a>';
3292
        } elseif ($_SESSION['studentview'] == 'teacherview') {
3293
            // Switching to teacherview
3294
            $sourceurl = str_replace('&isStudentView=true', '', $sourceurl);
3295
            $sourceurl = str_replace('&isStudentView=false', '', $sourceurl);
3296
            $output_string .= '<a class="btn btn-default btn-sm" href="'.$sourceurl.'&isStudentView=true" target="_self">'.
3297
                Display::returnFontAwesomeIcon('eye').' '.get_lang('Switch to student view').'</a>';
3298
        }
3299
    } else {
3300
        $output_string .= '<a class="btn btn-default btn-sm" href="'.$sourceurl.'&isStudentView=true" target="_self">'.
3301
            Display::returnFontAwesomeIcon('eye').' '.get_lang('Switch to student view').'</a>';
3302
    }
3303
    $output_string = Security::remove_XSS($output_string);
3304
    $html = Display::tag('div', $output_string, ['class' => 'view-options']);
3305
3306
    return $html;
3307
}
3308
3309
// TODO: This is for the permission section.
3310
/**
3311
 * Function that removes the need to directly use is_courseAdmin global in
3312
 * tool scripts. It returns true or false depending on the user's rights in
3313
 * this particular course.
3314
 * Optionally checking for tutor and coach roles here allows us to use the
3315
 * student_view feature altogether with these roles as well.
3316
 *
3317
 * @param bool  Whether to check if the user has the tutor role
3318
 * @param bool  Whether to check if the user has the coach role
3319
 * @param bool  Whether to check if the user has the session coach role
3320
 * @param bool  check the student view or not
3321
 *
3322
 * @author Roan Embrechts
3323
 * @author Patrick Cool
3324
 * @author Julio Montoya
3325
 *
3326
 * @version 1.1, February 2004
3327
 *
3328
 * @return bool true: the user has the rights to edit, false: he does not
3329
 */
3330
function api_is_allowed_to_edit(
3331
    $tutor = false,
3332
    $coach = false,
3333
    $session_coach = false,
3334
    $check_student_view = true
3335
) {
3336
    $allowSessionAdminEdit = api_get_setting('session.session_admins_edit_courses_content') === true;
3337
    // Admins can edit anything.
3338
    if (api_is_platform_admin($allowSessionAdminEdit)) {
3339
        //The student preview was on
3340
        if ($check_student_view && api_is_student_view_active()) {
3341
            return false;
3342
        } else {
3343
            return true;
3344
        }
3345
    }
3346
3347
    $sessionId = api_get_session_id();
3348
3349
    if ($sessionId && api_get_configuration_value('session_courses_read_only_mode')) {
3350
        $efv = new ExtraFieldValue('course');
3351
        $lockExrafieldField = $efv->get_values_by_handler_and_field_variable(
3352
            api_get_course_int_id(),
3353
            'session_courses_read_only_mode'
3354
        );
3355
3356
        if (!empty($lockExrafieldField['value'])) {
3357
            return false;
3358
        }
3359
    }
3360
3361
    $is_allowed_coach_to_edit = api_is_coach(null, null, $check_student_view);
3362
    $session_visibility = api_get_session_visibility($sessionId);
3363
    $is_courseAdmin = api_is_course_admin();
3364
3365
    if (!$is_courseAdmin && $tutor) {
3366
        // If we also want to check if the user is a tutor...
3367
        $is_courseAdmin = $is_courseAdmin || api_is_course_tutor();
3368
    }
3369
3370
    if (!$is_courseAdmin && $coach) {
3371
        // If we also want to check if the user is a coach...';
3372
        // Check if session visibility is read only for coaches.
3373
        if ($session_visibility == SESSION_VISIBLE_READ_ONLY) {
3374
            $is_allowed_coach_to_edit = false;
3375
        }
3376
3377
        if (api_get_setting('allow_coach_to_edit_course_session') === 'true') {
3378
            // Check if coach is allowed to edit a course.
3379
            $is_courseAdmin = $is_courseAdmin || $is_allowed_coach_to_edit;
3380
        }
3381
    }
3382
3383
    if (!$is_courseAdmin && $session_coach) {
3384
        $is_courseAdmin = $is_courseAdmin || $is_allowed_coach_to_edit;
3385
    }
3386
3387
    // Check if the student_view is enabled, and if so, if it is activated.
3388
    if (api_get_setting('student_view_enabled') === 'true') {
3389
        $studentView = api_is_student_view_active();
3390
        if (!empty($sessionId)) {
3391
            // Check if session visibility is read only for coaches.
3392
            if ($session_visibility == SESSION_VISIBLE_READ_ONLY) {
3393
                $is_allowed_coach_to_edit = false;
3394
            }
3395
3396
            $is_allowed = false;
3397
            if (api_get_setting('allow_coach_to_edit_course_session') === 'true') {
3398
                // Check if coach is allowed to edit a course.
3399
                $is_allowed = $is_allowed_coach_to_edit;
3400
            }
3401
            if ($check_student_view) {
3402
                $is_allowed = $is_allowed && $studentView === false;
3403
            }
3404
        } else {
3405
            $is_allowed = $is_courseAdmin;
3406
            if ($check_student_view) {
3407
                $is_allowed = $is_courseAdmin && $studentView === false;
3408
            }
3409
        }
3410
3411
        return $is_allowed;
3412
    } else {
3413
        return $is_courseAdmin;
3414
    }
3415
}
3416
3417
/**
3418
 * Returns true if user is a course coach of at least one course in session.
3419
 *
3420
 * @param int $sessionId
3421
 *
3422
 * @return bool
3423
 */
3424
function api_is_coach_of_course_in_session($sessionId)
3425
{
3426
    if (api_is_platform_admin()) {
3427
        return true;
3428
    }
3429
3430
    $userId = api_get_user_id();
3431
    $courseList = UserManager::get_courses_list_by_session(
3432
        $userId,
3433
        $sessionId
3434
    );
3435
3436
    // Session visibility.
3437
    $visibility = api_get_session_visibility(
3438
        $sessionId,
3439
        null,
3440
        false
3441
    );
3442
3443
    if ($visibility != SESSION_VISIBLE && !empty($courseList)) {
3444
        // Course Coach session visibility.
3445
        $blockedCourseCount = 0;
3446
        $closedVisibilityList = [
3447
            COURSE_VISIBILITY_CLOSED,
3448
            COURSE_VISIBILITY_HIDDEN,
3449
        ];
3450
3451
        foreach ($courseList as $course) {
3452
            // Checking session visibility
3453
            $sessionCourseVisibility = api_get_session_visibility(
3454
                $sessionId,
3455
                $course['real_id']
3456
            );
3457
3458
            $courseIsVisible = !in_array(
3459
                $course['visibility'],
3460
                $closedVisibilityList
3461
            );
3462
            if ($courseIsVisible === false || $sessionCourseVisibility == SESSION_INVISIBLE) {
3463
                $blockedCourseCount++;
3464
            }
3465
        }
3466
3467
        // If all courses are blocked then no show in the list.
3468
        if ($blockedCourseCount === count($courseList)) {
3469
            $visibility = SESSION_INVISIBLE;
3470
        } else {
3471
            $visibility = SESSION_VISIBLE;
3472
        }
3473
    }
3474
3475
    switch ($visibility) {
3476
        case SESSION_VISIBLE_READ_ONLY:
3477
        case SESSION_VISIBLE:
3478
        case SESSION_AVAILABLE:
3479
            return true;
3480
            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...
3481
        case SESSION_INVISIBLE:
3482
            return false;
3483
    }
3484
3485
    return false;
3486
}
3487
3488
/**
3489
 * Checks if a student can edit contents in a session depending
3490
 * on the session visibility.
3491
 *
3492
 * @param bool $tutor Whether to check if the user has the tutor role
3493
 * @param bool $coach Whether to check if the user has the coach role
3494
 *
3495
 * @return bool true: the user has the rights to edit, false: he does not
3496
 */
3497
function api_is_allowed_to_session_edit($tutor = false, $coach = false)
3498
{
3499
    if (api_is_allowed_to_edit($tutor, $coach)) {
3500
        // If I'm a teacher, I will return true in order to not affect the normal behaviour of Chamilo tools.
3501
        return true;
3502
    } else {
3503
        $sessionId = api_get_session_id();
3504
3505
        if ($sessionId == 0) {
3506
            // I'm not in a session so i will return true to not affect the normal behaviour of Chamilo tools.
3507
            return true;
3508
        } else {
3509
            // I'm in a session and I'm a student
3510
            // Get the session visibility
3511
            $session_visibility = api_get_session_visibility($sessionId);
3512
            // if 5 the session is still available
3513
            switch ($session_visibility) {
3514
                case SESSION_VISIBLE_READ_ONLY: // 1
3515
                    return false;
3516
                case SESSION_VISIBLE:           // 2
3517
                    return true;
3518
                case SESSION_INVISIBLE:         // 3
3519
                    return false;
3520
                case SESSION_AVAILABLE:         //5
3521
                    return true;
3522
            }
3523
        }
3524
    }
3525
}
3526
3527
/**
3528
 * Checks whether the user is allowed in a specific tool for a specific action.
3529
 *
3530
 * @param string $tool   the tool we are checking if the user has a certain permission
3531
 * @param string $action the action we are checking (add, edit, delete, move, visibility)
3532
 *
3533
 * @return bool
3534
 *
3535
 * @author Patrick Cool <[email protected]>, Ghent University
3536
 * @author Julio Montoya
3537
 *
3538
 * @version 1.0
3539
 */
3540
function api_is_allowed($tool, $action, $task_id = 0)
3541
{
3542
    $_user = api_get_user_info();
3543
    $_course = api_get_course_info();
3544
3545
    if (api_is_course_admin()) {
3546
        return true;
3547
    }
3548
3549
    if (is_array($_course) and count($_course) > 0) {
3550
        require_once api_get_path(SYS_CODE_PATH).'permissions/permissions_functions.inc.php';
3551
3552
        // Getting the permissions of this user.
3553
        if ($task_id == 0) {
3554
            $user_permissions = get_permissions('user', $_user['user_id']);
3555
            $_SESSION['total_permissions'][$_course['code']] = $user_permissions;
3556
        }
3557
3558
        // Getting the permissions of the task.
3559
        if ($task_id != 0) {
3560
            $task_permissions = get_permissions('task', $task_id);
3561
            /* !!! */$_SESSION['total_permissions'][$_course['code']] = $task_permissions;
3562
        }
3563
        //print_r($_SESSION['total_permissions']);
3564
3565
        // Getting the permissions of the groups of the user
3566
        //$groups_of_user = GroupManager::get_group_ids($_course['db_name'], $_user['user_id']);
3567
3568
        //foreach($groups_of_user as $group)
3569
        //   $this_group_permissions = get_permissions('group', $group);
3570
3571
        // Getting the permissions of the courseroles of the user
3572
        $user_courserole_permissions = get_roles_permissions('user', $_user['user_id']);
3573
3574
        // Getting the permissions of the platformroles of the user
3575
        //$user_platformrole_permissions = get_roles_permissions('user', $_user['user_id'], ', platform');
3576
3577
        // Getting the permissions of the roles of the groups of the user
3578
        //foreach($groups_of_user as $group)
3579
        //    $this_group_courserole_permissions = get_roles_permissions('group', $group);
3580
3581
        // Getting the permissions of the platformroles of the groups of the user
3582
        //foreach($groups_of_user as $group)
3583
        //    $this_group_platformrole_permissions = get_roles_permissions('group', $group, 'platform');
3584
    }
3585
3586
    // If the permissions are limited, we have to map the extended ones to the limited ones.
3587
    if (api_get_setting('permissions') == 'limited') {
3588
        if ($action == 'Visibility') {
3589
            $action = 'Edit';
3590
        }
3591
        if ($action == 'Move') {
3592
            $action = 'Edit';
3593
        }
3594
    }
3595
3596
    // The session that contains all the permissions already exists for this course
3597
    // so there is no need to requery everything.
3598
    //my_print_r($_SESSION['total_permissions'][$_course['code']][$tool]);
3599
    if (is_array($_SESSION['total_permissions'][$_course['code']][$tool])) {
3600
        if (in_array($action, $_SESSION['total_permissions'][$_course['code']][$tool])) {
3601
            return true;
3602
        } else {
3603
            return false;
3604
        }
3605
    }
3606
}
3607
3608
/**
3609
 * Tells whether this user is an anonymous user.
3610
 *
3611
 * @param int  $user_id  User ID (optional, will take session ID if not provided)
3612
 * @param bool $db_check Whether to check in the database (true) or simply in
3613
 *                       the session (false) to see if the current user is the anonymous user
3614
 *
3615
 * @return bool true if this user is anonymous, false otherwise
3616
 */
3617
function api_is_anonymous($user_id = null, $db_check = false)
3618
{
3619
    if ($db_check) {
3620
        if (!isset($user_id)) {
3621
            $user_id = api_get_user_id();
3622
        }
3623
3624
        $info = api_get_user_info($user_id);
3625
3626
        if ($info['status'] == 6 || $user_id == 0 || empty($info)) {
3627
            return true;
3628
        }
3629
    }
3630
3631
    return !Container::getAuthorizationChecker()->isGranted('IS_AUTHENTICATED_FULLY');
3632
}
3633
3634
/**
3635
 * Displays message "You are not allowed here..." and exits the entire script.
3636
 *
3637
 * @param bool   $print_headers Whether or not to print headers (default = false -> does not print them)
3638
 * @param string $message
3639
 * @param int    $responseCode
3640
 */
3641
function api_not_allowed(
3642
    $print_headers = false,
0 ignored issues
show
Unused Code introduced by
The parameter $print_headers is not used and could be removed. ( Ignorable by Annotation )

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

3642
    /** @scrutinizer ignore-unused */ $print_headers = false,

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
3643
    $message = null,
3644
    $responseCode = 0
3645
) {
3646
    $debug = api_get_setting('server_type') === 'test';
3647
3648
    // Default code is 403 forbidden
3649
    $responseCode = empty($responseCode) ? 403 : $responseCode;
3650
    $message = empty($message) ? get_lang('Not authorized') : $message;
3651
3652
    // Create new exception rendered by template:
3653
    // src/ThemeBundle/Resources/views/Exception/error.html.twig
3654
3655
    // if error is 404 then the template is:
3656
    // src/ThemeBundle/Resources/views/Exception/error404.html.twig
3657
    $exception = new Exception($message);
3658
    $request = Container::getRequest();
3659
    $exception = FlattenException::create($exception, $responseCode);
3660
    $controller = new ExceptionController(Container::getTwig(), $debug);
3661
    $response = $controller->showAction($request, $exception);
3662
    $response->send();
3663
    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...
3664
}
3665
3666
/**
3667
 * Gets a UNIX timestamp from a database (MySQL) datetime format string.
3668
 *
3669
 * @param $last_post_datetime standard output date in a sql query
3670
 *
3671
 * @return int timestamp
3672
 *
3673
 * @author Toon Van Hoecke <[email protected]>
3674
 *
3675
 * @version October 2003
3676
 * @desc convert sql date to unix timestamp
3677
 */
3678
function convert_sql_date($last_post_datetime)
3679
{
3680
    list($last_post_date, $last_post_time) = explode(' ', $last_post_datetime);
3681
    list($year, $month, $day) = explode('-', $last_post_date);
3682
    list($hour, $min, $sec) = explode(':', $last_post_time);
3683
3684
    return mktime((int) $hour, (int) $min, (int) $sec, (int) $month, (int) $day, (int) $year);
3685
}
3686
3687
/**
3688
 * Gets item visibility from the item_property table.
3689
 *
3690
 * Getting the visibility is done by getting the last updated visibility entry,
3691
 * using the largest session ID found if session 0 and another was found (meaning
3692
 * the only one that is actually from the session, in case there are results from
3693
 * session 0 *AND* session n).
3694
 *
3695
 * @param array  $_course  Course properties array (result of api_get_course_info())
3696
 * @param string $tool     Tool (learnpath, document, etc)
3697
 * @param int    $id       The item ID in the given tool
3698
 * @param int    $session  The session ID (optional)
3699
 * @param int    $user_id
3700
 * @param string $type
3701
 * @param string $group_id
3702
 *
3703
 * @return int -1 on error, 0 if invisible, 1 if visible
3704
 */
3705
function api_get_item_visibility(
3706
    $_course,
3707
    $tool,
3708
    $id,
3709
    $session = 0,
3710
    $user_id = null,
3711
    $type = null,
3712
    $group_id = null
3713
) {
3714
    if (!is_array($_course) || count($_course) == 0 || empty($tool) || empty($id)) {
3715
        return -1;
3716
    }
3717
3718
    // 0 visible
3719
    // 1 visible
3720
    // 2 deleted
3721
3722
    switch ($tool) {
3723
        case 'learnpath':
3724
3725
            break;
3726
    }
3727
3728
    $tool = Database::escape_string($tool);
3729
    $id = (int) $id;
3730
    $session = (int) $session;
3731
    $TABLE_ITEMPROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY);
3732
    $course_id = (int) $_course['real_id'];
3733
3734
    $userCondition = '';
3735
    if (!empty($user_id)) {
3736
        $user_id = (int) $user_id;
3737
        $userCondition = " AND to_user_id = $user_id ";
3738
    }
3739
3740
    $typeCondition = '';
3741
    if (!empty($type)) {
3742
        $type = Database::escape_string($type);
3743
        $typeCondition = " AND lastedit_type = '$type' ";
3744
    }
3745
3746
    $groupCondition = '';
3747
    if (!empty($group_id)) {
3748
        $group_id = (int) $group_id;
3749
        $groupCondition = " AND to_group_id = '$group_id' ";
3750
    }
3751
3752
    $sql = "SELECT visibility
3753
            FROM $TABLE_ITEMPROPERTY
3754
            WHERE
3755
                c_id = $course_id AND
3756
                tool = '$tool' AND
3757
                ref = $id AND
3758
                (session_id = $session OR session_id = 0 OR session_id IS NULL)
3759
                $userCondition $typeCondition $groupCondition
3760
            ORDER BY session_id DESC, lastedit_date DESC
3761
            LIMIT 1";
3762
3763
    $res = Database::query($sql);
3764
    if ($res === false || Database::num_rows($res) == 0) {
3765
        return -1;
3766
    }
3767
    $row = Database::fetch_array($res);
3768
3769
    return (int) $row['visibility'];
3770
}
3771
3772
/**
3773
 * Delete a row in the c_item_property table.
3774
 *
3775
 * @param array  $courseInfo
3776
 * @param string $tool
3777
 * @param int    $itemId
3778
 * @param int    $userId
3779
 * @param int    $groupId    group.iid
3780
 * @param int    $sessionId
3781
 *
3782
 * @return false|null
3783
 */
3784
function api_item_property_delete(
3785
    $courseInfo,
3786
    $tool,
3787
    $itemId,
3788
    $userId,
3789
    $groupId = 0,
3790
    $sessionId = 0
3791
) {
3792
    if (empty($courseInfo)) {
3793
        return false;
3794
    }
3795
3796
    $courseId = (int) $courseInfo['real_id'];
3797
3798
    if (empty($courseId) || empty($tool) || empty($itemId)) {
3799
        return false;
3800
    }
3801
3802
    $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
3803
    $tool = Database::escape_string($tool);
3804
    $itemId = intval($itemId);
3805
    $userId = intval($userId);
3806
    $groupId = intval($groupId);
3807
    $sessionId = intval($sessionId);
3808
3809
    $groupCondition = " AND to_group_id = $groupId ";
3810
    if (empty($groupId)) {
3811
        $groupCondition = " AND (to_group_id is NULL OR to_group_id = 0) ";
3812
    }
3813
3814
    $userCondition = " AND to_user_id = $userId ";
3815
    if (empty($userId)) {
3816
        $userCondition = " AND (to_user_id is NULL OR to_user_id = 0) ";
3817
    }
3818
    $sessionCondition = api_get_session_condition($sessionId, true, false, 'session_id');
3819
    $sql = "DELETE FROM $table
3820
            WHERE
3821
                c_id = $courseId AND
3822
                tool  = '$tool' AND
3823
                ref = $itemId
3824
                $sessionCondition
3825
                $userCondition
3826
                $groupCondition
3827
            ";
3828
3829
    Database::query($sql);
3830
}
3831
3832
/**
3833
 * Updates or adds item properties to the Item_propetry table
3834
 * Tool and lastedit_type are language independant strings (langvars->get_lang!).
3835
 *
3836
 * @param array  $_course        array with course properties
3837
 * @param string $tool           tool id, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
3838
 * @param int    $item_id        id of the item itself, linked to key of every tool ('id', ...)
3839
 * @param string $last_edit_type add or update action
3840
 *                               (1) message to be translated (in trad4all) : e.g. DocumentAdded, DocumentUpdated;
3841
 *                               (2) "delete"
3842
 *                               (3) "visible"
3843
 *                               (4) "invisible"
3844
 * @param int    $user_id        id of the editing/adding user
3845
 * @param array  $groupInfo      must include group.iid/group.od
3846
 * @param int    $to_user_id     id of the intended user (always has priority over $to_group_id !), only relevant for $type (1)
3847
 * @param string $start_visible  0000-00-00 00:00:00 format
3848
 * @param string $end_visible    0000-00-00 00:00:00 format
3849
 * @param int    $session_id     The session ID, if any, otherwise will default to 0
3850
 *
3851
 * @return bool false if update fails
3852
 *
3853
 * @author Toon Van Hoecke <[email protected]>, Ghent University
3854
 *
3855
 * @version January 2005
3856
 * @desc update the item_properties table (if entry not exists, insert) of the course
3857
 */
3858
function api_item_property_update(
3859
    $_course,
3860
    $tool,
3861
    $item_id,
3862
    $last_edit_type,
3863
    $user_id,
3864
    $groupInfo = [],
3865
    $to_user_id = null,
3866
    $start_visible = '',
3867
    $end_visible = '',
3868
    $session_id = 0
3869
) {
3870
    if (empty($_course)) {
3871
        return false;
3872
    }
3873
3874
    $course_id = $_course['real_id'];
3875
3876
    if (empty($course_id)) {
3877
        return false;
3878
    }
3879
3880
    $to_group_id = 0;
3881
    if (!empty($groupInfo) && isset($groupInfo['iid'])) {
3882
        $to_group_id = (int) $groupInfo['iid'];
3883
    }
3884
3885
    $em = Database::getManager();
3886
3887
    // Definition of variables.
3888
    $tool = Database::escape_string($tool);
3889
    $item_id = (int) $item_id;
3890
    $lastEditTypeNoFilter = $last_edit_type;
3891
    $last_edit_type = Database::escape_string($last_edit_type);
3892
    $user_id = (int) $user_id;
3893
3894
    $startVisible = "NULL";
3895
    if (!empty($start_visible)) {
3896
        $start_visible = Database::escape_string($start_visible);
3897
        $startVisible = "'$start_visible'";
3898
    }
3899
3900
    $endVisible = "NULL";
3901
    if (!empty($end_visible)) {
3902
        $end_visible = Database::escape_string($end_visible);
3903
        $endVisible = "'$end_visible'";
3904
    }
3905
3906
    $to_filter = '';
3907
    $time = api_get_utc_datetime();
3908
3909
    if (!empty($session_id)) {
3910
        $session_id = (int) $session_id;
3911
    } else {
3912
        $session_id = api_get_session_id();
3913
    }
3914
3915
    // Definition of tables.
3916
    $tableItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
3917
3918
    if ($to_user_id <= 0) {
3919
        $to_user_id = null; // No to_user_id set
3920
    }
3921
3922
    if (!is_null($to_user_id)) {
3923
        // $to_user_id has more priority than $to_group_id
3924
        $to_user_id = (int) $to_user_id;
3925
        $to_field = 'to_user_id';
3926
        $to_value = $to_user_id;
3927
    } else {
3928
        // $to_user_id is not set.
3929
        $to_field = 'to_group_id';
3930
        $to_value = $to_group_id;
3931
    }
3932
3933
    $toValueCondition = empty($to_value) ? 'NULL' : "'$to_value'";
3934
    // Set filters for $to_user_id and $to_group_id, with priority for $to_user_id
3935
    $condition_session = " AND session_id = $session_id ";
3936
    if (empty($session_id)) {
3937
        $condition_session = ' AND (session_id = 0 OR session_id IS NULL) ';
3938
    }
3939
3940
    $filter = " c_id = $course_id AND tool = '$tool' AND ref = $item_id $condition_session ";
3941
3942
    // Check whether $to_user_id and $to_group_id are passed in the function call.
3943
    // If both are not passed (both are null) then it is a message for everybody and $to_group_id should be 0 !
3944
    if (is_null($to_user_id) && is_null($to_group_id)) {
3945
        $to_group_id = 0;
3946
    }
3947
3948
    if (!is_null($to_user_id)) {
3949
        // Set filter to intended user.
3950
        $to_filter = " AND to_user_id = $to_user_id $condition_session";
3951
    } else {
3952
        // Set filter to intended group.
3953
        if (($to_group_id != 0) && $to_group_id == strval(intval($to_group_id))) {
3954
            $to_filter = " AND to_group_id = $to_group_id $condition_session";
3955
        }
3956
    }
3957
3958
    // Adding filter if set.
3959
    $filter .= $to_filter;
3960
3961
    // Update if possible
3962
    $set_type = '';
3963
3964
    switch ($lastEditTypeNoFilter) {
3965
        case 'delete':
3966
            // delete = make item only visible for the platform admin.
3967
            $visibility = '2';
3968
            if (!empty($session_id)) {
3969
                // Check whether session id already exist into item_properties for updating visibility or add it.
3970
                $sql = "SELECT session_id FROM $tableItemProperty
3971
                        WHERE
3972
                            c_id = $course_id AND
3973
                            tool = '$tool' AND
3974
                            ref = $item_id AND
3975
                            session_id = $session_id";
3976
                $rs = Database::query($sql);
3977
                if (Database::num_rows($rs) > 0) {
3978
                    $sql = "UPDATE $tableItemProperty
3979
                            SET lastedit_type       = '".str_replace('_', '', ucwords($tool))."Deleted',
3980
                                lastedit_date       = '$time',
3981
                                lastedit_user_id    = $user_id,
3982
                                visibility          = $visibility,
3983
                                session_id          = $session_id $set_type
3984
                            WHERE $filter";
3985
                    $result = Database::query($sql);
3986
                } else {
3987
                    $sql = "INSERT INTO $tableItemProperty (c_id, tool, ref, insert_date, insert_user_id, lastedit_date, lastedit_type, lastedit_user_id, $to_field, visibility, start_visible, end_visible, session_id)
3988
                            VALUES ($course_id, '$tool',$item_id, '$time', $user_id, '$time', '$last_edit_type',$user_id, $toValueCondition, $visibility, $startVisible, $endVisible, $session_id)";
3989
                    $result = Database::query($sql);
3990
                    $id = Database::insert_id();
3991
                    if ($id) {
3992
                        $sql = "UPDATE $tableItemProperty SET id = iid WHERE iid = $id";
3993
                        Database::query($sql);
3994
                    }
3995
                }
3996
            } else {
3997
                $sql = "UPDATE $tableItemProperty
3998
                        SET
3999
                            lastedit_type='".str_replace('_', '', ucwords($tool))."Deleted',
4000
                            lastedit_date='$time',
4001
                            lastedit_user_id = $user_id,
4002
                            visibility = $visibility $set_type
4003
                        WHERE $filter";
4004
                $result = Database::query($sql);
4005
            }
4006
            break;
4007
        case 'visible': // Change item to visible.
4008
            $visibility = '1';
4009
            if (!empty($session_id)) {
4010
                // Check whether session id already exist into item_properties for updating visibility or add it.
4011
                $sql = "SELECT session_id FROM $tableItemProperty
4012
                        WHERE
4013
                            c_id = $course_id AND
4014
                            tool = '$tool' AND
4015
                            ref = $item_id AND
4016
                            session_id = $session_id";
4017
                $rs = Database::query($sql);
4018
                if (Database::num_rows($rs) > 0) {
4019
                    $sql = "UPDATE $tableItemProperty
4020
                            SET
4021
                                lastedit_type='".str_replace('_', '', ucwords($tool))."Visible',
4022
                                lastedit_date='$time',
4023
                                lastedit_user_id = $user_id,
4024
                                visibility = $visibility,
4025
                                session_id = $session_id $set_type
4026
                            WHERE $filter";
4027
                    $result = Database::query($sql);
4028
                } else {
4029
                    $sql = "INSERT INTO $tableItemProperty (c_id, tool, ref, insert_date, insert_user_id, lastedit_date, lastedit_type, lastedit_user_id, $to_field, visibility, start_visible, end_visible, session_id)
4030
                            VALUES ($course_id, '$tool', $item_id, '$time', $user_id, '$time', '$last_edit_type', $user_id, $toValueCondition, $visibility, $startVisible, $endVisible, $session_id)";
4031
                    $result = Database::query($sql);
4032
                    $id = Database::insert_id();
4033
                    if ($id) {
4034
                        $sql = "UPDATE $tableItemProperty SET id = iid WHERE iid = $id";
4035
                        Database::query($sql);
4036
                    }
4037
                }
4038
            } else {
4039
                $sql = "UPDATE $tableItemProperty
4040
                        SET
4041
                            lastedit_type='".str_replace('_', '', ucwords($tool))."Visible',
4042
                            lastedit_date='$time',
4043
                            lastedit_user_id = $user_id,
4044
                            visibility = $visibility $set_type
4045
                        WHERE $filter";
4046
                $result = Database::query($sql);
4047
            }
4048
            break;
4049
        case 'invisible': // Change item to invisible.
4050
            $visibility = '0';
4051
            if (!empty($session_id)) {
4052
                // Check whether session id already exist into item_properties for updating visibility or add it
4053
                $sql = "SELECT session_id FROM $tableItemProperty
4054
                        WHERE
4055
                            c_id = $course_id AND
4056
                            tool = '$tool' AND
4057
                            ref = $item_id AND
4058
                            session_id = $session_id";
4059
                $rs = Database::query($sql);
4060
                if (Database::num_rows($rs) > 0) {
4061
                    $sql = "UPDATE $tableItemProperty
4062
                            SET
4063
                                lastedit_type = '".str_replace('_', '', ucwords($tool))."Invisible',
4064
                                lastedit_date = '$time',
4065
                                lastedit_user_id = $user_id,
4066
                                visibility = $visibility,
4067
                                session_id = $session_id $set_type
4068
                            WHERE $filter";
4069
                    $result = Database::query($sql);
4070
                } else {
4071
                    $sql = "INSERT INTO $tableItemProperty (c_id, tool, ref, insert_date, insert_user_id, lastedit_date, lastedit_type, lastedit_user_id,$to_field, visibility, start_visible, end_visible, session_id)
4072
                            VALUES ($course_id, '$tool', $item_id, '$time', $user_id, '$time', '$last_edit_type', $user_id, $toValueCondition, $visibility, $startVisible, $endVisible, $session_id)";
4073
                    $result = Database::query($sql);
4074
                    $id = Database::insert_id();
4075
                    if ($id) {
4076
                        $sql = "UPDATE $tableItemProperty SET id = iid WHERE iid = $id";
4077
                        Database::query($sql);
4078
                    }
4079
                }
4080
            } else {
4081
                $sql = "UPDATE $tableItemProperty
4082
                        SET
4083
                            lastedit_type = '".str_replace('_', '', ucwords($tool))."Invisible',
4084
                            lastedit_date = '$time',
4085
                            lastedit_user_id = $user_id,
4086
                            visibility = $visibility $set_type
4087
                        WHERE $filter";
4088
                $result = Database::query($sql);
4089
            }
4090
            break;
4091
        default: // The item will be added or updated.
4092
            $set_type = ", lastedit_type = '$last_edit_type' ";
4093
            $visibility = '1';
4094
            //$filter .= $to_filter; already added
4095
            $sql = "UPDATE $tableItemProperty
4096
                    SET
4097
                      lastedit_date = '$time',
4098
                      lastedit_user_id = $user_id $set_type
4099
                    WHERE $filter";
4100
            $result = Database::query($sql);
4101
    }
4102
4103
    // Insert if no entries are found (can only happen in case of $last_edit_type switch is 'default').
4104
    if ($result == false || Database::affected_rows($result) == 0) {
4105
        $objCourse = $em->find('ChamiloCoreBundle:Course', intval($course_id));
4106
        $objTime = new DateTime('now', new DateTimeZone('UTC'));
4107
        $objUser = api_get_user_entity($user_id);
4108
        if (empty($objUser)) {
4109
            // Use anonymous
4110
            $user_id = api_get_anonymous_id();
4111
            $objUser = api_get_user_entity($user_id);
4112
        }
4113
4114
        $objGroup = null;
4115
        if (!empty($to_group_id)) {
4116
            $objGroup = $em->find('ChamiloCourseBundle:CGroupInfo', $to_group_id);
4117
        }
4118
4119
        $objToUser = api_get_user_entity($to_user_id);
4120
        $objSession = $em->find('ChamiloCoreBundle:Session', intval($session_id));
4121
4122
        $startVisibleDate = !empty($start_visible) ? new DateTime($start_visible, new DateTimeZone('UTC')) : null;
4123
        $endVisibleDate = !empty($endVisibleDate) ? new DateTime($endVisibleDate, new DateTimeZone('UTC')) : null;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $endVisibleDate seems to never exist and therefore empty should always be true.
Loading history...
4124
4125
        $cItemProperty = new CItemProperty($objCourse);
0 ignored issues
show
Deprecated Code introduced by
The class Chamilo\CourseBundle\Entity\CItemProperty has been deprecated. ( Ignorable by Annotation )

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

4125
        $cItemProperty = /** @scrutinizer ignore-deprecated */ new CItemProperty($objCourse);
Loading history...
4126
        $cItemProperty
4127
            ->setTool($tool)
4128
            ->setRef($item_id)
4129
            ->setInsertDate($objTime)
4130
            ->setInsertUser($objUser)
4131
            ->setLasteditDate($objTime)
4132
            ->setLasteditType($last_edit_type)
4133
            ->setGroup($objGroup)
4134
            ->setToUser($objToUser)
4135
            ->setVisibility($visibility)
4136
            ->setStartVisible($startVisibleDate)
4137
            ->setEndVisible($endVisibleDate)
4138
            ->setSession($objSession);
4139
4140
        $em->persist($cItemProperty);
4141
        $em->flush();
4142
4143
        $id = $cItemProperty->getIid();
4144
4145
        if ($id) {
4146
            $cItemProperty->setId($id);
4147
            $em->merge($cItemProperty);
4148
            $em->flush();
4149
4150
            return false;
4151
        }
4152
    }
4153
4154
    return true;
4155
}
4156
4157
/**
4158
 * Gets item property by tool.
4159
 *
4160
 * @param string    course code
4161
 * @param string    tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4162
 * @param int       id of the item itself, linked to key of every tool ('id', ...), "*" = all items of the tool
4163
 * @param int    $session_id
4164
 * @param string $tool
4165
 * @param string $course_code
4166
 *
4167
 * @return array All fields from c_item_property (all rows found) or empty array
4168
 */
4169
function api_get_item_property_by_tool($tool, $course_code, $session_id = null)
4170
{
4171
    $course_info = api_get_course_info($course_code);
4172
    $tool = Database::escape_string($tool);
4173
4174
    // Definition of tables.
4175
    $item_property_table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4176
    $session_id = (int) $session_id;
4177
    $session_condition = ' AND session_id = '.$session_id;
4178
    if (empty($session_id)) {
4179
        $session_condition = " AND (session_id = 0 OR session_id IS NULL) ";
4180
    }
4181
    $course_id = $course_info['real_id'];
4182
4183
    $sql = "SELECT * FROM $item_property_table
4184
            WHERE
4185
                c_id = $course_id AND
4186
                tool = '$tool'
4187
                $session_condition ";
4188
    $rs = Database::query($sql);
4189
    $list = [];
4190
    if (Database::num_rows($rs) > 0) {
4191
        while ($row = Database::fetch_array($rs, 'ASSOC')) {
4192
            $list[] = $row;
4193
        }
4194
    }
4195
4196
    return $list;
4197
}
4198
4199
/**
4200
 * Gets item property by tool and user.
4201
 *
4202
 * @param int $userId
4203
 * @param int $tool
4204
 * @param int $courseId
4205
 * @param int $session_id
4206
 *
4207
 * @return array
4208
 */
4209
function api_get_item_property_list_by_tool_by_user(
4210
    $userId,
4211
    $tool,
4212
    $courseId,
4213
    $session_id = 0
4214
) {
4215
    $userId = intval($userId);
4216
    $tool = Database::escape_string($tool);
4217
    $session_id = intval($session_id);
4218
    $courseId = intval($courseId);
4219
4220
    // Definition of tables.
4221
    $item_property_table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4222
    $session_condition = ' AND session_id = '.$session_id;
4223
    if (empty($session_id)) {
4224
        $session_condition = " AND (session_id = 0 OR session_id IS NULL) ";
4225
    }
4226
    $sql = "SELECT * FROM $item_property_table
4227
            WHERE
4228
                insert_user_id = $userId AND
4229
                c_id = $courseId AND
4230
                tool = '$tool'
4231
                $session_condition ";
4232
4233
    $rs = Database::query($sql);
4234
    $list = [];
4235
    if (Database::num_rows($rs) > 0) {
4236
        while ($row = Database::fetch_array($rs, 'ASSOC')) {
4237
            $list[] = $row;
4238
        }
4239
    }
4240
4241
    return $list;
4242
}
4243
4244
/**
4245
 * Gets item property id from tool of a course.
4246
 *
4247
 * @param string $course_code course code
4248
 * @param string $tool        tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4249
 * @param int    $ref         id of the item itself, linked to key of every tool ('id', ...), "*" = all items of the tool
4250
 * @param int    $sessionId   Session ID (optional)
4251
 *
4252
 * @return int
4253
 */
4254
function api_get_item_property_id($course_code, $tool, $ref, $sessionId = 0)
4255
{
4256
    $course_info = api_get_course_info($course_code);
4257
    $tool = Database::escape_string($tool);
4258
    $ref = (int) $ref;
4259
4260
    // Definition of tables.
4261
    $tableItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
4262
    $course_id = $course_info['real_id'];
4263
    $sessionId = (int) $sessionId;
4264
    $sessionCondition = " AND session_id = $sessionId ";
4265
    if (empty($sessionId)) {
4266
        $sessionCondition = ' AND (session_id = 0 OR session_id IS NULL) ';
4267
    }
4268
    $sql = "SELECT id FROM $tableItemProperty
4269
            WHERE
4270
                c_id = $course_id AND
4271
                tool = '$tool' AND
4272
                ref = $ref
4273
                $sessionCondition";
4274
    $rs = Database::query($sql);
4275
    $item_property_id = '';
4276
    if (Database::num_rows($rs) > 0) {
4277
        $row = Database::fetch_array($rs);
4278
        $item_property_id = $row['id'];
4279
    }
4280
4281
    return $item_property_id;
4282
}
4283
4284
/**
4285
 * Inserts a record in the track_e_item_property table (No update).
4286
 *
4287
 * @param string $tool
4288
 * @param int    $ref
4289
 * @param string $title
4290
 * @param string $content
4291
 * @param int    $progress
4292
 *
4293
 * @return bool|int
4294
 */
4295
function api_track_item_property_update($tool, $ref, $title, $content, $progress)
4296
{
4297
    $tbl_stats_item_property = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ITEM_PROPERTY);
4298
    $course_id = api_get_course_int_id(); //numeric
4299
    $course_code = api_get_course_id(); //alphanumeric
4300
    $item_property_id = api_get_item_property_id($course_code, $tool, $ref);
4301
    if (!empty($item_property_id)) {
4302
        $sql = "INSERT IGNORE INTO $tbl_stats_item_property SET
4303
                course_id           = '$course_id',
4304
                item_property_id    = '$item_property_id',
4305
                title               = '".Database::escape_string($title)."',
4306
                content             = '".Database::escape_string($content)."',
4307
                progress            = '".intval($progress)."',
4308
                lastedit_date       = '".api_get_utc_datetime()."',
4309
                lastedit_user_id    = '".api_get_user_id()."',
4310
                session_id          = '".api_get_session_id()."'";
4311
        $result = Database::query($sql);
4312
        $affected_rows = Database::affected_rows($result);
4313
4314
        return $affected_rows;
4315
    }
4316
4317
    return false;
4318
}
4319
4320
/**
4321
 * @param string $tool
4322
 * @param int    $ref
4323
 *
4324
 * @return array|resource
4325
 */
4326
function api_get_track_item_property_history($tool, $ref)
4327
{
4328
    $tbl_stats_item_property = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ITEM_PROPERTY);
4329
    $course_id = api_get_course_int_id(); //numeric
4330
    $course_code = api_get_course_id(); //alphanumeric
4331
    $item_property_id = api_get_item_property_id($course_code, $tool, $ref);
4332
    $sql = "SELECT * FROM $tbl_stats_item_property
4333
            WHERE item_property_id = $item_property_id AND course_id = $course_id
4334
            ORDER BY lastedit_date DESC";
4335
    $result = Database::query($sql);
4336
    if ($result === false or $result === null) {
4337
        $result = [];
4338
    } else {
4339
        $result = Database::store_result($result, 'ASSOC');
4340
    }
4341
4342
    return $result;
4343
}
4344
4345
/**
4346
 * Gets item property data from tool of a course id.
4347
 *
4348
 * @param int    $course_id
4349
 * @param string $tool       tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4350
 * @param int    $ref        id of the item itself, linked to key of every tool ('id', ...), "*" = all items of the tool
4351
 * @param int    $session_id
4352
 * @param int    $groupId
4353
 *
4354
 * @return array with all fields from c_item_property, empty array if not found or false if course could not be found
4355
 */
4356
function api_get_item_property_info($course_id, $tool, $ref, $session_id = 0, $groupId = 0)
4357
{
4358
    $courseInfo = api_get_course_info_by_id($course_id);
4359
4360
    if (empty($courseInfo)) {
4361
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type array.
Loading history...
4362
    }
4363
4364
    $tool = Database::escape_string($tool);
4365
    $course_id = $courseInfo['real_id'];
4366
    $ref = (int) $ref;
4367
    $session_id = (int) $session_id;
4368
4369
    $sessionCondition = " session_id = $session_id";
4370
    if (empty($session_id)) {
4371
        $sessionCondition = ' (session_id = 0 OR session_id IS NULL) ';
4372
    }
4373
4374
    // Definition of tables.
4375
    $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4376
4377
    $sql = "SELECT * FROM $table
4378
            WHERE
4379
                c_id = $course_id AND
4380
                tool = '$tool' AND
4381
                ref = $ref AND
4382
                $sessionCondition ";
4383
4384
    if (!empty($groupId)) {
4385
        $groupId = (int) $groupId;
4386
        $sql .= " AND to_group_id = $groupId ";
4387
    }
4388
4389
    $rs = Database::query($sql);
4390
    $row = [];
4391
    if (Database::num_rows($rs) > 0) {
4392
        $row = Database::fetch_array($rs, 'ASSOC');
4393
    }
4394
4395
    return $row;
4396
}
4397
4398
/**
4399
 * Displays a combo box so the user can select his/her preferred language.
4400
 *
4401
 * @param string The desired name= value for the select
4402
 * @param bool Whether we use the JQuery Chozen library or not
4403
 * (in some cases, like the indexing language picker, it can alter the presentation)
4404
 *
4405
 * @deprecated
4406
 *
4407
 * @return string
4408
 */
4409
function api_get_languages_combo($name = 'language')
4410
{
4411
    $ret = '';
4412
    $platformLanguage = api_get_setting('platformLanguage');
4413
4414
    // Retrieve a complete list of all the languages.
4415
    $language_list = api_get_languages();
4416
4417
    if (count($language_list) < 2) {
4418
        return $ret;
4419
    }
4420
4421
    // The the current language of the user so that his/her language occurs as selected in the dropdown menu.
4422
    if (isset($_SESSION['user_language_choice'])) {
4423
        $default = $_SESSION['user_language_choice'];
4424
    } else {
4425
        $default = $platformLanguage;
4426
    }
4427
4428
    $ret .= '<select name="'.$name.'" id="language_chosen" class="selectpicker show-tick form-control">';
4429
    foreach ($language_list as $key => $value) {
4430
        if ($key == $default) {
4431
            $selected = ' selected="selected"';
4432
        } else {
4433
            $selected = '';
4434
        }
4435
        $ret .= sprintf('<option value=%s" %s>%s</option>', $key, $selected, $value);
4436
    }
4437
    $ret .= '</select>';
4438
4439
    return $ret;
4440
}
4441
4442
/**
4443
 * Displays a form (drop down menu) so the user can select his/her preferred language.
4444
 * The form works with or without javascript.
4445
 *
4446
 * @param  bool Hide form if only one language available (defaults to false = show the box anyway)
4447
 * @param bool $showAsButton
4448
 *
4449
 * @return string|null Display the box directly
4450
 */
4451
function api_display_language_form($hide_if_no_choice = false, $showAsButton = false)
4452
{
4453
    // Retrieve a complete list of all the languages.
4454
    $language_list = api_get_languages();
4455
    if (count($language_list['name']) <= 1 && $hide_if_no_choice) {
4456
        return; //don't show any form
4457
    }
4458
4459
    // The the current language of the user so that his/her language occurs as selected in the dropdown menu.
4460
    if (isset($_SESSION['user_language_choice'])) {
4461
        $user_selected_language = $_SESSION['user_language_choice'];
4462
    }
4463
    if (empty($user_selected_language)) {
4464
        $user_selected_language = api_get_setting('platformLanguage');
4465
    }
4466
4467
    $currentLanguageId = api_get_language_id($user_selected_language);
4468
    $currentLanguageInfo = api_get_language_info($currentLanguageId);
4469
    $countryCode = languageToCountryIsoCode($currentLanguageInfo['isocode']);
4470
    $url = api_get_self();
4471
    if ($showAsButton) {
4472
        $html = '<div class="btn-group">
4473
              <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
4474
                <span class="flag-icon flag-icon-'.$countryCode.'"></span>
4475
                '.$currentLanguageInfo['original_name'].'
4476
                <span class="caret">
4477
                </span>
4478
              </button>';
4479
    } else {
4480
        $html = '
4481
            <a href="'.$url.'" class="dropdown-toggle" data-toggle="dropdown" role="button">
4482
                <span class="flag-icon flag-icon-'.$countryCode.'"></span>
4483
                '.$currentLanguageInfo['original_name'].'
4484
                <span class="caret"></span>
4485
            </a>
4486
            ';
4487
    }
4488
4489
    $html .= '<ul class="dropdown-menu" role="menu">';
4490
    foreach ($language_list['all'] as $key => $data) {
4491
        $urlLink = $url.'?language='.$data['english_name'];
4492
        $html .= '<li><a href="'.$urlLink.'"><span class="flag-icon flag-icon-'.languageToCountryIsoCode($data['isocode']).'"></span> '.$data['original_name'].'</a></li>';
4493
    }
4494
    $html .= '</ul>';
4495
4496
    if ($showAsButton) {
4497
        $html .= '</div>';
4498
    }
4499
4500
    return $html;
4501
}
4502
4503
/**
4504
 * @param string $languageIsoCode
4505
 *
4506
 * @return string
4507
 */
4508
function languageToCountryIsoCode($languageIsoCode)
4509
{
4510
    $allow = api_get_configuration_value('language_flags_by_country');
4511
4512
    // @todo save in DB
4513
    switch ($languageIsoCode) {
4514
        case 'ko':
4515
            $country = 'kr';
4516
            break;
4517
        case 'ja':
4518
            $country = 'jp';
4519
            break;
4520
        case 'ca':
4521
            $country = 'es';
4522
            if ($allow) {
4523
                $country = 'catalan';
4524
            }
4525
            break;
4526
        case 'gl': // galego
4527
            $country = 'es';
4528
            if ($allow) {
4529
                $country = 'galician';
4530
            }
4531
            break;
4532
        case 'ka':
4533
            $country = 'ge';
4534
            break;
4535
        case 'sl':
4536
            $country = 'si';
4537
            break;
4538
        case 'eu': // Euskera
4539
            $country = 'es';
4540
            if ($allow) {
4541
                $country = 'basque';
4542
            }
4543
            break;
4544
        case 'cs':
4545
            $country = 'cz';
4546
            break;
4547
        case 'el':
4548
            $country = 'ae';
4549
            break;
4550
        case 'ar':
4551
            $country = 'ae';
4552
            break;
4553
        case 'en_US':
4554
        case 'en':
4555
            $country = 'gb';
4556
            break;
4557
        case 'he':
4558
            $country = 'il';
4559
            break;
4560
        case 'uk': // Ukraine
4561
            $country = 'ua';
4562
            break;
4563
        case 'da':
4564
            $country = 'dk';
4565
            break;
4566
        case 'pt-BR':
4567
            $country = 'br';
4568
            break;
4569
        case 'qu':
4570
            $country = 'pe';
4571
            break;
4572
        case 'sv':
4573
            $country = 'se';
4574
            break;
4575
        case 'zh-TW':
4576
        case 'zh':
4577
            $country = 'cn';
4578
            break;
4579
        default:
4580
            $country = $languageIsoCode;
4581
            break;
4582
    }
4583
    $country = strtolower($country);
4584
4585
    return $country;
4586
}
4587
4588
/**
4589
 * Returns a list of all the languages that are made available by the admin.
4590
 *
4591
 * @return array An array with all languages. Structure of the array is
4592
 *               array['name'] = An array with the name of every language
4593
 *               array['folder'] = An array with the corresponding names of the language-folders in the filesystem
4594
 */
4595
function api_get_languages()
4596
{
4597
    $table = Database::get_main_table(TABLE_MAIN_LANGUAGE);
4598
    $sql = "SELECT * FROM $table WHERE available='1'
4599
            ORDER BY original_name ASC";
4600
    $result = Database::query($sql);
4601
    $languages = [];
4602
    while ($row = Database::fetch_array($result, 'ASSOC')) {
4603
        $languages[$row['isocode']] = $row['original_name'];
4604
    }
4605
4606
    return $languages;
4607
}
4608
4609
/**
4610
 * Returns a list of all the languages that are made available by the admin.
4611
 *
4612
 * @return array
4613
 */
4614
function api_get_languages_to_array()
4615
{
4616
    $tbl_language = Database::get_main_table(TABLE_MAIN_LANGUAGE);
4617
    $sql = "SELECT * FROM $tbl_language WHERE available='1' ORDER BY original_name ASC";
4618
    $result = Database::query($sql);
4619
    $languages = [];
4620
    while ($row = Database::fetch_array($result)) {
4621
        $languages[$row['dokeos_folder']] = $row['original_name'];
4622
    }
4623
4624
    return $languages;
4625
}
4626
4627
/**
4628
 * Returns the id (the database id) of a language.
4629
 *
4630
 * @param   string  language name (the corresponding name of the language-folder in the filesystem)
4631
 *
4632
 * @return int id of the language
4633
 */
4634
function api_get_language_id($language)
4635
{
4636
    $tbl_language = Database::get_main_table(TABLE_MAIN_LANGUAGE);
4637
    if (empty($language)) {
4638
        return null;
4639
    }
4640
    $language = Database::escape_string($language);
4641
    $sql = "SELECT id FROM $tbl_language
4642
            WHERE dokeos_folder = '$language' LIMIT 1";
4643
    $result = Database::query($sql);
4644
    $row = Database::fetch_array($result);
4645
4646
    return $row['id'];
4647
}
4648
4649
/**
4650
 * Get the language information by its id.
4651
 *
4652
 * @param int $languageId
4653
 *
4654
 * @throws Exception
4655
 *
4656
 * @return array
4657
 */
4658
function api_get_language_info($languageId)
4659
{
4660
    if (empty($languageId)) {
4661
        return [];
4662
    }
4663
4664
    $language = Database::getManager()
4665
        ->find('ChamiloCoreBundle:Language', $languageId);
4666
4667
    if (!$language) {
4668
        return [];
4669
    }
4670
4671
    return [
4672
        'id' => $language->getId(),
4673
        'original_name' => $language->getOriginalName(),
4674
        'english_name' => $language->getEnglishName(),
4675
        'isocode' => $language->getIsocode(),
4676
        'dokeos_folder' => $language->getDokeosFolder(),
4677
        'available' => $language->getAvailable(),
4678
        'parent_id' => $language->getParent() ? $language->getParent()->getId() : null,
4679
    ];
4680
}
4681
4682
/**
4683
 * @param string $code
4684
 *
4685
 * @return \Chamilo\CoreBundle\Entity\Language
4686
 */
4687
function api_get_language_from_iso($code)
4688
{
4689
    $em = Database::getManager();
4690
    $language = $em->getRepository('ChamiloCoreBundle:Language')->findOneBy(['isocode' => $code]);
4691
4692
    return $language;
4693
}
4694
4695
/**
4696
 * Returns the name of the visual (CSS) theme to be applied on the current page.
4697
 * The returned name depends on the platform, course or user -wide settings.
4698
 *
4699
 * @return string The visual theme's name, it is the name of a folder inside web/css/themes
4700
 */
4701
function api_get_visual_theme()
4702
{
4703
    static $visual_theme;
4704
    if (!isset($visual_theme)) {
4705
        // Get style directly from DB
4706
        $styleFromDatabase = api_get_settings_params_simple(
4707
            [
4708
                'variable = ? AND access_url = ?' => [
4709
                    'stylesheets',
4710
                    api_get_current_access_url_id(),
4711
                ],
4712
            ]
4713
        );
4714
        if ($styleFromDatabase) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $styleFromDatabase 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...
4715
            $platform_theme = $styleFromDatabase['selected_value'];
4716
        } else {
4717
            $platform_theme = api_get_setting('stylesheets');
4718
        }
4719
4720
        // Platform's theme.
4721
        $visual_theme = $platform_theme;
4722
        if (api_get_setting('user_selected_theme') == 'true') {
4723
            $user_info = api_get_user_info();
4724
            if (isset($user_info['theme'])) {
4725
                $user_theme = $user_info['theme'];
4726
4727
                if (!empty($user_theme)) {
4728
                    $visual_theme = $user_theme;
4729
                    // User's theme.
4730
                }
4731
            }
4732
        }
4733
4734
        $course_id = api_get_course_id();
4735
        if (!empty($course_id)) {
4736
            if (api_get_setting('allow_course_theme') == 'true') {
4737
                $course_theme = api_get_course_setting('course_theme', $course_id);
4738
4739
                if (!empty($course_theme) && $course_theme != -1) {
4740
                    if (!empty($course_theme)) {
4741
                        // Course's theme.
4742
                        $visual_theme = $course_theme;
4743
                    }
4744
                }
4745
4746
                $allow_lp_theme = api_get_course_setting('allow_learning_path_theme');
4747
                if ($allow_lp_theme == 1) {
4748
                    global $lp_theme_css, $lp_theme_config;
4749
                    // These variables come from the file lp_controller.php.
4750
                    if (!$lp_theme_config) {
4751
                        if (!empty($lp_theme_css)) {
4752
                            // LP's theme.
4753
                            $visual_theme = $lp_theme_css;
4754
                        }
4755
                    }
4756
                }
4757
            }
4758
        }
4759
4760
        if (empty($visual_theme)) {
4761
            $visual_theme = 'chamilo';
4762
        }
4763
4764
        global $lp_theme_log;
4765
        if ($lp_theme_log) {
4766
            $visual_theme = $platform_theme;
4767
        }
4768
    }
4769
4770
    return $visual_theme;
4771
}
4772
4773
/**
4774
 * Returns a list of CSS themes currently available in the CSS folder
4775
 * The folder must have a default.css file.
4776
 *
4777
 * @param bool $getOnlyThemeFromVirtualInstance Used by the vchamilo plugin
4778
 *
4779
 * @return array list of themes directories from the css folder
4780
 *               Note: Directory names (names of themes) in the file system should contain ASCII-characters only
4781
 */
4782
function api_get_themes($getOnlyThemeFromVirtualInstance = false)
4783
{
4784
    // This configuration value is set by the vchamilo plugin
4785
    $virtualTheme = api_get_configuration_value('virtual_css_theme_folder');
4786
4787
    $readCssFolder = function ($dir) use ($virtualTheme) {
4788
        $finder = new Finder();
4789
        $themes = $finder->directories()->in($dir)->depth(0)->sortByName();
4790
        $list = [];
4791
        /** @var Symfony\Component\Finder\SplFileInfo $theme */
4792
        foreach ($themes as $theme) {
4793
            $folder = $theme->getFilename();
4794
            // A theme folder is consider if there's a default.css file
4795
            if (!file_exists($theme->getPathname().'/default.css')) {
4796
                continue;
4797
            }
4798
            $name = ucwords(str_replace('_', ' ', $folder));
4799
            if ($folder == $virtualTheme) {
4800
                continue;
4801
            }
4802
            $list[$folder] = $name;
4803
        }
4804
4805
        return $list;
4806
    };
4807
4808
    $dir = api_get_path(SYS_CSS_PATH).'themes/';
4809
    $list = $readCssFolder($dir);
4810
4811
    if (!empty($virtualTheme)) {
4812
        $newList = $readCssFolder($dir.'/'.$virtualTheme);
4813
        if ($getOnlyThemeFromVirtualInstance) {
4814
            return $newList;
4815
        }
4816
        $list = $list + $newList;
4817
        asort($list);
4818
    }
4819
4820
    return $list;
4821
}
4822
4823
/**
4824
 * Find the largest sort value in a given user_course_category
4825
 * This function is used when we are moving a course to a different category
4826
 * and also when a user subscribes to courses (the new course is added at the end of the main category.
4827
 *
4828
 * @author Patrick Cool <[email protected]>, Ghent University
4829
 *
4830
 * @param int $user_course_category the id of the user_course_category
4831
 * @param int $user_id
4832
 *
4833
 * @return int the value of the highest sort of the user_course_category
4834
 */
4835
function api_max_sort_value($user_course_category, $user_id)
4836
{
4837
    $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4838
    $sql = "SELECT max(sort) as max_sort FROM $tbl_course_user
4839
            WHERE
4840
                user_id='".intval($user_id)."' AND
4841
                relation_type<>".COURSE_RELATION_TYPE_RRHH." AND
4842
                user_course_cat='".intval($user_course_category)."'";
4843
    $result_max = Database::query($sql);
4844
    if (Database::num_rows($result_max) == 1) {
4845
        $row_max = Database::fetch_array($result_max);
4846
4847
        return $row_max['max_sort'];
4848
    }
4849
4850
    return 0;
4851
}
4852
4853
/**
4854
 * Transforms a number of seconds in hh:mm:ss format.
4855
 *
4856
 * @author Julian Prud'homme
4857
 *
4858
 * @param int    $seconds      number of seconds
4859
 * @param string $space
4860
 * @param bool   $showSeconds
4861
 * @param bool   $roundMinutes
4862
 *
4863
 * @return string the formatted time
4864
 */
4865
function api_time_to_hms($seconds, $space = ':', $showSeconds = true, $roundMinutes = false)
4866
{
4867
    // $seconds = -1 means that we have wrong data in the db.
4868
    if ($seconds == -1) {
4869
        return
4870
            get_lang('Unknown').
4871
            Display::return_icon(
4872
                'info2.gif',
4873
                get_lang('The datas about this user were registered when the calculation of time spent on the platform wasn\'t possible.'),
4874
                ['align' => 'absmiddle', 'hspace' => '3px']
4875
            );
4876
    }
4877
4878
    // How many hours ?
4879
    $hours = floor($seconds / 3600);
4880
4881
    // How many minutes ?
4882
    $min = floor(($seconds - ($hours * 3600)) / 60);
4883
4884
    if ($roundMinutes) {
4885
        if ($min >= 45) {
4886
            $min = 45;
4887
        }
4888
4889
        if ($min >= 30 && $min <= 44) {
4890
            $min = 30;
4891
        }
4892
4893
        if ($min >= 15 && $min <= 29) {
4894
            $min = 15;
4895
        }
4896
4897
        if ($min >= 0 && $min <= 14) {
4898
            $min = 0;
4899
        }
4900
    }
4901
4902
    // How many seconds
4903
    $sec = floor($seconds - ($hours * 3600) - ($min * 60));
4904
4905
    if ($hours < 10) {
4906
        $hours = "0$hours";
4907
    }
4908
4909
    if ($sec < 10) {
4910
        $sec = "0$sec";
4911
    }
4912
4913
    if ($min < 10) {
4914
        $min = "0$min";
4915
    }
4916
4917
    $seconds = '';
4918
    if ($showSeconds) {
4919
        $seconds = $space.$sec;
4920
    }
4921
4922
    return $hours.$space.$min.$seconds;
4923
}
4924
4925
/* FILE SYSTEM RELATED FUNCTIONS */
4926
4927
/**
4928
 * Returns the permissions to be assigned to every newly created directory by the web-server.
4929
 * The return value is based on the platform administrator's setting
4930
 * "Administration > Configuration settings > Security > Permissions for new directories".
4931
 *
4932
 * @return int returns the permissions in the format "Owner-Group-Others, Read-Write-Execute", as an integer value
4933
 */
4934
function api_get_permissions_for_new_directories()
4935
{
4936
    static $permissions;
4937
    if (!isset($permissions)) {
4938
        $permissions = trim(api_get_setting('permissions_for_new_directories'));
4939
        // The default value 0777 is according to that in the platform administration panel after fresh system installation.
4940
        $permissions = octdec(!empty($permissions) ? $permissions : '0777');
4941
    }
4942
4943
    return $permissions;
4944
}
4945
4946
/**
4947
 * Returns the permissions to be assigned to every newly created directory by the web-server.
4948
 * The return value is based on the platform administrator's setting
4949
 * "Administration > Configuration settings > Security > Permissions for new files".
4950
 *
4951
 * @return int returns the permissions in the format
4952
 *             "Owner-Group-Others, Read-Write-Execute", as an integer value
4953
 */
4954
function api_get_permissions_for_new_files()
4955
{
4956
    static $permissions;
4957
    if (!isset($permissions)) {
4958
        $permissions = trim(api_get_setting('permissions_for_new_files'));
4959
        // The default value 0666 is according to that in the platform
4960
        // administration panel after fresh system installation.
4961
        $permissions = octdec(!empty($permissions) ? $permissions : '0666');
4962
    }
4963
4964
    return $permissions;
4965
}
4966
4967
/**
4968
 * Deletes a file, or a folder and its contents.
4969
 *
4970
 * @author      Aidan Lister <[email protected]>
4971
 *
4972
 * @version     1.0.3
4973
 *
4974
 * @param string $dirname Directory to delete
4975
 * @param       bool     Deletes only the content or not
4976
 * @param bool $strict if one folder/file fails stop the loop
4977
 *
4978
 * @return bool Returns TRUE on success, FALSE on failure
4979
 *
4980
 * @see http://aidanlister.com/2004/04/recursively-deleting-a-folder-in-php/
4981
 *
4982
 * @author      Yannick Warnier, adaptation for the Chamilo LMS, April, 2008
4983
 * @author      Ivan Tcholakov, a sanity check about Directory class creation has been added, September, 2009
4984
 */
4985
function rmdirr($dirname, $delete_only_content_in_folder = false, $strict = false)
4986
{
4987
    $res = true;
4988
    // A sanity check.
4989
    if (!file_exists($dirname)) {
4990
        return false;
4991
    }
4992
    $php_errormsg = '';
4993
    // Simple delete for a file.
4994
    if (is_file($dirname) || is_link($dirname)) {
4995
        $res = unlink($dirname);
4996
        if ($res === false) {
4997
            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);
4998
        }
4999
5000
        return $res;
5001
    }
5002
5003
    // Loop through the folder.
5004
    $dir = dir($dirname);
5005
    // A sanity check.
5006
    $is_object_dir = is_object($dir);
5007
    if ($is_object_dir) {
5008
        while (false !== $entry = $dir->read()) {
5009
            // Skip pointers.
5010
            if ($entry == '.' || $entry == '..') {
5011
                continue;
5012
            }
5013
5014
            // Recurse.
5015
            if ($strict) {
5016
                $result = rmdirr("$dirname/$entry");
5017
                if ($result == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

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

Loading history...
5018
                    $res = false;
5019
                    break;
5020
                }
5021
            } else {
5022
                rmdirr("$dirname/$entry");
5023
            }
5024
        }
5025
    }
5026
5027
    // Clean up.
5028
    if ($is_object_dir) {
5029
        $dir->close();
5030
    }
5031
5032
    if ($delete_only_content_in_folder == false) {
5033
        $res = rmdir($dirname);
5034
        if ($res === false) {
5035
            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);
5036
        }
5037
    }
5038
5039
    return $res;
5040
}
5041
5042
// TODO: This function is to be simplified. File access modes to be implemented.
5043
/**
5044
 * function adapted from a php.net comment
5045
 * copy recursively a folder.
5046
 *
5047
 * @param the source folder
5048
 * @param the dest folder
5049
 * @param an array of excluded file_name (without extension)
5050
 * @param copied_files the returned array of copied files
5051
 * @param string $source
5052
 * @param string $dest
5053
 */
5054
function copyr($source, $dest, $exclude = [], $copied_files = [])
5055
{
5056
    if (empty($dest)) {
5057
        return false;
5058
    }
5059
    // Simple copy for a file
5060
    if (is_file($source)) {
5061
        $path_info = pathinfo($source);
5062
        if (!in_array($path_info['filename'], $exclude)) {
5063
            copy($source, $dest);
5064
        }
5065
5066
        return true;
5067
    } elseif (!is_dir($source)) {
5068
        //then source is not a dir nor a file, return
5069
        return false;
5070
    }
5071
5072
    // Make destination directory.
5073
    if (!is_dir($dest)) {
5074
        mkdir($dest, api_get_permissions_for_new_directories());
5075
    }
5076
5077
    // Loop through the folder.
5078
    $dir = dir($source);
5079
    while (false !== $entry = $dir->read()) {
5080
        // Skip pointers
5081
        if ($entry == '.' || $entry == '..') {
5082
            continue;
5083
        }
5084
5085
        // Deep copy directories.
5086
        if ($dest !== "$source/$entry") {
5087
            $files = copyr("$source/$entry", "$dest/$entry", $exclude, $copied_files);
0 ignored issues
show
Bug introduced by
It seems like $copied_files can also be of type array; however, parameter $copied_files of copyr() does only seem to accept the, maybe add an additional type check? ( Ignorable by Annotation )

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

5087
            $files = copyr("$source/$entry", "$dest/$entry", $exclude, /** @scrutinizer ignore-type */ $copied_files);
Loading history...
5088
        }
5089
    }
5090
    // Clean up.
5091
    $dir->close();
5092
5093
    return true;
5094
}
5095
5096
/**
5097
 * @todo: Using DIRECTORY_SEPARATOR is not recommended, this is an obsolete approach.
5098
 * Documentation header to be added here.
5099
 *
5100
 * @param string $pathname
5101
 * @param string $base_path_document
5102
 * @param int    $session_id
5103
 *
5104
 * @return mixed True if directory already exists, false if a file already exists at
5105
 *               the destination and null if everything goes according to plan
5106
 */
5107
function copy_folder_course_session(
5108
    $pathname,
5109
    $base_path_document,
5110
    $session_id,
5111
    $course_info,
5112
    $document,
5113
    $source_course_id
5114
) {
5115
    $table = Database::get_course_table(TABLE_DOCUMENT);
5116
    $session_id = intval($session_id);
5117
    $source_course_id = intval($source_course_id);
5118
5119
    // Check whether directory already exists.
5120
    if (is_dir($pathname) || empty($pathname)) {
5121
        return true;
5122
    }
5123
5124
    // Ensure that a file with the same name does not already exist.
5125
    if (is_file($pathname)) {
5126
        trigger_error('copy_folder_course_session(): File exists', E_USER_WARNING);
5127
5128
        return false;
5129
    }
5130
5131
    $course_id = $course_info['real_id'];
5132
    $folders = explode(DIRECTORY_SEPARATOR, str_replace($base_path_document.DIRECTORY_SEPARATOR, '', $pathname));
5133
    $new_pathname = $base_path_document;
5134
    $path = '';
5135
5136
    foreach ($folders as $folder) {
5137
        $new_pathname .= DIRECTORY_SEPARATOR.$folder;
5138
        $path .= DIRECTORY_SEPARATOR.$folder;
5139
5140
        if (!file_exists($new_pathname)) {
5141
            $path = Database::escape_string($path);
5142
5143
            $sql = "SELECT * FROM $table
5144
                    WHERE
5145
                        c_id = $source_course_id AND
5146
                        path = '$path' AND
5147
                        filetype = 'folder' AND
5148
                        session_id = '$session_id'";
5149
            $rs1 = Database::query($sql);
5150
            $num_rows = Database::num_rows($rs1);
5151
5152
            if ($num_rows == 0) {
5153
                mkdir($new_pathname, api_get_permissions_for_new_directories());
5154
5155
                // Insert new folder with destination session_id.
5156
                $params = [
5157
                    'c_id' => $course_id,
5158
                    'path' => $path,
5159
                    'comment' => $document->comment,
5160
                    'title' => basename($new_pathname),
5161
                    'filetype' => 'folder',
5162
                    'size' => '0',
5163
                    'session_id' => $session_id,
5164
                ];
5165
                $document_id = Database::insert($table, $params);
5166
                if ($document_id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $document_id of type false|integer is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
5167
                    $sql = "UPDATE $table SET id = iid WHERE iid = $document_id";
5168
                    Database::query($sql);
5169
5170
                    api_item_property_update(
5171
                        $course_info,
5172
                        TOOL_DOCUMENT,
5173
                        $document_id,
5174
                        'FolderCreated',
5175
                        api_get_user_id(),
5176
                        0,
5177
                        0,
5178
                        null,
5179
                        null,
5180
                        $session_id
5181
                    );
5182
                }
5183
            }
5184
        }
5185
    } // en foreach
5186
}
5187
5188
// TODO: chmodr() is a better name. Some corrections are needed. Documentation header to be added here.
5189
/**
5190
 * @param string $path
5191
 */
5192
function api_chmod_R($path, $filemode)
5193
{
5194
    if (!is_dir($path)) {
5195
        return chmod($path, $filemode);
5196
    }
5197
5198
    $handler = opendir($path);
5199
    while ($file = readdir($handler)) {
0 ignored issues
show
Bug introduced by
It seems like $handler can also be of type false; however, parameter $dir_handle of readdir() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

5199
    while ($file = readdir(/** @scrutinizer ignore-type */ $handler)) {
Loading history...
5200
        if ($file != '.' && $file != '..') {
5201
            $fullpath = "$path/$file";
5202
            if (!is_dir($fullpath)) {
5203
                if (!chmod($fullpath, $filemode)) {
5204
                    return false;
5205
                }
5206
            } else {
5207
                if (!api_chmod_R($fullpath, $filemode)) {
5208
                    return false;
5209
                }
5210
            }
5211
        }
5212
    }
5213
5214
    closedir($handler);
0 ignored issues
show
Bug introduced by
It seems like $handler can also be of type false; however, parameter $dir_handle of closedir() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

5214
    closedir(/** @scrutinizer ignore-type */ $handler);
Loading history...
5215
5216
    return chmod($path, $filemode);
5217
}
5218
5219
// TODO: Where the following function has been copy/pased from? There is no information about author and license. Style, coding conventions...
5220
/**
5221
 * Parse info file format. (e.g: file.info).
5222
 *
5223
 * Files should use an ini-like format to specify values.
5224
 * White-space generally doesn't matter, except inside values.
5225
 * e.g.
5226
 *
5227
 * @verbatim
5228
 *   key = value
5229
 *   key = "value"
5230
 *   key = 'value'
5231
 *   key = "multi-line
5232
 *
5233
 *   value"
5234
 *   key = 'multi-line
5235
 *
5236
 *   value'
5237
 *   key
5238
 *   =
5239
 *   'value'
5240
 * @endverbatim
5241
 *
5242
 * Arrays are created using a GET-like syntax:
5243
 *
5244
 * @verbatim
5245
 *   key[] = "numeric array"
5246
 *   key[index] = "associative array"
5247
 *   key[index][] = "nested numeric array"
5248
 *   key[index][index] = "nested associative array"
5249
 * @endverbatim
5250
 *
5251
 * PHP constants are substituted in, but only when used as the entire value:
5252
 *
5253
 * Comments should start with a semi-colon at the beginning of a line.
5254
 *
5255
 * This function is NOT for placing arbitrary module-specific settings. Use
5256
 * variable_get() and variable_set() for that.
5257
 *
5258
 * Information stored in the module.info file:
5259
 * - name: The real name of the module for display purposes.
5260
 * - description: A brief description of the module.
5261
 * - dependencies: An array of shortnames of other modules this module depends on.
5262
 * - package: The name of the package of modules this module belongs to.
5263
 *
5264
 * Example of .info file:
5265
 * <code>
5266
 * @verbatim
5267
 *   name = Forum
5268
 *   description = Enables threaded discussions about general topics.
5269
 *   dependencies[] = taxonomy
5270
 *   dependencies[] = comment
5271
 *   package = Core - optional
5272
 *   version = VERSION
5273
 * @endverbatim
5274
 * </code>
5275
 *
5276
 * @param string $filename
5277
 *                         The file we are parsing. Accepts file with relative or absolute path.
5278
 *
5279
 * @return
5280
 *   The info array
5281
 */
5282
function api_parse_info_file($filename)
5283
{
5284
    $info = [];
5285
5286
    if (!file_exists($filename)) {
5287
        return $info;
5288
    }
5289
5290
    $data = file_get_contents($filename);
5291
    if (preg_match_all('
5292
        @^\s*                           # Start at the beginning of a line, ignoring leading whitespace
5293
        ((?:
5294
          [^=;\[\]]|                    # Key names cannot contain equal signs, semi-colons or square brackets,
5295
          \[[^\[\]]*\]                  # unless they are balanced and not nested
5296
        )+?)
5297
        \s*=\s*                         # Key/value pairs are separated by equal signs (ignoring white-space)
5298
        (?:
5299
          ("(?:[^"]|(?<=\\\\)")*")|     # Double-quoted string, which may contain slash-escaped quotes/slashes
5300
          (\'(?:[^\']|(?<=\\\\)\')*\')| # Single-quoted string, which may contain slash-escaped quotes/slashes
5301
          ([^\r\n]*?)                   # Non-quoted string
5302
        )\s*$                           # Stop at the next end of a line, ignoring trailing whitespace
5303
        @msx', $data, $matches, PREG_SET_ORDER)) {
5304
        $key = $value1 = $value2 = $value3 = '';
5305
        foreach ($matches as $match) {
5306
            // Fetch the key and value string.
5307
            $i = 0;
5308
            foreach (['key', 'value1', 'value2', 'value3'] as $var) {
5309
                $$var = isset($match[++$i]) ? $match[$i] : '';
5310
            }
5311
            $value = stripslashes(substr($value1, 1, -1)).stripslashes(substr($value2, 1, -1)).$value3;
5312
5313
            // Parse array syntax.
5314
            $keys = preg_split('/\]?\[/', rtrim($key, ']'));
5315
            $last = array_pop($keys);
0 ignored issues
show
Bug introduced by
It seems like $keys can also be of type false; however, parameter $array of array_pop() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

5315
            $last = array_pop(/** @scrutinizer ignore-type */ $keys);
Loading history...
5316
            $parent = &$info;
5317
5318
            // Create nested arrays.
5319
            foreach ($keys as $key) {
5320
                if ($key == '') {
5321
                    $key = count($parent);
5322
                }
5323
                if (!isset($parent[$key]) || !is_array($parent[$key])) {
5324
                    $parent[$key] = [];
5325
                }
5326
                $parent = &$parent[$key];
5327
            }
5328
5329
            // Handle PHP constants.
5330
            if (defined($value)) {
5331
                $value = constant($value);
5332
            }
5333
5334
            // Insert actual value.
5335
            if ($last == '') {
5336
                $last = count($parent);
5337
            }
5338
            $parent[$last] = $value;
5339
        }
5340
    }
5341
5342
    return $info;
5343
}
5344
5345
/**
5346
 * Gets Chamilo version from the configuration files.
5347
 *
5348
 * @return string A string of type "1.8.4", or an empty string if the version could not be found
5349
 */
5350
function api_get_version()
5351
{
5352
    return (string) api_get_configuration_value('system_version');
5353
}
5354
5355
/**
5356
 * Gets the software name (the name/brand of the Chamilo-based customized system).
5357
 *
5358
 * @return string
5359
 */
5360
function api_get_software_name()
5361
{
5362
    $name = api_get_configuration_value('software_name');
5363
    if (!empty($name)) {
5364
        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...
5365
    } else {
5366
        return 'Chamilo';
5367
    }
5368
}
5369
5370
function api_get_status_list()
5371
{
5372
    $list = [];
5373
    // Table of status
5374
    $list[COURSEMANAGER] = 'teacher'; // 1
5375
    $list[SESSIONADMIN] = 'session_admin'; // 3
5376
    $list[DRH] = 'drh'; // 4
5377
    $list[STUDENT] = 'user'; // 5
5378
    $list[ANONYMOUS] = 'anonymous'; // 6
5379
    $list[INVITEE] = 'invited'; // 20
5380
5381
    return $list;
5382
}
5383
5384
/**
5385
 * Checks whether status given in parameter exists in the platform.
5386
 *
5387
 * @param mixed the status (can be either int either string)
5388
 *
5389
 * @return bool if the status exists, else returns false
5390
 */
5391
function api_status_exists($status_asked)
5392
{
5393
    $list = api_get_status_list();
5394
5395
    return in_array($status_asked, $list) ? true : isset($list[$status_asked]);
5396
}
5397
5398
/**
5399
 * Checks whether status given in parameter exists in the platform. The function
5400
 * returns the status ID or false if it does not exist, but given the fact there
5401
 * is no "0" status, the return value can be checked against
5402
 * if(api_status_key()) to know if it exists.
5403
 *
5404
 * @param   mixed   The status (can be either int or string)
5405
 *
5406
 * @return mixed Status ID if exists, false otherwise
5407
 */
5408
function api_status_key($status)
5409
{
5410
    $list = api_get_status_list();
5411
5412
    return isset($list[$status]) ? $status : array_search($status, $list);
5413
}
5414
5415
/**
5416
 * Gets the status langvars list.
5417
 *
5418
 * @return string[] the list of status with their translations
5419
 */
5420
function api_get_status_langvars()
5421
{
5422
    return [
5423
        COURSEMANAGER => get_lang('Teacher'),
5424
        SESSIONADMIN => get_lang('SessionsAdmin'),
5425
        DRH => get_lang('Human Resources Manager'),
5426
        STUDENT => get_lang('Learner'),
5427
        ANONYMOUS => get_lang('Anonymous'),
5428
        STUDENT_BOSS => get_lang('RoleStudentBoss'),
5429
        INVITEE => get_lang('Invited'),
5430
    ];
5431
}
5432
5433
/**
5434
 * The function that retrieves all the possible settings for a certain config setting.
5435
 *
5436
 * @author Patrick Cool <[email protected]>, Ghent University
5437
 */
5438
function api_get_settings_options($var)
5439
{
5440
    $table_settings_options = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
5441
    $var = Database::escape_string($var);
5442
    $sql = "SELECT * FROM $table_settings_options
5443
            WHERE variable = '$var'
5444
            ORDER BY id";
5445
    $result = Database::query($sql);
5446
    $settings_options_array = [];
5447
    while ($row = Database::fetch_array($result, 'ASSOC')) {
5448
        $settings_options_array[] = $row;
5449
    }
5450
5451
    return $settings_options_array;
5452
}
5453
5454
/**
5455
 * @param array $params
5456
 */
5457
function api_set_setting_option($params)
5458
{
5459
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
5460
    if (empty($params['id'])) {
5461
        Database::insert($table, $params);
5462
    } else {
5463
        Database::update($table, $params, ['id = ? ' => $params['id']]);
5464
    }
5465
}
5466
5467
/**
5468
 * @param array $params
5469
 */
5470
function api_set_setting_simple($params)
5471
{
5472
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5473
    $url_id = api_get_current_access_url_id();
5474
5475
    if (empty($params['id'])) {
5476
        $params['access_url'] = $url_id;
5477
        Database::insert($table, $params);
5478
    } else {
5479
        Database::update($table, $params, ['id = ? ' => [$params['id']]]);
5480
    }
5481
}
5482
5483
/**
5484
 * @param int $id
5485
 */
5486
function api_delete_setting_option($id)
5487
{
5488
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
5489
    if (!empty($id)) {
5490
        Database::delete($table, ['id = ? ' => $id]);
5491
    }
5492
}
5493
5494
/**
5495
 * Sets a platform configuration setting to a given value.
5496
 *
5497
 * @param string    The variable we want to update
5498
 * @param string    The value we want to record
5499
 * @param string    The sub-variable if any (in most cases, this will remain null)
5500
 * @param string    The category if any (in most cases, this will remain null)
5501
 * @param int       The access_url for which this parameter is valid
5502
 * @param string $cat
5503
 *
5504
 * @return bool|null
5505
 */
5506
function api_set_setting($var, $value, $subvar = null, $cat = null, $access_url = 1)
5507
{
5508
    if (empty($var)) {
5509
        return false;
5510
    }
5511
    $t_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5512
    $var = Database::escape_string($var);
5513
    $value = Database::escape_string($value);
5514
    $access_url = (int) $access_url;
5515
    if (empty($access_url)) {
5516
        $access_url = 1;
5517
    }
5518
    $select = "SELECT id FROM $t_settings WHERE variable = '$var' ";
5519
    if (!empty($subvar)) {
5520
        $subvar = Database::escape_string($subvar);
5521
        $select .= " AND subkey = '$subvar'";
5522
    }
5523
    if (!empty($cat)) {
5524
        $cat = Database::escape_string($cat);
5525
        $select .= " AND category = '$cat'";
5526
    }
5527
    if ($access_url > 1) {
5528
        $select .= " AND access_url = $access_url";
5529
    } else {
5530
        $select .= " AND access_url = 1 ";
5531
    }
5532
5533
    $res = Database::query($select);
5534
    if (Database::num_rows($res) > 0) {
5535
        // Found item for this access_url.
5536
        $row = Database::fetch_array($res);
5537
        $sql = "UPDATE $t_settings SET selected_value = '$value'
5538
                WHERE id = ".$row['id'];
5539
        Database::query($sql);
5540
    } else {
5541
        // Item not found for this access_url, we have to check if it exist with access_url = 1
5542
        $select = "SELECT * FROM $t_settings
5543
                   WHERE variable = '$var' AND access_url = 1 ";
5544
        // Just in case
5545
        if ($access_url == 1) {
5546
            if (!empty($subvar)) {
5547
                $select .= " AND subkey = '$subvar'";
5548
            }
5549
            if (!empty($cat)) {
5550
                $select .= " AND category = '$cat'";
5551
            }
5552
            $res = Database::query($select);
5553
            if (Database::num_rows($res) > 0) {
5554
                // We have a setting for access_url 1, but none for the current one, so create one.
5555
                $row = Database::fetch_array($res);
5556
                $insert = "INSERT INTO $t_settings (variable, subkey, type,category, selected_value, title, comment, scope, subkeytext, access_url)
5557
                        VALUES
5558
                        ('".$row['variable']."',".(!empty($row['subkey']) ? "'".$row['subkey']."'" : "NULL").",".
5559
                    "'".$row['type']."','".$row['category']."',".
5560
                    "'$value','".$row['title']."',".
5561
                    "".(!empty($row['comment']) ? "'".$row['comment']."'" : "NULL").",".(!empty($row['scope']) ? "'".$row['scope']."'" : "NULL").",".
5562
                    "".(!empty($row['subkeytext']) ? "'".$row['subkeytext']."'" : "NULL").",$access_url)";
5563
                Database::query($insert);
5564
            } else {
5565
                // Such a setting does not exist.
5566
                //error_log(__FILE__.':'.__LINE__.': Attempting to update setting '.$var.' ('.$subvar.') which does not exist at all', 0);
5567
            }
5568
        } else {
5569
            // Other access url.
5570
            if (!empty($subvar)) {
5571
                $select .= " AND subkey = '$subvar'";
5572
            }
5573
            if (!empty($cat)) {
5574
                $select .= " AND category = '$cat'";
5575
            }
5576
            $res = Database::query($select);
5577
5578
            if (Database::num_rows($res) > 0) {
5579
                // We have a setting for access_url 1, but none for the current one, so create one.
5580
                $row = Database::fetch_array($res);
5581
                if ($row['access_url_changeable'] == 1) {
5582
                    $insert = "INSERT INTO $t_settings (variable,subkey, type,category, selected_value,title, comment,scope, subkeytext,access_url, access_url_changeable) VALUES
5583
                            ('".$row['variable']."',".
5584
                        (!empty($row['subkey']) ? "'".$row['subkey']."'" : "NULL").",".
5585
                        "'".$row['type']."','".$row['category']."',".
5586
                        "'$value','".$row['title']."',".
5587
                        "".(!empty($row['comment']) ? "'".$row['comment']."'" : "NULL").",".
5588
                        (!empty($row['scope']) ? "'".$row['scope']."'" : "NULL").",".
5589
                        "".(!empty($row['subkeytext']) ? "'".$row['subkeytext']."'" : "NULL").",$access_url,".$row['access_url_changeable'].")";
5590
                    Database::query($insert);
5591
                }
5592
            } else { // Such a setting does not exist.
5593
                //error_log(__FILE__.':'.__LINE__.': Attempting to update setting '.$var.' ('.$subvar.') which does not exist at all. The access_url is: '.$access_url.' ',0);
5594
            }
5595
        }
5596
    }
5597
}
5598
5599
/**
5600
 * Sets a whole category of settings to one specific value.
5601
 *
5602
 * @param string    Category
5603
 * @param string    Value
5604
 * @param int       Access URL. Optional. Defaults to 1
5605
 * @param array     Optional array of filters on field type
5606
 * @param string $category
5607
 * @param string $value
5608
 *
5609
 * @return bool
5610
 */
5611
function api_set_settings_category($category, $value = null, $access_url = 1, $fieldtype = [])
5612
{
5613
    if (empty($category)) {
5614
        return false;
5615
    }
5616
    $category = Database::escape_string($category);
5617
    $t_s = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5618
    $access_url = (int) $access_url;
5619
    if (empty($access_url)) {
5620
        $access_url = 1;
5621
    }
5622
    if (isset($value)) {
5623
        $value = Database::escape_string($value);
5624
        $sql = "UPDATE $t_s SET selected_value = '$value'
5625
                WHERE category = '$category' AND access_url = $access_url";
5626
        if (is_array($fieldtype) && count($fieldtype) > 0) {
5627
            $sql .= " AND ( ";
5628
            $i = 0;
5629
            foreach ($fieldtype as $type) {
5630
                if ($i > 0) {
5631
                    $sql .= ' OR ';
5632
                }
5633
                $type = Database::escape_string($type);
5634
                $sql .= " type='".$type."' ";
5635
                $i++;
5636
            }
5637
            $sql .= ")";
5638
        }
5639
        $res = Database::query($sql);
5640
5641
        return $res !== false;
5642
    } else {
5643
        $sql = "UPDATE $t_s SET selected_value = NULL
5644
                WHERE category = '$category' AND access_url = $access_url";
5645
        if (is_array($fieldtype) && count($fieldtype) > 0) {
5646
            $sql .= " AND ( ";
5647
            $i = 0;
5648
            foreach ($fieldtype as $type) {
5649
                if ($i > 0) {
5650
                    $sql .= ' OR ';
5651
                }
5652
                $type = Database::escape_string($type);
5653
                $sql .= " type='".$type."' ";
5654
                $i++;
5655
            }
5656
            $sql .= ")";
5657
        }
5658
        $res = Database::query($sql);
5659
5660
        return $res !== false;
5661
    }
5662
}
5663
5664
/**
5665
 * Gets all available access urls in an array (as in the database).
5666
 *
5667
 * @return array An array of database records
5668
 */
5669
function api_get_access_urls($from = 0, $to = 1000000, $order = 'url', $direction = 'ASC')
5670
{
5671
    $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5672
    $from = (int) $from;
5673
    $to = (int) $to;
5674
    $order = Database::escape_string($order, null, false);
5675
    $direction = Database::escape_string($direction, null, false);
5676
    $sql = "SELECT id, url, description, active, created_by, tms
5677
            FROM $table
5678
            ORDER BY $order $direction
5679
            LIMIT $to OFFSET $from";
5680
    $res = Database::query($sql);
5681
5682
    return Database::store_result($res);
5683
}
5684
5685
/**
5686
 * Gets the access url info in an array.
5687
 *
5688
 * @param int  $id            Id of the access url
5689
 * @param bool $returnDefault Set to false if you want the real URL if URL 1 is still 'http://localhost/'
5690
 *
5691
 * @return array All the info (url, description, active, created_by, tms)
5692
 *               from the access_url table
5693
 *
5694
 * @author Julio Montoya
5695
 */
5696
function api_get_access_url($id, $returnDefault = true)
5697
{
5698
    static $staticResult;
5699
    $id = (int) $id;
5700
5701
    if (isset($staticResult[$id])) {
5702
        $result = $staticResult[$id];
5703
    } else {
5704
        // Calling the Database:: library dont work this is handmade.
5705
        $table_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5706
        $sql = "SELECT url, description, active, created_by, tms
5707
                FROM $table_access_url WHERE id = '$id' ";
5708
        $res = Database::query($sql);
5709
        $result = @Database::fetch_array($res);
5710
        $staticResult[$id] = $result;
5711
    }
5712
5713
    // If the result url is 'http://localhost/' (the default) and the root_web
5714
    // (=current url) is different, and the $id is = 1 (which might mean
5715
    // api_get_current_access_url_id() returned 1 by default), then return the
5716
    // root_web setting instead of the current URL
5717
    // This is provided as an option to avoid breaking the storage of URL-specific
5718
    // homepages in home/localhost/
5719
    if ($id === 1 && $returnDefault === false) {
5720
        $currentUrl = api_get_current_access_url_id();
5721
        // only do this if we are on the main URL (=1), otherwise we could get
5722
        // information on another URL instead of the one asked as parameter
5723
        if ($currentUrl === 1) {
5724
            $rootWeb = api_get_path(WEB_PATH);
5725
            $default = 'http://localhost/';
5726
            if ($result['url'] === $default && $rootWeb != $default) {
5727
                $result['url'] = $rootWeb;
5728
            }
5729
        }
5730
    }
5731
5732
    return $result;
5733
}
5734
5735
/**
5736
 * Gets all the current settings for a specific access url.
5737
 *
5738
 * @param string    The category, if any, that we want to get
5739
 * @param string    Whether we want a simple list (display a category) or
5740
 * a grouped list (group by variable as in settings.php default). Values: 'list' or 'group'
5741
 * @param int       Access URL's ID. Optional. Uses 1 by default, which is the unique URL
5742
 *
5743
 * @return array Array of database results for the current settings of the current access URL
5744
 */
5745
function &api_get_settings($cat = null, $ordering = 'list', $access_url = 1, $url_changeable = 0)
5746
{
5747
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5748
    $access_url = (int) $access_url;
5749
    $where_condition = '';
5750
    if ($url_changeable == 1) {
5751
        $where_condition = " AND access_url_changeable= '1' ";
5752
    }
5753
    if (empty($access_url) || $access_url == -1) {
5754
        $access_url = 1;
5755
    }
5756
    $sql = "SELECT * FROM $table
5757
            WHERE access_url = $access_url  $where_condition ";
5758
5759
    if (!empty($cat)) {
5760
        $cat = Database::escape_string($cat);
5761
        $sql .= " AND category='$cat' ";
5762
    }
5763
    if ($ordering == 'group') {
5764
        $sql .= " ORDER BY id ASC";
5765
    } else {
5766
        $sql .= " ORDER BY 1,2 ASC";
5767
    }
5768
    $result = Database::query($sql);
5769
    if ($result === null) {
5770
        return [];
5771
    }
5772
    $result = Database::store_result($result, 'ASSOC');
5773
5774
    return $result;
5775
}
5776
5777
/**
5778
 * @param string $value       The value we want to record
5779
 * @param string $variable    The variable name we want to insert
5780
 * @param string $subKey      The subkey for the variable we want to insert
5781
 * @param string $type        The type for the variable we want to insert
5782
 * @param string $category    The category for the variable we want to insert
5783
 * @param string $title       The title
5784
 * @param string $comment     The comment
5785
 * @param string $scope       The scope
5786
 * @param string $subKeyText  The subkey text
5787
 * @param int    $accessUrlId The access_url for which this parameter is valid
5788
 * @param int    $visibility  The changeability of this setting for non-master urls
5789
 *
5790
 * @return int The setting ID
5791
 */
5792
function api_add_setting(
5793
    $value,
5794
    $variable,
5795
    $subKey = '',
5796
    $type = 'textfield',
5797
    $category = '',
5798
    $title = '',
5799
    $comment = '',
5800
    $scope = '',
5801
    $subKeyText = '',
5802
    $accessUrlId = 1,
5803
    $visibility = 0
5804
) {
5805
    $em = Database::getManager();
5806
    $settingRepo = $em->getRepository('ChamiloCoreBundle:SettingsCurrent');
5807
    $accessUrlId = (int) $accessUrlId ?: 1;
5808
5809
    if (is_array($value)) {
5810
        $value = serialize($value);
5811
    } else {
5812
        $value = trim($value);
5813
    }
5814
5815
    $criteria = ['variable' => $variable, 'url' => $accessUrlId];
5816
5817
    if (!empty($subKey)) {
5818
        $criteria['subkey'] = $subKey;
5819
    }
5820
5821
    // Check if this variable doesn't exist already
5822
    /** @var SettingsCurrent $setting */
5823
    $setting = $settingRepo->findOneBy($criteria);
5824
5825
    if ($setting) {
0 ignored issues
show
introduced by
$setting is of type Chamilo\CoreBundle\Entity\SettingsCurrent, thus it always evaluated to true.
Loading history...
5826
        $setting->setSelectedValue($value);
5827
5828
        $em->persist($setting);
5829
        $em->flush();
5830
5831
        return $setting->getId();
5832
    }
5833
5834
    // Item not found for this access_url, we have to check if the whole thing is missing
5835
    // (in which case we ignore the insert) or if there *is* a record but just for access_url = 1
5836
    $setting = new SettingsCurrent();
5837
    $url = api_get_url_entity();
5838
5839
    $setting
5840
        ->setVariable($variable)
5841
        ->setSelectedValue($value)
5842
        ->setType($type)
5843
        ->setCategory($category)
5844
        ->setSubkey($subKey)
5845
        ->setTitle($title)
5846
        ->setComment($comment)
5847
        ->setScope($scope)
5848
        ->setSubkeytext($subKeyText)
5849
        ->setUrl(api_get_url_entity())
5850
        ->setAccessUrlChangeable($visibility);
5851
5852
    $em->persist($setting);
5853
    $em->flush();
5854
5855
    return $setting->getId();
5856
}
5857
5858
/**
5859
 * Checks wether a user can or can't view the contents of a course.
5860
 *
5861
 * @deprecated use CourseManager::is_user_subscribed_in_course
5862
 *
5863
 * @param int $userid User id or NULL to get it from $_SESSION
5864
 * @param int $cid    course id to check whether the user is allowed
5865
 *
5866
 * @return bool
5867
 */
5868
function api_is_course_visible_for_user($userid = null, $cid = null)
5869
{
5870
    if ($userid === null) {
5871
        $userid = api_get_user_id();
5872
    }
5873
    if (empty($userid) || strval(intval($userid)) != $userid) {
5874
        if (api_is_anonymous()) {
5875
            $userid = api_get_anonymous_id();
5876
        } else {
5877
            return false;
5878
        }
5879
    }
5880
    $cid = Database::escape_string($cid);
5881
5882
    $courseInfo = api_get_course_info($cid);
5883
    $courseId = $courseInfo['real_id'];
5884
    $is_platformAdmin = api_is_platform_admin();
5885
5886
    $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
5887
    $course_cat_table = Database::get_main_table(TABLE_MAIN_CATEGORY);
5888
5889
    $sql = "SELECT
5890
                $course_cat_table.code AS category_code,
5891
                $course_table.visibility,
5892
                $course_table.code,
5893
                $course_cat_table.code
5894
            FROM $course_table
5895
            LEFT JOIN $course_cat_table
5896
                ON $course_table.category_id = $course_cat_table.id
5897
            WHERE
5898
                $course_table.code = '$cid'
5899
            LIMIT 1";
5900
5901
    $result = Database::query($sql);
5902
5903
    if (Database::num_rows($result) > 0) {
5904
        $visibility = Database::fetch_array($result);
5905
        $visibility = $visibility['visibility'];
5906
    } else {
5907
        $visibility = 0;
5908
    }
5909
    // Shortcut permissions in case the visibility is "open to the world".
5910
    if ($visibility === COURSE_VISIBILITY_OPEN_WORLD) {
5911
        return true;
5912
    }
5913
5914
    $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
5915
5916
    $sql = "SELECT
5917
                is_tutor, status
5918
            FROM $tbl_course_user
5919
            WHERE
5920
                user_id  = '$userid' AND
5921
                relation_type <> '".COURSE_RELATION_TYPE_RRHH."' AND
5922
                c_id = $courseId
5923
            LIMIT 1";
5924
5925
    $result = Database::query($sql);
5926
5927
    if (Database::num_rows($result) > 0) {
5928
        // This user has got a recorded state for this course.
5929
        $cuData = Database::fetch_array($result);
5930
        $is_courseMember = true;
5931
        $is_courseAdmin = ($cuData['status'] == 1);
5932
    }
5933
5934
    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...
5935
        // This user has no status related to this course.
5936
        // Is it the session coach or the session admin?
5937
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
5938
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
5939
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
5940
5941
        $sql = "SELECT
5942
                    session.id_coach, session_admin_id, session.id
5943
                FROM
5944
                    $tbl_session as session
5945
                INNER JOIN $tbl_session_course
5946
                    ON session_rel_course.session_id = session.id
5947
                    AND session_rel_course.c_id = '$courseId'
5948
                LIMIT 1";
5949
5950
        $result = Database::query($sql);
5951
        $row = Database::store_result($result);
5952
5953
        if ($row[0]['id_coach'] == $userid) {
5954
            $is_courseMember = true;
5955
            $is_courseAdmin = false;
5956
        } elseif ($row[0]['session_admin_id'] == $userid) {
5957
            $is_courseMember = false;
5958
            $is_courseAdmin = false;
5959
        } else {
5960
            // Check if the current user is the course coach.
5961
            $sql = "SELECT 1
5962
                    FROM $tbl_session_course
5963
                    WHERE session_rel_course.c_id = '$courseId'
5964
                    AND session_rel_course.id_coach = '$userid'
5965
                    LIMIT 1";
5966
5967
            $result = Database::query($sql);
5968
5969
            //if ($row = Database::fetch_array($result)) {
5970
            if (Database::num_rows($result) > 0) {
5971
                $is_courseMember = true;
5972
                $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
5973
5974
                $sql = "SELECT status FROM $tbl_user
5975
                        WHERE user_id = $userid
5976
                        LIMIT 1";
5977
5978
                $result = Database::query($sql);
5979
5980
                if (Database::result($result, 0, 0) == 1) {
5981
                    $is_courseAdmin = true;
5982
                } else {
5983
                    $is_courseAdmin = false;
5984
                }
5985
            } else {
5986
                // Check if the user is a student is this session.
5987
                $sql = "SELECT  id
5988
                        FROM $tbl_session_course_user
5989
                        WHERE
5990
                            user_id  = '$userid' AND
5991
                            c_id = '$courseId'
5992
                        LIMIT 1";
5993
5994
                if (Database::num_rows($result) > 0) {
5995
                    // This user haa got a recorded state for this course.
5996
                    while ($row = Database::fetch_array($result)) {
5997
                        $is_courseMember = true;
5998
                        $is_courseAdmin = false;
5999
                    }
6000
                }
6001
            }
6002
        }
6003
    }
6004
6005
    switch ($visibility) {
6006
        case COURSE_VISIBILITY_OPEN_WORLD:
6007
            return true;
6008
        case COURSE_VISIBILITY_OPEN_PLATFORM:
6009
            return isset($userid);
6010
        case COURSE_VISIBILITY_REGISTERED:
6011
        case COURSE_VISIBILITY_CLOSED:
6012
            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...
6013
        case COURSE_VISIBILITY_HIDDEN:
6014
            return $is_platformAdmin;
6015
    }
6016
6017
    return false;
6018
}
6019
6020
/**
6021
 * Returns whether an element (forum, message, survey ...) belongs to a session or not.
6022
 *
6023
 * @param string the tool of the element
6024
 * @param int the element id in database
6025
 * @param int the session_id to compare with element session id
6026
 *
6027
 * @return bool true if the element is in the session, false else
6028
 */
6029
function api_is_element_in_the_session($tool, $element_id, $session_id = null)
6030
{
6031
    if (is_null($session_id)) {
6032
        $session_id = api_get_session_id();
6033
    }
6034
6035
    $element_id = (int) $element_id;
6036
6037
    if (empty($element_id)) {
6038
        return false;
6039
    }
6040
6041
    // Get information to build query depending of the tool.
6042
    switch ($tool) {
6043
        case TOOL_SURVEY:
6044
            $table_tool = Database::get_course_table(TABLE_SURVEY);
6045
            $key_field = 'survey_id';
6046
            break;
6047
        case TOOL_ANNOUNCEMENT:
6048
            $table_tool = Database::get_course_table(TABLE_ANNOUNCEMENT);
6049
            $key_field = 'id';
6050
            break;
6051
        case TOOL_AGENDA:
6052
            $table_tool = Database::get_course_table(TABLE_AGENDA);
6053
            $key_field = 'id';
6054
            break;
6055
        case TOOL_GROUP:
6056
            $table_tool = Database::get_course_table(TABLE_GROUP);
6057
            $key_field = 'id';
6058
            break;
6059
        default:
6060
            return false;
6061
    }
6062
    $course_id = api_get_course_int_id();
6063
6064
    $sql = "SELECT session_id FROM $table_tool
6065
            WHERE c_id = $course_id AND $key_field =  ".$element_id;
6066
    $rs = Database::query($sql);
6067
    if ($element_session_id = Database::result($rs, 0, 0)) {
6068
        if ($element_session_id == intval($session_id)) {
6069
            // The element belongs to the session.
6070
            return true;
6071
        }
6072
    }
6073
6074
    return false;
6075
}
6076
6077
/**
6078
 * Replaces "forbidden" characters in a filename string.
6079
 *
6080
 * @param string $filename
6081
 * @param bool   $treat_spaces_as_hyphens
6082
 *
6083
 * @return string
6084
 */
6085
function api_replace_dangerous_char($filename, $treat_spaces_as_hyphens = true)
6086
{
6087
    // Some non-properly encoded file names can cause the whole file to be
6088
    // skipped when uploaded. Avoid this by detecting the encoding and
6089
    // converting to UTF-8, setting the source as ASCII (a reasonably
6090
    // limited characters set) if nothing could be found (BT#
6091
    $encoding = api_detect_encoding($filename);
6092
    if (empty($encoding)) {
6093
        $encoding = 'ASCII';
6094
        if (!api_is_valid_ascii($filename)) {
6095
            // try iconv and try non standard ASCII a.k.a CP437
6096
            // see BT#15022
6097
            if (function_exists('iconv')) {
6098
                $result = iconv('CP437', 'UTF-8', $filename);
6099
                if (api_is_valid_utf8($result)) {
6100
                    $filename = $result;
6101
                    $encoding = 'UTF-8';
6102
                }
6103
            }
6104
        }
6105
    }
6106
6107
    $filename = api_to_system_encoding($filename, $encoding);
6108
6109
    $url = URLify::filter(
6110
        $filename,
6111
        250,
6112
        '',
6113
        true,
6114
        false,
6115
        false,
6116
        false,
6117
        $treat_spaces_as_hyphens
6118
    );
6119
6120
    return $url;
6121
}
6122
6123
/**
6124
 * Fixes the $_SERVER['REQUEST_URI'] that is empty in IIS6.
6125
 *
6126
 * @author Ivan Tcholakov, 28-JUN-2006.
6127
 */
6128
function api_request_uri()
6129
{
6130
    if (!empty($_SERVER['REQUEST_URI'])) {
6131
        return $_SERVER['REQUEST_URI'];
6132
    }
6133
    $uri = $_SERVER['SCRIPT_NAME'];
6134
    if (!empty($_SERVER['QUERY_STRING'])) {
6135
        $uri .= '?'.$_SERVER['QUERY_STRING'];
6136
    }
6137
    $_SERVER['REQUEST_URI'] = $uri;
6138
6139
    return $uri;
6140
}
6141
6142
/** Gets the current access_url id of the Chamilo Platform
6143
 * @author Julio Montoya <[email protected]>
6144
 *
6145
 * @return int access_url_id of the current Chamilo Installation
6146
 */
6147
function api_get_current_access_url_id()
6148
{
6149
    if (api_get_multiple_access_url() === false) {
6150
        return 1;
6151
    }
6152
6153
    static $id;
6154
    if (!empty($id)) {
6155
        return $id;
6156
    }
6157
6158
    $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
6159
    $path = Database::escape_string(api_get_path(WEB_PATH));
6160
    $sql = "SELECT id FROM $table WHERE url = '".$path."'";
6161
    $result = Database::query($sql);
6162
    if (Database::num_rows($result) > 0) {
6163
        $id = Database::result($result, 0, 0);
6164
        if ($id === false) {
6165
            return -1;
6166
        }
6167
6168
        return (int) $id;
6169
    }
6170
6171
    $id = 1;
6172
6173
    //if the url in WEB_PATH was not found, it can only mean that there is
6174
    // either a configuration problem or the first URL has not been defined yet
6175
    // (by default it is http://localhost/). Thus the more sensible thing we can
6176
    // do is return 1 (the main URL) as the user cannot hack this value anyway
6177
    return 1;
6178
}
6179
6180
/**
6181
 * Gets the registered urls from a given user id.
6182
 *
6183
 * @author Julio Montoya <[email protected]>
6184
 *
6185
 * @param int $user_id
6186
 *
6187
 * @return array
6188
 */
6189
function api_get_access_url_from_user($user_id)
6190
{
6191
    $user_id = (int) $user_id;
6192
    $table_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
6193
    $table_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
6194
    $sql = "SELECT access_url_id
6195
            FROM $table_url_rel_user url_rel_user
6196
            INNER JOIN $table_url u
6197
            ON (url_rel_user.access_url_id = u.id)
6198
            WHERE user_id = ".$user_id;
6199
    $result = Database::query($sql);
6200
    $list = [];
6201
    while ($row = Database::fetch_array($result, 'ASSOC')) {
6202
        $list[] = $row['access_url_id'];
6203
    }
6204
6205
    return $list;
6206
}
6207
6208
/**
6209
 * Gets the status of a user in a course.
6210
 *
6211
 * @param int $user_id
6212
 * @param int $courseId
6213
 *
6214
 * @return int user status
6215
 */
6216
function api_get_status_of_user_in_course($user_id, $courseId)
6217
{
6218
    $tbl_rel_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
6219
    if (!empty($user_id) && !empty($courseId)) {
6220
        $user_id = intval($user_id);
6221
        $courseId = intval($courseId);
6222
        $sql = 'SELECT status
6223
                FROM '.$tbl_rel_course_user.'
6224
                WHERE user_id='.$user_id.' AND c_id = '.$courseId;
6225
        $result = Database::query($sql);
6226
        $row_status = Database::fetch_array($result, 'ASSOC');
6227
6228
        return $row_status['status'];
6229
    } else {
6230
        return 0;
6231
    }
6232
}
6233
6234
/**
6235
 * Checks whether the curent user is in a group or not.
6236
 *
6237
 * @param string        The group id - optional (takes it from session if not given)
6238
 * @param string        The course code - optional (no additional check by course if course code is not given)
6239
 *
6240
 * @return bool
6241
 *
6242
 * @author Ivan Tcholakov
6243
 */
6244
function api_is_in_group($groupIdParam = null, $courseCodeParam = null)
6245
{
6246
    if (!empty($courseCodeParam)) {
6247
        $courseCode = api_get_course_id();
6248
        if (!empty($courseCode)) {
6249
            if ($courseCodeParam != $courseCode) {
6250
                return false;
6251
            }
6252
        } else {
6253
            return false;
6254
        }
6255
    }
6256
6257
    $groupId = api_get_group_id();
6258
6259
    if (isset($groupId) && $groupId != '') {
6260
        if (!empty($groupIdParam)) {
6261
            return $groupIdParam == $groupId;
6262
        } else {
6263
            return true;
6264
        }
6265
    }
6266
6267
    return false;
6268
}
6269
6270
/**
6271
 * Checks whether a secret key is valid.
6272
 *
6273
 * @param string $original_key_secret - secret key from (webservice) client
6274
 * @param string $security_key        - security key from Chamilo
6275
 *
6276
 * @return bool - true if secret key is valid, false otherwise
6277
 */
6278
function api_is_valid_secret_key($original_key_secret, $security_key)
6279
{
6280
    return $original_key_secret == sha1($security_key);
6281
}
6282
6283
/**
6284
 * Checks whether a user is into course.
6285
 *
6286
 * @param int $course_id - the course id
6287
 * @param int $user_id   - the user id
6288
 *
6289
 * @return bool
6290
 */
6291
function api_is_user_of_course($course_id, $user_id)
6292
{
6293
    $tbl_course_rel_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
6294
    $sql = 'SELECT user_id FROM '.$tbl_course_rel_user.'
6295
            WHERE
6296
                c_id ="'.intval($course_id).'" AND
6297
                user_id = "'.intval($user_id).'" AND
6298
                relation_type <> '.COURSE_RELATION_TYPE_RRHH.' ';
6299
    $result = Database::query($sql);
6300
6301
    return Database::num_rows($result) == 1;
6302
}
6303
6304
/**
6305
 * Checks whether the server's operating system is Windows (TM).
6306
 *
6307
 * @return bool - true if the operating system is Windows, false otherwise
6308
 */
6309
function api_is_windows_os()
6310
{
6311
    if (function_exists('php_uname')) {
6312
        // php_uname() exists as of PHP 4.0.2, according to the documentation.
6313
        // We expect that this function will always work for Chamilo 1.8.x.
6314
        $os = php_uname();
6315
    }
6316
    // The following methods are not needed, but let them stay, just in case.
6317
    elseif (isset($_ENV['OS'])) {
6318
        // Sometimes $_ENV['OS'] may not be present (bugs?)
6319
        $os = $_ENV['OS'];
6320
    } elseif (defined('PHP_OS')) {
6321
        // PHP_OS means on which OS PHP was compiled, this is why
6322
        // using PHP_OS is the last choice for detection.
6323
        $os = PHP_OS;
6324
    } else {
6325
        return false;
6326
    }
6327
6328
    return strtolower(substr((string) $os, 0, 3)) == 'win';
6329
}
6330
6331
/**
6332
 * This function informs whether the sent request is XMLHttpRequest.
6333
 */
6334
function api_is_xml_http_request()
6335
{
6336
    return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest';
6337
}
6338
6339
/**
6340
 * This wrapper function has been implemented for avoiding some known problems about the function getimagesize().
6341
 *
6342
 * @see http://php.net/manual/en/function.getimagesize.php
6343
 * @see http://www.dokeos.com/forum/viewtopic.php?t=12345
6344
 * @see http://www.dokeos.com/forum/viewtopic.php?t=16355
6345
 *
6346
 * @return int
6347
 */
6348
function api_getimagesize($path)
6349
{
6350
    $image = new Image($path);
6351
6352
    return $image->get_image_size();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $image->get_image_size() returns the type array|array<string,integer> which is incompatible with the documented return type integer.
Loading history...
6353
}
6354
6355
/**
6356
 * This function resizes an image, with preserving its proportions (or aspect ratio).
6357
 *
6358
 * @author Ivan Tcholakov, MAY-2009.
6359
 *
6360
 * @param int $image         System path or URL of the image
6361
 * @param int $target_width  Targeted width
6362
 * @param int $target_height Targeted height
6363
 *
6364
 * @return array Calculated new width and height
6365
 */
6366
function api_resize_image($image, $target_width, $target_height)
6367
{
6368
    $image_properties = api_getimagesize($image);
6369
6370
    return api_calculate_image_size(
6371
        $image_properties['width'],
6372
        $image_properties['height'],
6373
        $target_width,
6374
        $target_height
6375
    );
6376
}
6377
6378
/**
6379
 * This function calculates new image size, with preserving image's proportions (or aspect ratio).
6380
 *
6381
 * @author Ivan Tcholakov, MAY-2009.
6382
 * @author The initial idea has been taken from code by Patrick Cool, MAY-2004.
6383
 *
6384
 * @param int $image_width   Initial width
6385
 * @param int $image_height  Initial height
6386
 * @param int $target_width  Targeted width
6387
 * @param int $target_height Targeted height
6388
 *
6389
 * @return array Calculated new width and height
6390
 */
6391
function api_calculate_image_size(
6392
    $image_width,
6393
    $image_height,
6394
    $target_width,
6395
    $target_height
6396
) {
6397
    // Only maths is here.
6398
    $result = ['width' => $image_width, 'height' => $image_height];
6399
    if ($image_width <= 0 || $image_height <= 0) {
6400
        return $result;
6401
    }
6402
    $resize_factor_width = $target_width / $image_width;
6403
    $resize_factor_height = $target_height / $image_height;
6404
    $delta_width = $target_width - $image_width * $resize_factor_height;
6405
    $delta_height = $target_height - $image_height * $resize_factor_width;
6406
    if ($delta_width > $delta_height) {
6407
        $result['width'] = ceil($image_width * $resize_factor_height);
6408
        $result['height'] = ceil($image_height * $resize_factor_height);
6409
    } elseif ($delta_width < $delta_height) {
6410
        $result['width'] = ceil($image_width * $resize_factor_width);
6411
        $result['height'] = ceil($image_height * $resize_factor_width);
6412
    } else {
6413
        $result['width'] = ceil($target_width);
6414
        $result['height'] = ceil($target_height);
6415
    }
6416
6417
    return $result;
6418
}
6419
6420
/**
6421
 * Returns a list of Chamilo's tools or
6422
 * checks whether a given identificator is a valid Chamilo's tool.
6423
 *
6424
 * @author Isaac flores paz
6425
 *
6426
 * @param string The tool name to filter
6427
 *
6428
 * @return mixed Filtered string or array
6429
 */
6430
function api_get_tools_lists($my_tool = null)
6431
{
6432
    $tools_list = [
6433
        TOOL_DOCUMENT,
6434
        TOOL_THUMBNAIL,
6435
        TOOL_HOTPOTATOES,
6436
        TOOL_CALENDAR_EVENT,
6437
        TOOL_LINK,
6438
        TOOL_COURSE_DESCRIPTION,
6439
        TOOL_SEARCH,
6440
        TOOL_LEARNPATH,
6441
        TOOL_ANNOUNCEMENT,
6442
        TOOL_FORUM,
6443
        TOOL_THREAD,
6444
        TOOL_POST,
6445
        TOOL_DROPBOX,
6446
        TOOL_QUIZ,
6447
        TOOL_USER,
6448
        TOOL_GROUP,
6449
        TOOL_BLOGS,
6450
        TOOL_CHAT,
6451
        TOOL_STUDENTPUBLICATION,
6452
        TOOL_TRACKING,
6453
        TOOL_HOMEPAGE_LINK,
6454
        TOOL_COURSE_SETTING,
6455
        TOOL_BACKUP,
6456
        TOOL_COPY_COURSE_CONTENT,
6457
        TOOL_RECYCLE_COURSE,
6458
        TOOL_COURSE_HOMEPAGE,
6459
        TOOL_COURSE_RIGHTS_OVERVIEW,
6460
        TOOL_UPLOAD,
6461
        TOOL_COURSE_MAINTENANCE,
6462
        TOOL_SURVEY,
6463
        TOOL_WIKI,
6464
        TOOL_GLOSSARY,
6465
        TOOL_GRADEBOOK,
6466
        TOOL_NOTEBOOK,
6467
        TOOL_ATTENDANCE,
6468
        TOOL_COURSE_PROGRESS,
6469
    ];
6470
    if (empty($my_tool)) {
6471
        return $tools_list;
6472
    }
6473
6474
    return in_array($my_tool, $tools_list) ? $my_tool : '';
6475
}
6476
6477
/**
6478
 * Checks whether we already approved the last version term and condition.
6479
 *
6480
 * @param int user id
6481
 *
6482
 * @return bool true if we pass false otherwise
6483
 */
6484
function api_check_term_condition($userId)
6485
{
6486
    if (api_get_setting('allow_terms_conditions') === 'true') {
6487
        // Check if exists terms and conditions
6488
        if (LegalManager::count() == 0) {
6489
            return true;
6490
        }
6491
6492
        $extraFieldValue = new ExtraFieldValue('user');
6493
        $data = $extraFieldValue->get_values_by_handler_and_field_variable(
6494
            $userId,
6495
            'legal_accept'
6496
        );
6497
6498
        if (!empty($data) && isset($data['value']) && !empty($data['value'])) {
6499
            $result = $data['value'];
6500
            $user_conditions = explode(':', $result);
6501
            $version = $user_conditions[0];
6502
            $langId = $user_conditions[1];
6503
            $realVersion = LegalManager::get_last_version($langId);
6504
6505
            return $version >= $realVersion;
6506
        }
6507
6508
        return false;
6509
    }
6510
6511
    return false;
6512
}
6513
6514
/**
6515
 * Gets all information of a tool into course.
6516
 *
6517
 * @param int The tool id
6518
 *
6519
 * @return array
6520
 */
6521
function api_get_tool_information_by_name($name)
6522
{
6523
    $t_tool = Database::get_course_table(TABLE_TOOL_LIST);
6524
    $course_id = api_get_course_int_id();
6525
6526
    $sql = "SELECT id FROM tool
6527
            WHERE name = '".Database::escape_string($name)."' ";
6528
    $rs = Database::query($sql);
6529
    $data = Database::fetch_array($rs);
6530
    $tool = $data['id'];
6531
6532
    $sql = "SELECT * FROM $t_tool
6533
            WHERE c_id = $course_id  AND tool_id = '".$tool."' ";
6534
    $rs = Database::query($sql);
6535
6536
    return Database::fetch_array($rs, 'ASSOC');
6537
}
6538
6539
/**
6540
 * Function used to protect a "global" admin script.
6541
 * The function blocks access when the user has no global platform admin rights.
6542
 * Global admins are the admins that are registered in the main.admin table
6543
 * AND the users who have access to the "principal" portal.
6544
 * That means that there is a record in the main.access_url_rel_user table
6545
 * with his user id and the access_url_id=1.
6546
 *
6547
 * @author Julio Montoya
6548
 *
6549
 * @param int $user_id
6550
 *
6551
 * @return bool
6552
 */
6553
function api_is_global_platform_admin($user_id = null)
6554
{
6555
    $user_id = (int) $user_id;
6556
    if (empty($user_id)) {
6557
        $user_id = api_get_user_id();
6558
    }
6559
    if (api_is_platform_admin_by_id($user_id)) {
6560
        $urlList = api_get_access_url_from_user($user_id);
6561
        // The admin is registered in the first "main" site with access_url_id = 1
6562
        if (in_array(1, $urlList)) {
6563
            return true;
6564
        } else {
6565
            return false;
6566
        }
6567
    }
6568
6569
    return false;
6570
}
6571
6572
/**
6573
 * @param int  $admin_id_to_check
6574
 * @param int  $my_user_id
6575
 * @param bool $allow_session_admin
6576
 *
6577
 * @return bool
6578
 */
6579
function api_global_admin_can_edit_admin(
6580
    $admin_id_to_check,
6581
    $my_user_id = null,
6582
    $allow_session_admin = false
6583
) {
6584
    if (empty($my_user_id)) {
6585
        $my_user_id = api_get_user_id();
6586
    }
6587
6588
    $iam_a_global_admin = api_is_global_platform_admin($my_user_id);
6589
    $user_is_global_admin = api_is_global_platform_admin($admin_id_to_check);
6590
6591
    if ($iam_a_global_admin) {
6592
        // Global admin can edit everything
6593
        return true;
6594
    } else {
6595
        // If i'm a simple admin
6596
        $is_platform_admin = api_is_platform_admin_by_id($my_user_id);
6597
6598
        if ($allow_session_admin) {
6599
            $is_platform_admin = api_is_platform_admin_by_id($my_user_id) || (api_get_user_status($my_user_id) == SESSIONADMIN);
6600
        }
6601
6602
        if ($is_platform_admin) {
6603
            if ($user_is_global_admin) {
6604
                return false;
6605
            } else {
6606
                return true;
6607
            }
6608
        } else {
6609
            return false;
6610
        }
6611
    }
6612
}
6613
6614
/**
6615
 * @param int  $admin_id_to_check
6616
 * @param int  $my_user_id
6617
 * @param bool $allow_session_admin
6618
 *
6619
 * @return bool|null
6620
 */
6621
function api_protect_super_admin($admin_id_to_check, $my_user_id = null, $allow_session_admin = false)
6622
{
6623
    if (api_global_admin_can_edit_admin($admin_id_to_check, $my_user_id, $allow_session_admin)) {
6624
        return true;
6625
    } else {
6626
        api_not_allowed();
6627
    }
6628
}
6629
6630
/**
6631
 * Function used to protect a global admin script.
6632
 * The function blocks access when the user has no global platform admin rights.
6633
 * See also the api_is_global_platform_admin() function wich defines who's a "global" admin.
6634
 *
6635
 * @author Julio Montoya
6636
 */
6637
function api_protect_global_admin_script()
6638
{
6639
    if (!api_is_global_platform_admin()) {
6640
        api_not_allowed();
6641
6642
        return false;
6643
    }
6644
6645
    return true;
6646
}
6647
6648
/**
6649
 * Check browser support for specific file types or features
6650
 * This function checks if the user's browser supports a file format or given
6651
 * feature, or returns the current browser and major version when
6652
 * $format=check_browser. Only a limited number of formats and features are
6653
 * checked by this method. Make sure you check its definition first.
6654
 *
6655
 * @param string $format Can be a file format (extension like svg, webm, ...) or a feature (like autocapitalize, ...)
6656
 *
6657
 * @deprecated
6658
 *
6659
 * @return bool or return text array if $format=check_browser
6660
 *
6661
 * @author Juan Carlos Raña Trabado
6662
 */
6663
function api_browser_support($format = '')
0 ignored issues
show
Unused Code introduced by
The parameter $format is not used and could be removed. ( Ignorable by Annotation )

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

6663
function api_browser_support(/** @scrutinizer ignore-unused */ $format = '')

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
6664
{
6665
    return true;
6666
6667
    $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...
6668
    $current_browser = $browser->getBrowser();
6669
    $a_versiontemp = explode('.', $browser->getVersion());
6670
    $current_majorver = $a_versiontemp[0];
6671
6672
    static $result;
6673
6674
    if (isset($result[$format])) {
6675
        return $result[$format];
6676
    }
6677
6678
    // Native svg support
6679
    if ($format == 'svg') {
6680
        if (($current_browser == 'Internet Explorer' && $current_majorver >= 9) ||
6681
            ($current_browser == 'Firefox' && $current_majorver > 1) ||
6682
            ($current_browser == 'Safari' && $current_majorver >= 4) ||
6683
            ($current_browser == 'Chrome' && $current_majorver >= 1) ||
6684
            ($current_browser == 'Opera' && $current_majorver >= 9)
6685
        ) {
6686
            $result[$format] = true;
6687
6688
            return true;
6689
        } else {
6690
            $result[$format] = false;
6691
6692
            return false;
6693
        }
6694
    } elseif ($format == 'pdf') {
6695
        // native pdf support
6696
        if ($current_browser == 'Chrome' && $current_majorver >= 6) {
6697
            $result[$format] = true;
6698
6699
            return true;
6700
        } else {
6701
            $result[$format] = false;
6702
6703
            return false;
6704
        }
6705
    } elseif ($format == 'tif' || $format == 'tiff') {
6706
        //native tif support
6707
        if ($current_browser == 'Safari' && $current_majorver >= 5) {
6708
            $result[$format] = true;
6709
6710
            return true;
6711
        } else {
6712
            $result[$format] = false;
6713
6714
            return false;
6715
        }
6716
    } elseif ($format == 'ogg' || $format == 'ogx' || $format == 'ogv' || $format == 'oga') {
6717
        //native ogg, ogv,oga support
6718
        if (($current_browser == 'Firefox' && $current_majorver >= 3) ||
6719
            ($current_browser == 'Chrome' && $current_majorver >= 3) ||
6720
            ($current_browser == 'Opera' && $current_majorver >= 9)) {
6721
            $result[$format] = true;
6722
6723
            return true;
6724
        } else {
6725
            $result[$format] = false;
6726
6727
            return false;
6728
        }
6729
    } elseif ($format == 'mpg' || $format == 'mpeg') {
6730
        //native mpg support
6731
        if (($current_browser == 'Safari' && $current_majorver >= 5)) {
6732
            $result[$format] = true;
6733
6734
            return true;
6735
        } else {
6736
            $result[$format] = false;
6737
6738
            return false;
6739
        }
6740
    } elseif ($format == 'mp4') {
6741
        //native mp4 support (TODO: Android, iPhone)
6742
        if ($current_browser == 'Android' || $current_browser == 'iPhone') {
6743
            $result[$format] = true;
6744
6745
            return true;
6746
        } else {
6747
            $result[$format] = false;
6748
6749
            return false;
6750
        }
6751
    } elseif ($format == 'mov') {
6752
        //native mov support( TODO:check iPhone)
6753
        if ($current_browser == 'Safari' && $current_majorver >= 5 || $current_browser == 'iPhone') {
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: ($current_browser == 'Sa...ent_browser == 'iPhone', Probably Intended Meaning: $current_browser == 'Saf...nt_browser == 'iPhone')
Loading history...
6754
            $result[$format] = true;
6755
6756
            return true;
6757
        } else {
6758
            $result[$format] = false;
6759
6760
            return false;
6761
        }
6762
    } elseif ($format == 'avi') {
6763
        //native avi support
6764
        if ($current_browser == 'Safari' && $current_majorver >= 5) {
6765
            $result[$format] = true;
6766
6767
            return true;
6768
        } else {
6769
            $result[$format] = false;
6770
6771
            return false;
6772
        }
6773
    } elseif ($format == 'wmv') {
6774
        //native wmv support
6775
        if ($current_browser == 'Firefox' && $current_majorver >= 4) {
6776
            $result[$format] = true;
6777
6778
            return true;
6779
        } else {
6780
            $result[$format] = false;
6781
6782
            return false;
6783
        }
6784
    } elseif ($format == 'webm') {
6785
        //native webm support (TODO:check IE9, Chrome9, Android)
6786
        if (($current_browser == 'Firefox' && $current_majorver >= 4) ||
6787
            ($current_browser == 'Opera' && $current_majorver >= 9) ||
6788
            ($current_browser == 'Internet Explorer' && $current_majorver >= 9) ||
6789
            ($current_browser == 'Chrome' && $current_majorver >= 9) ||
6790
            $current_browser == 'Android'
6791
        ) {
6792
            $result[$format] = true;
6793
6794
            return true;
6795
        } else {
6796
            $result[$format] = false;
6797
6798
            return false;
6799
        }
6800
    } elseif ($format == 'wav') {
6801
        //native wav support (only some codecs !)
6802
        if (($current_browser == 'Firefox' && $current_majorver >= 4) ||
6803
            ($current_browser == 'Safari' && $current_majorver >= 5) ||
6804
            ($current_browser == 'Opera' && $current_majorver >= 9) ||
6805
            ($current_browser == 'Internet Explorer' && $current_majorver >= 9) ||
6806
            ($current_browser == 'Chrome' && $current_majorver > 9) ||
6807
            $current_browser == 'Android' ||
6808
            $current_browser == 'iPhone'
6809
        ) {
6810
            $result[$format] = true;
6811
6812
            return true;
6813
        } else {
6814
            $result[$format] = false;
6815
6816
            return false;
6817
        }
6818
    } elseif ($format == 'mid' || $format == 'kar') {
6819
        //native midi support (TODO:check Android)
6820
        if ($current_browser == 'Opera' && $current_majorver >= 9 || $current_browser == 'Android') {
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: ($current_browser == 'Op...nt_browser == 'Android', Probably Intended Meaning: $current_browser == 'Ope...t_browser == 'Android')
Loading history...
6821
            $result[$format] = true;
6822
6823
            return true;
6824
        } else {
6825
            $result[$format] = false;
6826
6827
            return false;
6828
        }
6829
    } elseif ($format == 'wma') {
6830
        //native wma support
6831
        if ($current_browser == 'Firefox' && $current_majorver >= 4) {
6832
            $result[$format] = true;
6833
6834
            return true;
6835
        } else {
6836
            $result[$format] = false;
6837
6838
            return false;
6839
        }
6840
    } elseif ($format == 'au') {
6841
        //native au support
6842
        if ($current_browser == 'Safari' && $current_majorver >= 5) {
6843
            $result[$format] = true;
6844
6845
            return true;
6846
        } else {
6847
            $result[$format] = false;
6848
6849
            return false;
6850
        }
6851
    } elseif ($format == 'mp3') {
6852
        //native mp3 support (TODO:check Android, iPhone)
6853
        if (($current_browser == 'Safari' && $current_majorver >= 5) ||
6854
            ($current_browser == 'Chrome' && $current_majorver >= 6) ||
6855
            ($current_browser == 'Internet Explorer' && $current_majorver >= 9) ||
6856
            $current_browser == 'Android' ||
6857
            $current_browser == 'iPhone' ||
6858
            $current_browser == 'Firefox'
6859
        ) {
6860
            $result[$format] = true;
6861
6862
            return true;
6863
        } else {
6864
            $result[$format] = false;
6865
6866
            return false;
6867
        }
6868
    } elseif ($format == 'autocapitalize') {
6869
        // Help avoiding showing the autocapitalize option if the browser doesn't
6870
        // support it: this attribute is against the HTML5 standard
6871
        if ($current_browser == 'Safari' || $current_browser == 'iPhone') {
6872
            return true;
6873
        } else {
6874
            return false;
6875
        }
6876
    } elseif ($format == "check_browser") {
6877
        $array_check_browser = [$current_browser, $current_majorver];
6878
6879
        return $array_check_browser;
6880
    } else {
6881
        $result[$format] = false;
6882
6883
        return false;
6884
    }
6885
}
6886
6887
/**
6888
 * This function checks if exist path and file browscap.ini
6889
 * In order for this to work, your browscap configuration setting in php.ini
6890
 * must point to the correct location of the browscap.ini file on your system
6891
 * http://php.net/manual/en/function.get-browser.php.
6892
 *
6893
 * @return bool
6894
 *
6895
 * @author Juan Carlos Raña Trabado
6896
 */
6897
function api_check_browscap()
6898
{
6899
    $setting = ini_get('browscap');
6900
    if ($setting) {
6901
        $browser = get_browser($_SERVER['HTTP_USER_AGENT'], true);
6902
        if (strpos($setting, 'browscap.ini') && !empty($browser)) {
6903
            return true;
6904
        }
6905
    }
6906
6907
    return false;
6908
}
6909
6910
/**
6911
 * Returns the <script> HTML tag.
6912
 */
6913
function api_get_js($file)
6914
{
6915
    return '<script type="text/javascript" src="'.api_get_path(WEB_LIBRARY_PATH).'javascript/'.$file.'"></script>'."\n";
6916
}
6917
6918
function api_get_build_js($file)
6919
{
6920
    return '<script type="text/javascript" src="'.api_get_path(WEB_PUBLIC_PATH).'build/'.$file.'"></script>'."\n";
6921
}
6922
6923
/**
6924
 * Returns the <script> HTML tag.
6925
 *
6926
 * @return string
6927
 */
6928
function api_get_asset($file)
6929
{
6930
    return '<script type="text/javascript" src="'.api_get_path(WEB_PUBLIC_PATH).'build/libs/'.$file.'"></script>'."\n";
6931
}
6932
6933
/**
6934
 * Returns the <script> HTML tag.
6935
 *
6936
 * @param string $file
6937
 * @param string $media
6938
 *
6939
 * @return string
6940
 */
6941
function api_get_css_asset($file, $media = 'screen')
6942
{
6943
    return '<link href="'.api_get_path(WEB_PUBLIC_PATH).'libs/'.$file.'" rel="stylesheet" media="'.$media.'" type="text/css" />'."\n";
6944
}
6945
6946
/**
6947
 * Returns the <link> HTML tag.
6948
 *
6949
 * @param string $file
6950
 * @param string $media
6951
 */
6952
function api_get_css($file, $media = 'screen')
6953
{
6954
    return '<link href="'.$file.'" rel="stylesheet" media="'.$media.'" type="text/css" />'."\n";
6955
}
6956
6957
function api_get_bootstrap_and_font_awesome($returnOnlyPath = false)
6958
{
6959
    $url = api_get_path(WEB_PUBLIC_PATH).'build/css/bootstrap.css';
6960
    if ($returnOnlyPath) {
6961
        return $url;
6962
    }
6963
6964
    return '<link href="'.$url.'" rel="stylesheet" type="text/css" />'."\n";
6965
}
6966
6967
/**
6968
 * Returns the js header to include the jquery library.
6969
 */
6970
function api_get_jquery_js()
6971
{
6972
    return api_get_asset('jquery/jquery.min.js');
6973
}
6974
6975
/**
6976
 * Returns the jquery path.
6977
 *
6978
 * @return string
6979
 */
6980
function api_get_jquery_web_path()
6981
{
6982
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery/jquery.min.js';
6983
}
6984
6985
/**
6986
 * @return string
6987
 */
6988
function api_get_jquery_ui_js_web_path()
6989
{
6990
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery-ui/jquery-ui.min.js';
6991
}
6992
6993
/**
6994
 * @return string
6995
 */
6996
function api_get_jquery_ui_css_web_path()
6997
{
6998
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery-ui/themes/smoothness/jquery-ui.min.css';
6999
}
7000
7001
/**
7002
 * Returns the jquery-ui library js headers.
7003
 *
7004
 * @return string html tags
7005
 */
7006
function api_get_jquery_ui_js()
7007
{
7008
    $libraries = [];
7009
7010
    return api_get_jquery_libraries_js($libraries);
7011
}
7012
7013
function api_get_jqgrid_js()
7014
{
7015
    $routePublic = Container::getRouter()->generate('home');
7016
7017
    return api_get_css($routePublic.'build/free-jqgrid.css').PHP_EOL
7018
        .api_get_js_simple($routePublic.'build/free-jqgrid.js');
7019
}
7020
7021
/**
7022
 * Returns the jquery library js and css headers.
7023
 *
7024
 * @param   array   list of jquery libraries supported jquery-ui
7025
 * @param   bool    add the jquery library
7026
 *
7027
 * @return string html tags
7028
 */
7029
function api_get_jquery_libraries_js($libraries)
7030
{
7031
    $js = '';
7032
7033
    //Document multiple upload funcionality
7034
    if (in_array('jquery-uploadzs', $libraries)) {
7035
        $js .= api_get_asset('blueimp-load-image/js/load-image.all.min.js');
7036
        $js .= api_get_asset('blueimp-canvas-to-blob/js/canvas-to-blob.min.js');
7037
        $js .= api_get_asset('jquery-file-upload/js/jquery.iframe-transport.js');
7038
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload.js');
7039
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-process.js');
7040
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-image.js');
7041
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-audio.js');
7042
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-video.js');
7043
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-validate.js');
7044
7045
        $js .= api_get_css(api_get_path(WEB_PUBLIC_PATH).'assets/jquery-file-upload/css/jquery.fileupload.css');
7046
        $js .= api_get_css(api_get_path(WEB_PUBLIC_PATH).'assets/jquery-file-upload/css/jquery.fileupload-ui.css');
7047
    }
7048
7049
    // jquery datepicker
7050
    if (in_array('datepicker', $libraries)) {
7051
        $languaje = 'en-GB';
7052
        $platform_isocode = strtolower(api_get_language_isocode());
7053
7054
        $datapicker_langs = [
7055
            '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',
7056
        ];
7057
        if (in_array($platform_isocode, $datapicker_langs)) {
7058
            $languaje = $platform_isocode;
7059
        }
7060
7061
        $js .= api_get_js('jquery-ui/jquery-ui-i18n.min.js');
7062
        $script = '<script>
7063
        $(function(){
7064
            $.datepicker.setDefaults($.datepicker.regional["'.$languaje.'"]);
7065
            $.datepicker.regional["local"] = $.datepicker.regional["'.$languaje.'"];
7066
        });
7067
        </script>
7068
        ';
7069
        $js .= $script;
7070
    }
7071
7072
    return $js;
7073
}
7074
7075
/**
7076
 * Returns the URL to the course or session, removing the complexity of the URL
7077
 * building piece by piece.
7078
 *
7079
 * This function relies on api_get_course_info()
7080
 *
7081
 * @param string $courseCode The course code - optional (takes it from context if not given)
7082
 * @param int    $sessionId  The session ID  - optional (takes it from context if not given)
7083
 * @param int    $groupId    The group ID - optional (takes it from context if not given)
7084
 *
7085
 * @return string The URL to a course, a session, or empty string if nothing works e.g. https://localhost/courses/ABC/index.php?session_id=3&gidReq=1
7086
 *
7087
 * @author  Julio Montoya <[email protected]>
7088
 */
7089
function api_get_course_url($courseCode = null, $sessionId = null, $groupId = null)
7090
{
7091
    $courseDirectory = '';
7092
    $url = '';
7093
    // If courseCode not set, get context or []
7094
    if (empty($courseCode)) {
7095
        $courseInfo = api_get_course_info();
7096
    } else {
7097
        $courseInfo = api_get_course_info($courseCode);
7098
    }
7099
7100
    // If course defined, get directory, otherwise keep empty string
7101
    if (!empty($courseInfo['directory'])) {
7102
        $courseDirectory = $courseInfo['directory'];
7103
    }
7104
7105
    // If sessionId not set, get context or 0
7106
    if (empty($sessionId)) {
7107
        $sessionId = api_get_session_id();
7108
    }
7109
7110
    // If groupId not set, get context or 0
7111
    if (empty($groupId)) {
7112
        $groupId = api_get_group_id();
7113
    }
7114
7115
    // Build the URL
7116
    if (!empty($courseDirectory)) {
7117
        // directory not empty, so we do have a course
7118
        $url = api_get_path(WEB_COURSE_PATH).$courseDirectory.'/index.php?id_session='.$sessionId.'&gidReq='.$groupId;
7119
    } elseif (!empty($sessionId) &&
7120
        api_get_setting('session.remove_session_url') !== 'true'
7121
    ) {
7122
        // if the course was unset and the session was set, send directly to the session
7123
        $url = api_get_path(WEB_CODE_PATH).'session/index.php?session_id='.$sessionId;
7124
    }
7125
7126
    // if not valid combination was found, return an empty string
7127
    return $url;
7128
}
7129
7130
/**
7131
 * Check if the current portal has the $_configuration['multiple_access_urls'] parameter on.
7132
 *
7133
 * @return bool true if multi site is enabled
7134
 */
7135
function api_get_multiple_access_url()
7136
{
7137
    global $_configuration;
7138
    if (isset($_configuration['multiple_access_urls']) && $_configuration['multiple_access_urls']) {
7139
        return true;
7140
    }
7141
7142
    return false;
7143
}
7144
7145
/**
7146
 * @return bool
7147
 */
7148
function api_is_multiple_url_enabled()
7149
{
7150
    return api_get_multiple_access_url();
7151
}
7152
7153
/**
7154
 * Returns a md5 unique id.
7155
 *
7156
 * @todo add more parameters
7157
 */
7158
function api_get_unique_id()
7159
{
7160
    $id = md5(time().uniqid().api_get_user_id().api_get_course_id().api_get_session_id());
7161
7162
    return $id;
7163
}
7164
7165
/**
7166
 * @param int Course id
7167
 * @param int tool id: TOOL_QUIZ, TOOL_FORUM, TOOL_STUDENTPUBLICATION, TOOL_LEARNPATH
7168
 * @param int the item id (tool id, exercise id, lp id)
7169
 *
7170
 * @return bool
7171
 */
7172
function api_resource_is_locked_by_gradebook($item_id, $link_type, $course_code = null)
7173
{
7174
    if (api_is_platform_admin()) {
7175
        return false;
7176
    }
7177
    if (api_get_setting('gradebook_locking_enabled') == 'true') {
7178
        if (empty($course_code)) {
7179
            $course_code = api_get_course_id();
7180
        }
7181
        $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_LINK);
7182
        $item_id = (int) $item_id;
7183
        $link_type = (int) $link_type;
7184
        $course_code = Database::escape_string($course_code);
7185
        $sql = "SELECT locked FROM $table
7186
                WHERE locked = 1 AND ref_id = $item_id AND type = $link_type AND course_code = '$course_code' ";
7187
        $result = Database::query($sql);
7188
        if (Database::num_rows($result)) {
7189
            return true;
7190
        }
7191
    }
7192
7193
    return false;
7194
}
7195
7196
/**
7197
 * Blocks a page if the item was added in a gradebook.
7198
 *
7199
 * @param int       exercise id, work id, thread id,
7200
 * @param int       LINK_EXERCISE, LINK_STUDENTPUBLICATION, LINK_LEARNPATH LINK_FORUM_THREAD, LINK_ATTENDANCE
7201
 * see gradebook/lib/be/linkfactory
7202
 * @param string    course code
7203
 *
7204
 * @return false|null
7205
 */
7206
function api_block_course_item_locked_by_gradebook($item_id, $link_type, $course_code = null)
7207
{
7208
    if (api_is_platform_admin()) {
7209
        return false;
7210
    }
7211
7212
    if (api_resource_is_locked_by_gradebook($item_id, $link_type, $course_code)) {
7213
        $message = Display::return_message(get_lang('This option is not available because this activity is contained by an assessment, which is currently locked. To unlock the assessment, ask your platform administrator.'), 'warning');
7214
        api_not_allowed(true, $message);
7215
    }
7216
}
7217
7218
/**
7219
 * Checks the PHP version installed is enough to run Chamilo.
7220
 *
7221
 * @param string Include path (used to load the error page)
7222
 */
7223
function api_check_php_version()
7224
{
7225
    if (!function_exists('version_compare') ||
7226
        version_compare(phpversion(), REQUIRED_PHP_VERSION, '<')
7227
    ) {
7228
        throw new Exception('Wrong PHP version');
7229
    }
7230
}
7231
7232
/**
7233
 * Checks whether the Archive directory is present and writeable. If not,
7234
 * prints a warning message.
7235
 */
7236
function api_check_archive_dir()
7237
{
7238
    if (is_dir(api_get_path(SYS_ARCHIVE_PATH)) && !is_writable(api_get_path(SYS_ARCHIVE_PATH))) {
7239
        $message = Display::return_message(get_lang('The app/cache/ directory, used by this tool, is not writeable. Please contact your platform administrator.'), 'warning');
7240
        api_not_allowed(true, $message);
7241
    }
7242
}
7243
7244
/**
7245
 * Returns an array of global configuration settings which should be ignored
7246
 * when printing the configuration settings screens.
7247
 *
7248
 * @return array Array of strings, each identifying one of the excluded settings
7249
 */
7250
function api_get_locked_settings()
7251
{
7252
    return [
7253
        'permanently_remove_deleted_files',
7254
        'account_valid_duration',
7255
        'service_ppt2lp',
7256
        'wcag_anysurfer_public_pages',
7257
        'upload_extensions_list_type',
7258
        'upload_extensions_blacklist',
7259
        'upload_extensions_whitelist',
7260
        'upload_extensions_skip',
7261
        'upload_extensions_replace_by',
7262
        'hide_dltt_markup',
7263
        'split_users_upload_directory',
7264
        'permissions_for_new_directories',
7265
        'permissions_for_new_files',
7266
        'platform_charset',
7267
        'ldap_description',
7268
        'cas_activate',
7269
        'cas_server',
7270
        'cas_server_uri',
7271
        'cas_port',
7272
        'cas_protocol',
7273
        'cas_add_user_activate',
7274
        'update_user_info_cas_with_ldap',
7275
        'languagePriority1',
7276
        'languagePriority2',
7277
        'languagePriority3',
7278
        'languagePriority4',
7279
        'login_is_email',
7280
        'chamilo_database_version',
7281
    ];
7282
}
7283
7284
/**
7285
 * Checks if the user is corrently logged in. Returns the user ID if he is, or
7286
 * false if he isn't. If the user ID is given and is an integer, then the same
7287
 * ID is simply returned.
7288
 *
7289
 * @param  int User ID
7290
 *
7291
 * @return bool Integer User ID is logged in, or false otherwise
7292
 */
7293
function api_user_is_login($user_id = null)
0 ignored issues
show
Unused Code introduced by
The parameter $user_id is not used and could be removed. ( Ignorable by Annotation )

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

7293
function api_user_is_login(/** @scrutinizer ignore-unused */ $user_id = null)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
7294
{
7295
    return Container::getAuthorizationChecker()->isGranted('IS_AUTHENTICATED_FULLY');
7296
}
7297
7298
/**
7299
 * Guess the real ip for register in the database, even in reverse proxy cases.
7300
 * To be recognized, the IP has to be found in either $_SERVER['REMOTE_ADDR'] or
7301
 * in $_SERVER['HTTP_X_FORWARDED_FOR'], which is in common use with rproxies.
7302
 * Note: the result of this function is not SQL-safe. Please escape it before
7303
 * inserting in a database.
7304
 *
7305
 * @return string the user's real ip (unsafe - escape it before inserting to db)
7306
 *
7307
 * @author Jorge Frisancho Jibaja <[email protected]>, USIL - Some changes to allow the use of real IP using reverse proxy
7308
 *
7309
 * @version CEV CHANGE 24APR2012
7310
 */
7311
function api_get_real_ip()
7312
{
7313
    $ip = trim($_SERVER['REMOTE_ADDR']);
7314
    if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
7315
        if (preg_match('/,/', $_SERVER['HTTP_X_FORWARDED_FOR'])) {
7316
            @list($ip1, $ip2) = @explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
7317
        } else {
7318
            $ip1 = $_SERVER['HTTP_X_FORWARDED_FOR'];
7319
        }
7320
        $ip = trim($ip1);
7321
    }
7322
7323
    return $ip;
7324
}
7325
7326
/**
7327
 * Checks whether an IP is included inside an IP range.
7328
 *
7329
 * @param string IP address
7330
 * @param string IP range
7331
 * @param string $ip
7332
 *
7333
 * @return bool True if IP is in the range, false otherwise
7334
 *
7335
 * @author claudiu at cnixs dot com  on http://www.php.net/manual/fr/ref.network.php#55230
7336
 * @author Yannick Warnier for improvements and managment of multiple ranges
7337
 *
7338
 * @todo check for IPv6 support
7339
 */
7340
function api_check_ip_in_range($ip, $range)
7341
{
7342
    if (empty($ip) or empty($range)) {
7343
        return false;
7344
    }
7345
    $ip_ip = ip2long($ip);
7346
    // divide range param into array of elements
7347
    if (strpos($range, ',') !== false) {
7348
        $ranges = explode(',', $range);
7349
    } else {
7350
        $ranges = [$range];
7351
    }
7352
    foreach ($ranges as $range) {
0 ignored issues
show
introduced by
$range is overwriting one of the parameters of this function.
Loading history...
7353
        $range = trim($range);
7354
        if (empty($range)) {
7355
            continue;
7356
        }
7357
        if (strpos($range, '/') === false) {
7358
            if (strcmp($ip, $range) === 0) {
7359
                return true; // there is a direct IP match, return OK
7360
            }
7361
            continue; //otherwise, get to the next range
7362
        }
7363
        // the range contains a "/", so analyse completely
7364
        list($net, $mask) = explode("/", $range);
7365
7366
        $ip_net = ip2long($net);
7367
        // mask binary magic
7368
        $ip_mask = ~((1 << (32 - $mask)) - 1);
7369
7370
        $ip_ip_net = $ip_ip & $ip_mask;
7371
        if ($ip_ip_net == $ip_net) {
7372
            return true;
7373
        }
7374
    }
7375
7376
    return false;
7377
}
7378
7379
function api_check_user_access_to_legal($course_visibility)
7380
{
7381
    $course_visibility_list = [COURSE_VISIBILITY_OPEN_WORLD, COURSE_VISIBILITY_OPEN_PLATFORM];
7382
7383
    return in_array($course_visibility, $course_visibility_list) || api_is_drh();
7384
}
7385
7386
/**
7387
 * Checks if the global chat is enabled or not.
7388
 *
7389
 * @return bool
7390
 */
7391
function api_is_global_chat_enabled()
7392
{
7393
    return
7394
        !api_is_anonymous() &&
7395
        api_get_setting('allow_global_chat') === 'true' &&
7396
        api_get_setting('allow_social_tool') === 'true';
7397
}
7398
7399
/**
7400
 * @todo Fix tool_visible_by_default_at_creation labels
7401
 * @todo Add sessionId parameter to avoid using context
7402
 *
7403
 * @param int   $item_id
7404
 * @param int   $tool_id
7405
 * @param int   $group_id   id
7406
 * @param array $courseInfo
7407
 * @param int   $sessionId
7408
 * @param int   $userId
7409
 */
7410
function api_set_default_visibility(
7411
    $item_id,
7412
    $tool_id,
7413
    $group_id = 0,
7414
    $courseInfo = [],
7415
    $sessionId = 0,
7416
    $userId = 0
7417
) {
7418
    $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
7419
    $courseId = $courseInfo['real_id'];
7420
    $courseCode = $courseInfo['code'];
7421
    $sessionId = empty($sessionId) ? api_get_session_id() : $sessionId;
7422
    $userId = empty($userId) ? api_get_user_id() : $userId;
7423
7424
    // if group is null force group_id = 0, this force is needed to create a LP folder with group = 0
7425
    if (is_null($group_id)) {
7426
        $group_id = 0;
7427
    } else {
7428
        $group_id = empty($group_id) ? api_get_group_id() : $group_id;
7429
    }
7430
7431
    $groupInfo = [];
7432
    if (!empty($group_id)) {
7433
        $groupInfo = GroupManager::get_group_properties($group_id);
7434
    }
7435
    $original_tool_id = $tool_id;
7436
7437
    switch ($tool_id) {
7438
        case TOOL_LINK:
7439
        case TOOL_LINK_CATEGORY:
7440
            $tool_id = 'links';
7441
            break;
7442
        case TOOL_DOCUMENT:
7443
            $tool_id = 'documents';
7444
            break;
7445
        case TOOL_LEARNPATH:
7446
            $tool_id = 'learning';
7447
            break;
7448
        case TOOL_ANNOUNCEMENT:
7449
            $tool_id = 'announcements';
7450
            break;
7451
        case TOOL_FORUM:
7452
        case TOOL_FORUM_CATEGORY:
7453
        case TOOL_FORUM_THREAD:
7454
            $tool_id = 'forums';
7455
            break;
7456
        case TOOL_QUIZ:
7457
            $tool_id = 'quiz';
7458
            break;
7459
    }
7460
    $setting = api_get_setting('tool_visible_by_default_at_creation');
7461
7462
    if (isset($setting[$tool_id])) {
7463
        $visibility = 'invisible';
7464
        if ($setting[$tool_id] == 'true') {
7465
            $visibility = 'visible';
7466
        }
7467
7468
        // Read the portal and course default visibility
7469
        if ($tool_id === 'documents') {
7470
            $visibility = DocumentManager::getDocumentDefaultVisibility($courseInfo);
7471
        }
7472
7473
        api_item_property_update(
7474
            $courseInfo,
7475
            $original_tool_id,
7476
            $item_id,
7477
            $visibility,
7478
            $userId,
7479
            $groupInfo,
7480
            null,
7481
            null,
7482
            null,
7483
            $sessionId
7484
        );
7485
7486
        // Fixes default visibility for tests
7487
        switch ($original_tool_id) {
7488
            case TOOL_QUIZ:
7489
                if (empty($sessionId)) {
7490
                    $objExerciseTmp = new Exercise($courseId);
7491
                    $objExerciseTmp->read($item_id);
7492
                    if ($visibility == 'visible') {
7493
                        $objExerciseTmp->enable();
7494
                        $objExerciseTmp->save();
7495
                    } else {
7496
                        $objExerciseTmp->disable();
7497
                        $objExerciseTmp->save();
7498
                    }
7499
                }
7500
                break;
7501
        }
7502
    }
7503
}
7504
7505
/**
7506
 * @return string
7507
 */
7508
function api_get_security_key()
7509
{
7510
    return api_get_configuration_value('security_key');
0 ignored issues
show
Bug Best Practice introduced by
The expression return api_get_configura...n_value('security_key') also could return the type boolean which is incompatible with the documented return type string.
Loading history...
7511
}
7512
7513
/**
7514
 * @param int $user_id
7515
 * @param int $courseId
7516
 * @param int $session_id
7517
 *
7518
 * @return array
7519
 */
7520
function api_detect_user_roles($user_id, $courseId, $session_id = 0)
7521
{
7522
    $user_roles = [];
7523
    $courseInfo = api_get_course_info_by_id($courseId);
7524
    $course_code = $courseInfo['code'];
7525
7526
    $url_id = api_get_current_access_url_id();
7527
    if (api_is_platform_admin_by_id($user_id, $url_id)) {
7528
        $user_roles[] = PLATFORM_ADMIN;
7529
    }
7530
7531
    /*if (api_is_drh()) {
7532
        $user_roles[] = DRH;
7533
    }*/
7534
7535
    if (!empty($session_id)) {
7536
        if (SessionManager::user_is_general_coach($user_id, $session_id)) {
7537
            $user_roles[] = SESSION_GENERAL_COACH;
7538
        }
7539
    }
7540
7541
    if (!empty($course_code)) {
7542
        if (empty($session_id)) {
7543
            if (CourseManager::is_course_teacher($user_id, $course_code)) {
7544
                $user_roles[] = COURSEMANAGER;
7545
            }
7546
            if (CourseManager::get_tutor_in_course_status($user_id, $courseInfo['real_id'])) {
7547
                $user_roles[] = COURSE_TUTOR;
7548
            }
7549
7550
            if (CourseManager::is_user_subscribed_in_course($user_id, $course_code)) {
7551
                $user_roles[] = COURSE_STUDENT;
7552
            }
7553
        } else {
7554
            $user_status_in_session = SessionManager::get_user_status_in_course_session(
7555
                $user_id,
7556
                $courseId,
7557
                $session_id
7558
            );
7559
7560
            if (!empty($user_status_in_session)) {
7561
                if ($user_status_in_session == 0) {
7562
                    $user_roles[] = SESSION_STUDENT;
7563
                }
7564
                if ($user_status_in_session == 2) {
7565
                    $user_roles[] = SESSION_COURSE_COACH;
7566
                }
7567
            }
7568
7569
            /*if (api_is_course_session_coach($user_id, $course_code, $session_id)) {
7570
               $user_roles[] = SESSION_COURSE_COACH;
7571
            }*/
7572
        }
7573
    }
7574
7575
    return $user_roles;
7576
}
7577
7578
/**
7579
 * @param int $courseId
7580
 * @param int $session_id
7581
 *
7582
 * @return bool
7583
 */
7584
function api_coach_can_edit_view_results($courseId = null, $session_id = null)
7585
{
7586
    if (api_is_platform_admin()) {
7587
        return true;
7588
    }
7589
7590
    $user_id = api_get_user_id();
7591
7592
    if (empty($courseId)) {
7593
        $courseId = api_get_course_int_id();
7594
    }
7595
7596
    if (empty($session_id)) {
7597
        $session_id = api_get_session_id();
7598
    }
7599
7600
    $roles = api_detect_user_roles($user_id, $courseId, $session_id);
7601
7602
    if (in_array(SESSION_COURSE_COACH, $roles)) {
7603
        //return api_get_setting('session_tutor_reports_visibility') == 'true';
7604
        return true;
7605
    } else {
7606
        if (in_array(COURSEMANAGER, $roles)) {
7607
            return true;
7608
        }
7609
7610
        return false;
7611
    }
7612
}
7613
7614
/**
7615
 * @param string $file
7616
 *
7617
 * @return string
7618
 */
7619
function api_get_js_simple($file)
7620
{
7621
    return '<script type="text/javascript" src="'.$file.'"></script>'."\n";
7622
}
7623
7624
function api_set_settings_and_plugins()
7625
{
7626
    global $_configuration;
7627
    $_setting = [];
7628
    $_plugins = [];
7629
7630
    // access_url == 1 is the default chamilo location
7631
    $settings_by_access_list = [];
7632
    $access_url_id = api_get_current_access_url_id();
7633
    if ($access_url_id != 1) {
7634
        $url_info = api_get_access_url($_configuration['access_url']);
7635
        if ($url_info['active'] == 1) {
7636
            $settings_by_access = &api_get_settings(null, 'list', $_configuration['access_url'], 1);
7637
            foreach ($settings_by_access as &$row) {
7638
                if (empty($row['variable'])) {
7639
                    $row['variable'] = 0;
7640
                }
7641
                if (empty($row['subkey'])) {
7642
                    $row['subkey'] = 0;
7643
                }
7644
                if (empty($row['category'])) {
7645
                    $row['category'] = 0;
7646
                }
7647
                $settings_by_access_list[$row['variable']][$row['subkey']][$row['category']] = $row;
7648
            }
7649
        }
7650
    }
7651
7652
    $result = api_get_settings(null, 'list', 1);
7653
7654
    foreach ($result as &$row) {
7655
        if ($access_url_id != 1) {
7656
            if ($url_info['active'] == 1) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $url_info does not seem to be defined for all execution paths leading up to this point.
Loading history...
7657
                $var = empty($row['variable']) ? 0 : $row['variable'];
7658
                $subkey = empty($row['subkey']) ? 0 : $row['subkey'];
7659
                $category = empty($row['category']) ? 0 : $row['category'];
7660
            }
7661
7662
            if ($row['access_url_changeable'] == 1 && $url_info['active'] == 1) {
7663
                if (isset($settings_by_access_list[$var]) &&
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $var does not seem to be defined for all execution paths leading up to this point.
Loading history...
7664
                    $settings_by_access_list[$var][$subkey][$category]['selected_value'] != '') {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $subkey does not seem to be defined for all execution paths leading up to this point.
Loading history...
Comprehensibility Best Practice introduced by
The variable $category does not seem to be defined for all execution paths leading up to this point.
Loading history...
7665
                    if ($row['subkey'] == null) {
7666
                        $_setting[$row['variable']] = $settings_by_access_list[$var][$subkey][$category]['selected_value'];
7667
                    } else {
7668
                        $_setting[$row['variable']][$row['subkey']] = $settings_by_access_list[$var][$subkey][$category]['selected_value'];
7669
                    }
7670
                } else {
7671
                    if ($row['subkey'] == null) {
7672
                        $_setting[$row['variable']] = $row['selected_value'];
7673
                    } else {
7674
                        $_setting[$row['variable']][$row['subkey']] = $row['selected_value'];
7675
                    }
7676
                }
7677
            } else {
7678
                if ($row['subkey'] == null) {
7679
                    $_setting[$row['variable']] = $row['selected_value'];
7680
                } else {
7681
                    $_setting[$row['variable']][$row['subkey']] = $row['selected_value'];
7682
                }
7683
            }
7684
        } else {
7685
            if ($row['subkey'] == null) {
7686
                $_setting[$row['variable']] = $row['selected_value'];
7687
            } else {
7688
                $_setting[$row['variable']][$row['subkey']] = $row['selected_value'];
7689
            }
7690
        }
7691
    }
7692
7693
    $result = api_get_settings('Plugins', 'list', $access_url_id);
7694
    $_plugins = [];
7695
    foreach ($result as &$row) {
7696
        $key = &$row['variable'];
7697
        if (is_string($_setting[$key])) {
7698
            $_setting[$key] = [];
7699
        }
7700
        $_setting[$key][] = $row['selected_value'];
7701
        $_plugins[$key][] = $row['selected_value'];
7702
    }
7703
7704
    $_SESSION['_setting'] = $_setting;
7705
    $_SESSION['_plugins'] = $_plugins;
7706
}
7707
7708
/**
7709
 * Modify default memory_limit and max_execution_time limits
7710
 * Needed when processing long tasks.
7711
 */
7712
function api_set_more_memory_and_time_limits()
7713
{
7714
    if (function_exists('ini_set')) {
7715
        api_set_memory_limit('256M');
7716
        ini_set('max_execution_time', 1800);
7717
    }
7718
}
7719
7720
/**
7721
 * Tries to set memory limit, if authorized and new limit is higher than current.
7722
 *
7723
 * @param string $mem New memory limit
7724
 *
7725
 * @return bool True on success, false on failure or current is higher than suggested
7726
 * @assert (null) === false
7727
 * @assert (-1) === false
7728
 * @assert (0) === true
7729
 * @assert ('1G') === true
7730
 */
7731
function api_set_memory_limit($mem)
7732
{
7733
    //if ini_set() not available, this function is useless
7734
    if (!function_exists('ini_set') || is_null($mem) || $mem == -1) {
7735
        return false;
7736
    }
7737
7738
    $memory_limit = ini_get('memory_limit');
7739
    if (api_get_bytes_memory_limit($mem) > api_get_bytes_memory_limit($memory_limit)) {
7740
        ini_set('memory_limit', $mem);
7741
7742
        return true;
7743
    }
7744
7745
    return false;
7746
}
7747
7748
/**
7749
 * Gets memory limit in bytes.
7750
 *
7751
 * @param string The memory size (128M, 1G, 1000K, etc)
7752
 *
7753
 * @return int
7754
 * @assert (null) === false
7755
 * @assert ('1t')  === 1099511627776
7756
 * @assert ('1g')  === 1073741824
7757
 * @assert ('1m')  === 1048576
7758
 * @assert ('100k') === 102400
7759
 */
7760
function api_get_bytes_memory_limit($mem)
7761
{
7762
    $size = strtolower(substr($mem, -1));
7763
7764
    switch ($size) {
7765
        case 't':
7766
            $mem = intval(substr($mem, -1)) * 1024 * 1024 * 1024 * 1024;
7767
            break;
7768
        case 'g':
7769
            $mem = intval(substr($mem, 0, -1)) * 1024 * 1024 * 1024;
7770
            break;
7771
        case 'm':
7772
            $mem = intval(substr($mem, 0, -1)) * 1024 * 1024;
7773
            break;
7774
        case 'k':
7775
            $mem = intval(substr($mem, 0, -1)) * 1024;
7776
            break;
7777
        default:
7778
            // we assume it's integer only
7779
            $mem = intval($mem);
7780
            break;
7781
    }
7782
7783
    return $mem;
7784
}
7785
7786
/**
7787
 * Finds all the information about a user from username instead of user id.
7788
 *
7789
 * @param string $officialCode
7790
 *
7791
 * @return array $user_info user_id, lastname, firstname, username, email, ...
7792
 *
7793
 * @author Yannick Warnier <[email protected]>
7794
 */
7795
function api_get_user_info_from_official_code($officialCode)
7796
{
7797
    if (empty($officialCode)) {
7798
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type array.
Loading history...
7799
    }
7800
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
7801
            WHERE official_code ='".Database::escape_string($officialCode)."'";
7802
    $result = Database::query($sql);
7803
    if (Database::num_rows($result) > 0) {
7804
        $result_array = Database::fetch_array($result);
7805
7806
        return _api_format_user($result_array);
7807
    }
7808
7809
    return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type array.
Loading history...
7810
}
7811
7812
/**
7813
 * @param string $usernameInputId
7814
 * @param string $passwordInputId
7815
 *
7816
 * @return string|null
7817
 */
7818
function api_get_password_checker_js($usernameInputId, $passwordInputId)
7819
{
7820
    $checkPass = api_get_setting('allow_strength_pass_checker');
7821
    $useStrengthPassChecker = $checkPass === 'true';
7822
7823
    if ($useStrengthPassChecker === false) {
7824
        return null;
7825
    }
7826
7827
    $translations = [
7828
        'wordLength' => get_lang('The password is too short'),
7829
        'wordNotEmail' => get_lang('Your password cannot be the same as your email'),
7830
        'wordSimilarToUsername' => get_lang('Your password cannot contain your username'),
7831
        'wordTwoCharacterClasses' => get_lang('Use different character classes'),
7832
        'wordRepetitions' => get_lang('Too many repetitions'),
7833
        'wordSequences' => get_lang('Your password contains sequences'),
7834
        'errorList' => get_lang('errors found'),
7835
        'veryWeak' => get_lang('Very weak'),
7836
        'weak' => get_lang('Weak'),
7837
        'normal' => get_lang('Normal'),
7838
        'medium' => get_lang('Medium'),
7839
        'strong' => get_lang('Strong'),
7840
        'veryStrong' => get_lang('Very strong'),
7841
    ];
7842
7843
    $js = api_get_asset('pwstrength-bootstrap/dist/pwstrength-bootstrap.min.js');
7844
    $js .= "<script>
7845
    var errorMessages = {
7846
        password_to_short : \"".get_lang('The password is too short')."\",
7847
        same_as_username : \"".get_lang('Your password cannot be the same as your username')."\"
7848
    };
7849
7850
    $(function() {
7851
        var lang = ".json_encode($translations).";
7852
        var options = {
7853
            onLoad : function () {
7854
                //$('#messages').text('Start typing password');
7855
            },
7856
            onKeyUp: function (evt) {
7857
                $(evt.target).pwstrength('outputErrorList');
7858
            },
7859
            errorMessages : errorMessages,
7860
            viewports: {
7861
                progress: '#password_progress',
7862
                verdict: '#password-verdict',
7863
                errors: '#password-errors'
7864
            },
7865
            usernameField: '$usernameInputId'
7866
        };
7867
        options.i18n = {
7868
            t: function (key) {
7869
                var result = lang[key];
7870
                return result === key ? '' : result; // This assumes you return the
7871
            }
7872
        };
7873
        $('".$passwordInputId."').pwstrength(options);
7874
    });
7875
    </script>";
7876
7877
    return $js;
7878
}
7879
7880
/**
7881
 * create an user extra field called 'captcha_blocked_until_date'.
7882
 *
7883
 * @param string $username
7884
 *
7885
 * @return bool
7886
 */
7887
function api_block_account_captcha($username)
7888
{
7889
    $userInfo = api_get_user_info_from_username($username);
7890
    if (empty($userInfo)) {
7891
        return false;
7892
    }
7893
    $minutesToBlock = api_get_setting('captcha_time_to_block');
7894
    $time = time() + $minutesToBlock * 60;
7895
    UserManager::update_extra_field_value(
7896
        $userInfo['user_id'],
7897
        'captcha_blocked_until_date',
7898
        api_get_utc_datetime($time)
7899
    );
7900
7901
    return true;
7902
}
7903
7904
/**
7905
 * @param string $username
7906
 *
7907
 * @return bool
7908
 */
7909
function api_clean_account_captcha($username)
7910
{
7911
    $userInfo = api_get_user_info_from_username($username);
7912
    if (empty($userInfo)) {
7913
        return false;
7914
    }
7915
    Session::erase('loginFailedCount');
7916
    UserManager::update_extra_field_value(
7917
        $userInfo['user_id'],
7918
        'captcha_blocked_until_date',
7919
        null
7920
    );
7921
7922
    return true;
7923
}
7924
7925
/**
7926
 * @param string $username
7927
 *
7928
 * @return bool
7929
 */
7930
function api_get_user_blocked_by_captcha($username)
7931
{
7932
    $userInfo = api_get_user_info_from_username($username);
7933
    if (empty($userInfo)) {
7934
        return false;
7935
    }
7936
    $data = UserManager::get_extra_user_data_by_field(
7937
        $userInfo['user_id'],
7938
        'captcha_blocked_until_date'
7939
    );
7940
    if (isset($data) && isset($data['captcha_blocked_until_date'])) {
7941
        return $data['captcha_blocked_until_date'];
7942
    }
7943
7944
    return false;
7945
}
7946
7947
/**
7948
 * Remove tags from HTML anf return the $in_number_char first non-HTML char
7949
 * Postfix the text with "..." if it has been truncated.
7950
 *
7951
 * @param string $text
7952
 * @param int    $number
7953
 *
7954
 * @return string
7955
 *
7956
 * @author hubert borderiou
7957
 */
7958
function api_get_short_text_from_html($text, $number)
7959
{
7960
    // Delete script and style tags
7961
    $text = preg_replace('/(<(script|style)\b[^>]*>).*?(<\/\2>)/is', "$1$3", $text);
7962
    $text = api_html_entity_decode($text);
7963
    $out_res = api_remove_tags_with_space($text, false);
7964
    $postfix = "...";
7965
    if (strlen($out_res) > $number) {
7966
        $out_res = substr($out_res, 0, $number).$postfix;
7967
    }
7968
7969
    return $out_res;
7970
}
7971
7972
/**
7973
 * Replace tags with a space in a text.
7974
 * If $in_double_quote_replace, replace " with '' (for HTML attribute purpose, for exemple).
7975
 *
7976
 * @return string
7977
 *
7978
 * @author hubert borderiou
7979
 */
7980
function api_remove_tags_with_space($in_html, $in_double_quote_replace = true)
7981
{
7982
    $out_res = $in_html;
7983
    if ($in_double_quote_replace) {
7984
        $out_res = str_replace('"', "''", $out_res);
7985
    }
7986
    // avoid text stuck together when tags are removed, adding a space after >
7987
    $out_res = str_replace(">", "> ", $out_res);
7988
    $out_res = strip_tags($out_res);
7989
7990
    return $out_res;
7991
}
7992
7993
/**
7994
 * If true, the drh can access all content (courses, users) inside a session.
7995
 *
7996
 * @return bool
7997
 */
7998
function api_drh_can_access_all_session_content()
7999
{
8000
    $value = api_get_setting('drh_can_access_all_session_content');
8001
8002
    return $value === 'true';
8003
}
8004
8005
/**
8006
 * @param string $tool
8007
 * @param string $setting
8008
 * @param int    $defaultValue
8009
 *
8010
 * @return string
8011
 */
8012
function api_get_default_tool_setting($tool, $setting, $defaultValue)
8013
{
8014
    global $_configuration;
8015
    if (isset($_configuration[$tool]) &&
8016
        isset($_configuration[$tool]['default_settings']) &&
8017
        isset($_configuration[$tool]['default_settings'][$setting])
8018
    ) {
8019
        return $_configuration[$tool]['default_settings'][$setting];
8020
    }
8021
8022
    return $defaultValue;
8023
}
8024
8025
/**
8026
 * Checks if user can login as another user.
8027
 *
8028
 * @param int $loginAsUserId the user id to log in
8029
 * @param int $userId        my user id
8030
 *
8031
 * @return bool
8032
 */
8033
function api_can_login_as($loginAsUserId, $userId = null)
8034
{
8035
    if (empty($userId)) {
8036
        $userId = api_get_user_id();
8037
    }
8038
    if ($loginAsUserId == $userId) {
8039
        return false;
8040
    }
8041
8042
    if (empty($loginAsUserId)) {
8043
        return false;
8044
    }
8045
8046
    if ($loginAsUserId != strval(intval($loginAsUserId))) {
8047
        return false;
8048
    }
8049
8050
    // Check if the user to login is an admin
8051
    if (api_is_platform_admin_by_id($loginAsUserId)) {
8052
        // Only super admins can login to admin accounts
8053
        if (!api_global_admin_can_edit_admin($loginAsUserId)) {
8054
            return false;
8055
        }
8056
    }
8057
8058
    $userInfo = api_get_user_info($loginAsUserId);
8059
    $isDrh = function () use ($loginAsUserId) {
8060
        if (api_is_drh()) {
8061
            if (api_drh_can_access_all_session_content()) {
8062
                $users = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus(
8063
                    'drh_all',
8064
                    api_get_user_id()
8065
                );
8066
                $userList = [];
8067
                if (is_array($users)) {
8068
                    foreach ($users as $user) {
8069
                        $userList[] = $user['user_id'];
8070
                    }
8071
                }
8072
                if (in_array($loginAsUserId, $userList)) {
8073
                    return true;
8074
                }
8075
            } else {
8076
                if (api_is_drh() &&
8077
                    UserManager::is_user_followed_by_drh($loginAsUserId, api_get_user_id())
8078
                ) {
8079
                    return true;
8080
                }
8081
            }
8082
        }
8083
8084
        return false;
8085
    };
8086
8087
    $loginAsStatusForSessionAdmins = [STUDENT];
8088
8089
    if (api_get_setting('session.allow_session_admin_login_as_teacher')) {
8090
        $loginAsStatusForSessionAdmins[] = COURSEMANAGER;
8091
    }
8092
8093
    return api_is_platform_admin() ||
8094
        (api_is_session_admin() && in_array($userInfo['status'], $loginAsStatusForSessionAdmins)) ||
8095
        $isDrh();
8096
}
8097
8098
/**
8099
 * @return bool
8100
 */
8101
function api_is_allowed_in_course()
8102
{
8103
    if (api_is_platform_admin()) {
8104
        return true;
8105
    }
8106
8107
    $user = api_get_current_user();
8108
    if ($user instanceof User) {
8109
        if ($user->hasRole('ROLE_CURRENT_SESSION_COURSE_STUDENT') ||
8110
            $user->hasRole('ROLE_CURRENT_SESSION_COURSE_TEACHER') ||
8111
            $user->hasRole('ROLE_CURRENT_COURSE_STUDENT') ||
8112
            $user->hasRole('ROLE_CURRENT_COURSE_TEACHER')
8113
        ) {
8114
            return true;
8115
        }
8116
    }
8117
8118
    return false;
8119
}
8120
8121
/**
8122
 * Set the cookie to go directly to the course code $in_firstpage
8123
 * after login.
8124
 *
8125
 * @param string $value is the course code of the course to go
8126
 */
8127
function api_set_firstpage_parameter($value)
8128
{
8129
    setcookie('GotoCourse', $value);
8130
}
8131
8132
/**
8133
 * Delete the cookie to go directly to the course code $in_firstpage
8134
 * after login.
8135
 */
8136
function api_delete_firstpage_parameter()
8137
{
8138
    setcookie('GotoCourse', '', time() - 3600);
8139
}
8140
8141
/**
8142
 * @return bool if course_code for direct course access after login is set
8143
 */
8144
function exist_firstpage_parameter()
8145
{
8146
    return isset($_COOKIE['GotoCourse']) && $_COOKIE['GotoCourse'] != '';
8147
}
8148
8149
/**
8150
 * @return return the course_code of the course where user login
8151
 */
8152
function api_get_firstpage_parameter()
8153
{
8154
    return $_COOKIE['GotoCourse'];
8155
}
8156
8157
/**
8158
 * Return true on https install.
8159
 *
8160
 * @return bool
8161
 */
8162
function api_is_https()
8163
{
8164
    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...
8165
        $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https' || !empty($_configuration['force_https_forwarded_proto'])
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $_configuration seems to never exist and therefore empty should always be true.
Loading history...
8166
    ) {
8167
        $isSecured = true;
8168
    } else {
8169
        if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') {
8170
            $isSecured = true;
8171
        } else {
8172
            $isSecured = false;
8173
            // last chance
8174
            if (!empty($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443) {
8175
                $isSecured = true;
8176
            }
8177
        }
8178
    }
8179
8180
    return $isSecured;
8181
}
8182
8183
/**
8184
 * Return protocol (http or https).
8185
 *
8186
 * @return string
8187
 */
8188
function api_get_protocol()
8189
{
8190
    return api_is_https() ? 'https' : 'http';
8191
}
8192
8193
/**
8194
 * Return a string where " are replaced with 2 '
8195
 * It is useful when you pass a PHP variable in a Javascript browser dialog
8196
 * e.g. : alert("<?php get_lang('Message') ?>");
8197
 * and message contains character ".
8198
 *
8199
 * @param string $in_text
8200
 *
8201
 * @return string
8202
 */
8203
function convert_double_quote_to_single($in_text)
8204
{
8205
    return api_preg_replace('/"/', "''", $in_text);
8206
}
8207
8208
/**
8209
 * Get origin.
8210
 *
8211
 * @param string
8212
 *
8213
 * @return string
8214
 */
8215
function api_get_origin()
8216
{
8217
    $origin = isset($_REQUEST['origin']) ? Security::remove_XSS($_REQUEST['origin']) : '';
8218
8219
    return $origin;
8220
}
8221
8222
/**
8223
 * Warns an user that the portal reach certain limit.
8224
 *
8225
 * @param string $limitName
8226
 */
8227
function api_warn_hosting_contact($limitName)
8228
{
8229
    $hostingParams = api_get_configuration_value(1);
8230
    $email = null;
8231
8232
    if (!empty($hostingParams)) {
8233
        if (isset($hostingParams['hosting_contact_mail'])) {
8234
            $email = $hostingParams['hosting_contact_mail'];
8235
        }
8236
    }
8237
8238
    if (!empty($email)) {
8239
        $subject = get_lang('Hosting warning reached');
8240
        $body = get_lang('Portal name').': '.api_get_path(WEB_PATH)." \n ";
8241
        $body .= get_lang('Portal\'s limit type').': '.$limitName." \n ";
8242
        if (isset($hostingParams[$limitName])) {
8243
            $body .= get_lang('Value').': '.$hostingParams[$limitName];
8244
        }
8245
        api_mail_html(null, $email, $subject, $body);
8246
    }
8247
}
8248
8249
/**
8250
 * Gets value of a variable from config/configuration.php
8251
 * Variables that are not set in the configuration.php file but set elsewhere:
8252
 * - virtual_css_theme_folder (vchamilo plugin)
8253
 * - access_url (global.inc.php)
8254
 * - apc/apc_prefix (global.inc.php).
8255
 *
8256
 * @param string $variable
8257
 *
8258
 * @return bool|mixed
8259
 */
8260
function api_get_configuration_value($variable)
8261
{
8262
    global $_configuration;
8263
    // Check the current url id, id = 1 by default
8264
    $urlId = isset($_configuration['access_url']) ? (int) $_configuration['access_url'] : 1;
8265
8266
    $variable = trim($variable);
8267
8268
    // Check if variable exists
8269
    if (isset($_configuration[$variable])) {
8270
        if (is_array($_configuration[$variable])) {
8271
            // Check if it exists for the sub portal
8272
            if (array_key_exists($urlId, $_configuration[$variable])) {
8273
                return $_configuration[$variable][$urlId];
8274
            } else {
8275
                // Try to found element with id = 1 (master portal)
8276
                if (array_key_exists(1, $_configuration[$variable])) {
8277
                    return $_configuration[$variable][1];
8278
                }
8279
            }
8280
        }
8281
8282
        return $_configuration[$variable];
8283
    }
8284
8285
    return false;
8286
}
8287
8288
/**
8289
 * Returns supported image extensions in the portal.
8290
 *
8291
 * @param bool $supportVectors Whether vector images should also be accepted or not
8292
 *
8293
 * @return array Supported image extensions in the portal
8294
 */
8295
function api_get_supported_image_extensions($supportVectors = true)
8296
{
8297
    // jpg can also be called jpeg, jpe, jfif and jif. See https://en.wikipedia.org/wiki/JPEG#JPEG_filename_extensions
8298
    $supportedImageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'jpe', 'jfif', 'jif'];
8299
    if ($supportVectors) {
8300
        array_push($supportedImageExtensions, 'svg');
8301
    }
8302
    if (version_compare(PHP_VERSION, '5.5.0', '>=')) {
8303
        array_push($supportedImageExtensions, 'webp');
8304
    }
8305
8306
    return $supportedImageExtensions;
8307
}
8308
8309
/**
8310
 * This setting changes the registration status for the campus.
8311
 *
8312
 * @author Patrick Cool <[email protected]>, Ghent University
8313
 *
8314
 * @version August 2006
8315
 *
8316
 * @param bool $listCampus Whether we authorize
8317
 *
8318
 * @todo the $_settings should be reloaded here. => write api function for this and use this in global.inc.php also.
8319
 */
8320
function api_register_campus($listCampus = true)
8321
{
8322
    $tbl_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
8323
8324
    $sql = "UPDATE $tbl_settings SET selected_value='true' WHERE variable='registered'";
8325
    Database::query($sql);
8326
8327
    if (!$listCampus) {
8328
        $sql = "UPDATE $tbl_settings SET selected_value='true' WHERE variable='donotlistcampus'";
8329
        Database::query($sql);
8330
    }
8331
}
8332
8333
/**
8334
 * Checks whether current user is a student boss.
8335
 *
8336
 * @global array $_user
8337
 *
8338
 * @return bool
8339
 */
8340
function api_is_student_boss()
8341
{
8342
    $_user = api_get_user_info();
8343
8344
    return isset($_user['status']) && $_user['status'] == STUDENT_BOSS;
8345
}
8346
8347
/**
8348
 * Check whether the user type should be exclude.
8349
 * Such as invited or anonymous users.
8350
 *
8351
 * @param bool $checkDB Optional. Whether check the user status
8352
 * @param int  $userId  Options. The user id
8353
 *
8354
 * @return bool
8355
 */
8356
function api_is_excluded_user_type($checkDB = false, $userId = 0)
8357
{
8358
    if ($checkDB) {
8359
        $userId = empty($userId) ? api_get_user_id() : (int) $userId;
8360
8361
        if ($userId == 0) {
8362
            return true;
8363
        }
8364
8365
        $userInfo = api_get_user_info($userId);
8366
8367
        switch ($userInfo['status']) {
8368
            case INVITEE:
8369
            case ANONYMOUS:
8370
                return true;
8371
            default:
8372
                return false;
8373
        }
8374
    }
8375
8376
    $isInvited = api_is_invitee();
8377
    $isAnonymous = api_is_anonymous();
8378
8379
    if ($isInvited || $isAnonymous) {
8380
        return true;
8381
    }
8382
8383
    return false;
8384
}
8385
8386
/**
8387
 * Get the user status to ignore in reports.
8388
 *
8389
 * @param string $format Optional. The result type (array or string)
8390
 *
8391
 * @return array|string
8392
 */
8393
function api_get_users_status_ignored_in_reports($format = 'array')
8394
{
8395
    $excludedTypes = [
8396
        INVITEE,
8397
        ANONYMOUS,
8398
    ];
8399
8400
    if ($format == 'string') {
8401
        return implode(', ', $excludedTypes);
8402
    }
8403
8404
    return $excludedTypes;
8405
}
8406
8407
/**
8408
 * Set the Site Use Cookie Warning for 1 year.
8409
 */
8410
function api_set_site_use_cookie_warning_cookie()
8411
{
8412
    setcookie('ChamiloUsesCookies', 'ok', time() + 31556926);
8413
}
8414
8415
/**
8416
 * Return true if the Site Use Cookie Warning Cookie warning exists.
8417
 *
8418
 * @return bool
8419
 */
8420
function api_site_use_cookie_warning_cookie_exist()
8421
{
8422
    return isset($_COOKIE['ChamiloUsesCookies']);
8423
}
8424
8425
/**
8426
 * Given a number of seconds, format the time to show hours, minutes and seconds.
8427
 *
8428
 * @param int    $time         The time in seconds
8429
 * @param string $originFormat Optional. PHP o JS
8430
 *
8431
 * @return string (00h00'00")
8432
 */
8433
function api_format_time($time, $originFormat = 'php')
8434
{
8435
    $h = get_lang('h');
8436
    $hours = $time / 3600;
8437
    $mins = ($time % 3600) / 60;
8438
    $secs = ($time % 60);
8439
8440
    if ($time < 0) {
8441
        $hours = 0;
8442
        $mins = 0;
8443
        $secs = 0;
8444
    }
8445
8446
    if ($originFormat == 'js') {
8447
        $formattedTime = trim(sprintf("%02d : %02d : %02d", $hours, $mins, $secs));
8448
    } else {
8449
        $formattedTime = trim(sprintf("%02d$h%02d'%02d\"", $hours, $mins, $secs));
8450
    }
8451
8452
    return $formattedTime;
8453
}
8454
8455
/**
8456
 * Create a new empty directory with index.html file.
8457
 *
8458
 * @param string $name            The new directory name
8459
 * @param string $parentDirectory Directory parent directory name
8460
 *
8461
 * @deprecated use Resources
8462
 *
8463
 * @return bool Return true if the directory was create. Otherwise return false
8464
 */
8465
function api_create_protected_dir($name, $parentDirectory)
8466
{
8467
    $isCreated = false;
8468
8469
    if (!is_writable($parentDirectory)) {
8470
        return false;
8471
    }
8472
8473
    $fullPath = $parentDirectory.api_replace_dangerous_char($name);
8474
8475
    if (mkdir($fullPath, api_get_permissions_for_new_directories(), true)) {
8476
        $fp = fopen($fullPath.'/index.html', 'w');
8477
8478
        if ($fp) {
0 ignored issues
show
introduced by
$fp is of type false|resource, thus it always evaluated to false.
Loading history...
8479
            if (fwrite($fp, '<html><head></head><body></body></html>')) {
8480
                $isCreated = true;
8481
            }
8482
        }
8483
8484
        fclose($fp);
0 ignored issues
show
Bug introduced by
It seems like $fp can also be of type false; however, parameter $handle of fclose() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

8484
        fclose(/** @scrutinizer ignore-type */ $fp);
Loading history...
8485
    }
8486
8487
    return $isCreated;
8488
}
8489
8490
/**
8491
 * Sends an email
8492
 * Sender name and email can be specified, if not specified
8493
 * name and email of the platform admin are used.
8494
 *
8495
 * @param string    name of recipient
8496
 * @param string    email of recipient
8497
 * @param string    email subject
8498
 * @param string    email body
8499
 * @param string    sender name
8500
 * @param string    sender e-mail
8501
 * @param array     extra headers in form $headers = array($name => $value) to allow parsing
8502
 * @param array     data file (path and filename)
8503
 * @param bool      True for attaching a embedded file inside content html (optional)
8504
 * @param array     Additional parameters
8505
 *
8506
 * @return bool true if mail was sent
8507
 */
8508
function api_mail_html(
8509
    $recipientName,
8510
    $recipientEmail,
8511
    $subject,
8512
    $body,
8513
    $senderName = '',
8514
    $senderEmail = '',
8515
    $extra_headers = [],
8516
    $data_file = [],
8517
    $embeddedImage = false,
0 ignored issues
show
Unused Code introduced by
The parameter $embeddedImage is not used and could be removed. ( Ignorable by Annotation )

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

8517
    /** @scrutinizer ignore-unused */ $embeddedImage = false,

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
8518
    $additionalParameters = []
8519
) {
8520
    if (!api_valid_email($recipientEmail)) {
8521
        return false;
8522
    }
8523
8524
    // Default values
8525
    $notification = new Notification();
8526
    $defaultEmail = $notification->getDefaultPlatformSenderEmail();
8527
    $defaultName = $notification->getDefaultPlatformSenderName();
8528
8529
    // If the parameter is set don't use the admin.
8530
    $senderName = !empty($senderName) ? $senderName : $defaultName;
8531
    $senderEmail = !empty($senderEmail) ? $senderEmail : $defaultEmail;
8532
8533
    // Reply to first
8534
    $replyToName = '';
8535
    $replyToEmail = '';
8536
    if (isset($extra_headers['reply_to'])) {
8537
        $replyToEmail = $extra_headers['reply_to']['mail'];
8538
        $replyToName = $extra_headers['reply_to']['name'];
8539
    }
8540
8541
    try {
8542
        $message = new TemplatedEmail();
8543
        $message->subject($subject);
8544
8545
        $list = api_get_configuration_value('send_all_emails_to');
8546
        if (!empty($list) && isset($list['emails'])) {
8547
            foreach ($list['emails'] as $email) {
8548
                $message->cc($email);
8549
            }
8550
        }
8551
8552
        // Attachment
8553
        if (!empty($data_file)) {
8554
            foreach ($data_file as $file_attach) {
8555
                if (!empty($file_attach['path']) && !empty($file_attach['filename'])) {
8556
                    $message->attachFromPath($file_attach['path'], $file_attach['filename']);
8557
                }
8558
            }
8559
        }
8560
8561
        $noReply = api_get_setting('noreply_email_address');
8562
        $automaticEmailText = '';
8563
        if (!empty($noReply)) {
8564
            $automaticEmailText = '<br />'.get_lang('This is an automatic email message. Please do not reply to it.');
8565
        }
8566
8567
        $params = [
8568
            'mail_header_style' => api_get_configuration_value('mail_header_style'),
8569
            'mail_content_style' => api_get_configuration_value('mail_content_style'),
8570
            'link' => $additionalParameters['link'] ?? '',
8571
            'automatic_email_text' => $automaticEmailText,
8572
            'content' => $body,
8573
            'theme' => api_get_visual_theme(),
8574
        ];
8575
8576
        if (!empty($senderEmail)) {
8577
            $message->from(new Address($senderEmail, $senderName));
8578
        }
8579
8580
        if (!empty($recipientEmail)) {
8581
            $message->to(new Address($recipientEmail, $recipientName));
8582
        }
8583
8584
        if (!empty($replyToEmail)) {
8585
            $message->replyTo(new Address($replyToEmail, $replyToName));
8586
        }
8587
8588
        $message
8589
            ->htmlTemplate('ChamiloThemeBundle:Mailer:Default/default.html.twig')
8590
            ->textTemplate('ChamiloThemeBundle:Mailer:Default/default.text.twig')
8591
        ;
8592
        $message->context($params);
8593
        Container::getMailer()->send($message);
8594
8595
        return true;
8596
    } catch (Exception $e) {
8597
        error_log($e->getMessage());
8598
    }
8599
8600
    if (!empty($additionalParameters)) {
8601
        $plugin = new AppPlugin();
8602
        $smsPlugin = $plugin->getSMSPluginLibrary();
8603
        if ($smsPlugin) {
0 ignored issues
show
introduced by
$smsPlugin is of type SmsPluginLibraryInterface, thus it always evaluated to true.
Loading history...
8604
            $smsPlugin->send($additionalParameters);
8605
        }
8606
    }
8607
8608
    return 1;
0 ignored issues
show
Bug Best Practice introduced by
The expression return 1 returns the type integer which is incompatible with the documented return type boolean.
Loading history...
8609
}
8610
8611
/**
8612
 * @param string $tool       Possible values: GroupManager::GROUP_TOOL_*
8613
 * @param bool   $showHeader
8614
 */
8615
function api_protect_course_group($tool, $showHeader = true)
8616
{
8617
    $groupId = api_get_group_id();
8618
    if (!empty($groupId)) {
8619
        if (api_is_platform_admin()) {
8620
            return true;
8621
        }
8622
8623
        if (api_is_allowed_to_edit(false, true, true)) {
8624
            return true;
8625
        }
8626
8627
        $userId = api_get_user_id();
8628
        $sessionId = api_get_session_id();
8629
        if (!empty($sessionId)) {
8630
            if (api_is_coach($sessionId, api_get_course_int_id())) {
8631
                return true;
8632
            }
8633
8634
            if (api_is_drh()) {
8635
                if (SessionManager::isUserSubscribedAsHRM($sessionId, $userId)) {
8636
                    return true;
8637
                }
8638
            }
8639
        }
8640
8641
        $groupInfo = GroupManager::get_group_properties($groupId);
8642
8643
        // Group doesn't exists
8644
        if (empty($groupInfo)) {
8645
            api_not_allowed($showHeader);
8646
        }
8647
8648
        // Check group access
8649
        $allow = GroupManager::user_has_access(
8650
            $userId,
8651
            $groupInfo['iid'],
8652
            $tool
8653
        );
8654
8655
        if (!$allow) {
8656
            api_not_allowed($showHeader);
8657
        }
8658
    }
8659
}
8660
8661
/**
8662
 * Check if a date is in a date range.
8663
 *
8664
 * @param datetime $startDate
8665
 * @param datetime $endDate
8666
 * @param datetime $currentDate
8667
 *
8668
 * @return bool true if date is in rage, false otherwise
8669
 */
8670
function api_is_date_in_date_range($startDate, $endDate, $currentDate = null)
8671
{
8672
    $startDate = strtotime(api_get_local_time($startDate));
8673
    $endDate = strtotime(api_get_local_time($endDate));
8674
    $currentDate = strtotime(api_get_local_time($currentDate));
8675
8676
    if ($currentDate >= $startDate && $currentDate <= $endDate) {
8677
        return true;
8678
    }
8679
8680
    return false;
8681
}
8682
8683
/**
8684
 * Eliminate the duplicates of a multidimensional array by sending the key.
8685
 *
8686
 * @param array $array multidimensional array
8687
 * @param int   $key   key to find to compare
8688
 *
8689
 * @return array
8690
 */
8691
function api_unique_multidim_array($array, $key)
8692
{
8693
    $temp_array = [];
8694
    $i = 0;
8695
    $key_array = [];
8696
8697
    foreach ($array as $val) {
8698
        if (!in_array($val[$key], $key_array)) {
8699
            $key_array[$i] = $val[$key];
8700
            $temp_array[$i] = $val;
8701
        }
8702
        $i++;
8703
    }
8704
8705
    return $temp_array;
8706
}
8707
8708
/**
8709
 * Limit the access to Session Admins when the limit_session_admin_role
8710
 * configuration variable is set to true.
8711
 */
8712
function api_protect_limit_for_session_admin()
8713
{
8714
    $limitAdmin = api_get_setting('limit_session_admin_role');
8715
    if (api_is_session_admin() && $limitAdmin === 'true') {
8716
        api_not_allowed(true);
8717
    }
8718
}
8719
8720
/**
8721
 * Limits that a session admin has access to list users.
8722
 * When limit_session_admin_list_users configuration variable is set to true.
8723
 */
8724
function api_protect_session_admin_list_users()
8725
{
8726
    $limitAdmin = api_get_configuration_value('limit_session_admin_list_users');
8727
8728
    if (api_is_session_admin() && true === $limitAdmin) {
8729
        api_not_allowed(true);
8730
    }
8731
}
8732
8733
/**
8734
 * @return bool
8735
 */
8736
function api_is_student_view_active()
8737
{
8738
    $studentView = Session::read('studentview');
8739
8740
    return $studentView === 'studentview';
8741
}
8742
8743
/**
8744
 * Adds a file inside the upload/$type/id.
8745
 *
8746
 * @param string $type
8747
 * @param array  $file
8748
 * @param int    $itemId
8749
 * @param string $cropParameters
8750
 *
8751
 * @deprecated use Resources
8752
 *
8753
 * @return array|bool
8754
 */
8755
function api_upload_file($type, $file, $itemId, $cropParameters = '')
8756
{
8757
    $upload = process_uploaded_file($file);
8758
    if ($upload) {
8759
        $name = api_replace_dangerous_char($file['name']);
8760
8761
        // No "dangerous" files
8762
        $name = disable_dangerous_file($name);
8763
8764
        $pathId = '/'.substr((string) $itemId, 0, 1).'/'.$itemId.'/';
8765
        $path = api_get_path(SYS_UPLOAD_PATH).$type.$pathId;
8766
8767
        if (!is_dir($path)) {
8768
            mkdir($path, api_get_permissions_for_new_directories(), true);
8769
        }
8770
8771
        $pathToSave = $path.$name;
8772
        $result = moveUploadedFile($file, $pathToSave);
8773
8774
        if ($result) {
8775
            if (!empty($cropParameters)) {
8776
                $image = new Image($pathToSave);
8777
                $image->crop($cropParameters);
8778
            }
8779
8780
            return ['path_to_save' => $pathId.$name];
8781
        }
8782
8783
        return false;
8784
    }
8785
}
8786
8787
/**
8788
 * @param string $type
8789
 * @param int    $itemId
8790
 * @param string $file
8791
 *
8792
 * @return bool
8793
 */
8794
function api_get_uploaded_web_url($type, $itemId, $file)
8795
{
8796
    return api_get_uploaded_file($type, $itemId, $file, true);
8797
}
8798
8799
/**
8800
 * @param string $type
8801
 * @param int    $itemId
8802
 * @param string $file
8803
 * @param bool   $getUrl
8804
 *
8805
 * @return bool
8806
 */
8807
function api_get_uploaded_file($type, $itemId, $file, $getUrl = false)
8808
{
8809
    $itemId = (int) $itemId;
8810
    $pathId = '/'.substr((string) $itemId, 0, 1).'/'.$itemId.'/';
8811
    $path = api_get_path(SYS_UPLOAD_PATH).$type.$pathId;
8812
    $file = basename($file);
8813
    $file = $path.'/'.$file;
8814
    if (Security::check_abs_path($file, $path) && is_file($file) && file_exists($file)) {
8815
        if ($getUrl) {
8816
            return str_replace(api_get_path(SYS_UPLOAD_PATH), api_get_path(WEB_UPLOAD_PATH), $file);
0 ignored issues
show
Bug Best Practice introduced by
The expression return str_replace(api_g...EB_UPLOAD_PATH), $file) returns the type string which is incompatible with the documented return type boolean.
Loading history...
8817
        }
8818
8819
        return $file;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $file returns the type string which is incompatible with the documented return type boolean.
Loading history...
8820
    }
8821
8822
    return false;
8823
}
8824
8825
/**
8826
 * @param string $type
8827
 * @param int    $itemId
8828
 * @param string $file
8829
 * @param string $title
8830
 */
8831
function api_download_uploaded_file($type, $itemId, $file, $title = '')
8832
{
8833
    $file = api_get_uploaded_file($type, $itemId, $file);
8834
    if ($file) {
8835
        if (Security::check_abs_path($file, api_get_path(SYS_UPLOAD_PATH).$type)) {
8836
            DocumentManager::file_send_for_download($file, true, $title);
8837
            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...
8838
        }
8839
    }
8840
    api_not_allowed(true);
8841
}
8842
8843
/**
8844
 * @param string $type
8845
 * @param string $file
8846
 */
8847
function api_remove_uploaded_file($type, $file)
8848
{
8849
    $typePath = api_get_path(SYS_UPLOAD_PATH).$type;
8850
    $path = $typePath.'/'.$file;
8851
    if (Security::check_abs_path($path, $typePath) && file_exists($path) && is_file($path)) {
8852
        unlink($path);
8853
    }
8854
}
8855
8856
/**
8857
 * @param string $type
8858
 * @param int    $itemId
8859
 * @param string $file
8860
 *
8861
 * @return bool
8862
 */
8863
function api_remove_uploaded_file_by_id($type, $itemId, $file)
8864
{
8865
    $file = api_get_uploaded_file($type, $itemId, $file, false);
8866
    $typePath = api_get_path(SYS_UPLOAD_PATH).$type;
8867
    if (Security::check_abs_path($file, $typePath) && file_exists($file) && is_file($file)) {
8868
        unlink($file);
8869
8870
        return true;
8871
    }
8872
8873
    return false;
8874
}
8875
8876
/**
8877
 * Converts string value to float value.
8878
 *
8879
 * 3.141516 => 3.141516
8880
 * 3,141516 => 3.141516
8881
 *
8882
 * @todo WIP
8883
 *
8884
 * @param string $number
8885
 *
8886
 * @return float
8887
 */
8888
function api_float_val($number)
8889
{
8890
    $number = (float) str_replace(',', '.', trim($number));
8891
8892
    return $number;
8893
}
8894
8895
/**
8896
 * Converts float values
8897
 * Example if $decimals = 2.
8898
 *
8899
 * 3.141516 => 3.14
8900
 * 3,141516 => 3,14
8901
 *
8902
 * @param string $number            number in iso code
8903
 * @param int    $decimals
8904
 * @param string $decimalSeparator
8905
 * @param string $thousandSeparator
8906
 *
8907
 * @return bool|string
8908
 */
8909
function api_number_format($number, $decimals = 0, $decimalSeparator = '.', $thousandSeparator = ',')
8910
{
8911
    $number = api_float_val($number);
8912
8913
    return number_format($number, $decimals, $decimalSeparator, $thousandSeparator);
8914
}
8915
8916
/**
8917
 * Set location url with a exit break by default.
8918
 *
8919
 * @param $url
8920
 * @param bool $exit
8921
 */
8922
function location($url, $exit = true)
8923
{
8924
    header('Location: '.$url);
8925
8926
    if ($exit) {
8927
        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...
8928
    }
8929
}
8930
8931
/**
8932
 * @return string
8933
 */
8934
function api_get_web_url()
8935
{
8936
    if (api_get_setting('server_type') === 'test') {
8937
        return api_get_path(WEB_PATH).'web/app_dev.php/';
8938
    } else {
8939
        return api_get_path(WEB_PATH).'web/';
8940
    }
8941
}
8942
8943
/**
8944
 * @param string $from
8945
 * @param string $to
8946
 *
8947
 * @return string
8948
 */
8949
function api_get_relative_path($from, $to)
8950
{
8951
    // some compatibility fixes for Windows paths
8952
    $from = is_dir($from) ? rtrim($from, '\/').'/' : $from;
8953
    $to = is_dir($to) ? rtrim($to, '\/').'/' : $to;
8954
    $from = str_replace('\\', '/', $from);
8955
    $to = str_replace('\\', '/', $to);
8956
8957
    $from = explode('/', $from);
8958
    $to = explode('/', $to);
8959
    $relPath = $to;
8960
8961
    foreach ($from as $depth => $dir) {
8962
        // find first non-matching dir
8963
        if ($dir === $to[$depth]) {
8964
            // ignore this directory
8965
            array_shift($relPath);
8966
        } else {
8967
            // get number of remaining dirs to $from
8968
            $remaining = count($from) - $depth;
8969
            if ($remaining > 1) {
8970
                // add traversals up to first matching dir
8971
                $padLength = (count($relPath) + $remaining - 1) * -1;
8972
                $relPath = array_pad($relPath, $padLength, '..');
8973
                break;
8974
            } else {
8975
                $relPath[0] = './'.$relPath[0];
8976
            }
8977
        }
8978
    }
8979
8980
    return implode('/', $relPath);
8981
}
8982
8983
/**
8984
 * Unserialize content using Brummann\Polyfill\Unserialize.
8985
 *
8986
 * @param string $type
8987
 * @param string $serialized
8988
 * @param bool   $ignoreErrors. Optional.
8989
 *
8990
 * @return mixed
8991
 */
8992
function api_unserialize_content($type, $serialized, $ignoreErrors = false)
8993
{
8994
    switch ($type) {
8995
        case 'career':
8996
        case 'sequence_graph':
8997
            $allowedClasses = [Graph::class, VerticesMap::class, Vertices::class, Edges::class];
8998
            break;
8999
        case 'lp':
9000
            $allowedClasses = [
9001
                learnpath::class,
9002
                learnpathItem::class,
9003
                aicc::class,
9004
                aiccBlock::class,
9005
                aiccItem::class,
9006
                aiccObjective::class,
9007
                aiccResource::class,
9008
                scorm::class,
9009
                scormItem::class,
9010
                scormMetadata::class,
9011
                scormOrganization::class,
9012
                scormResource::class,
9013
                Link::class,
9014
                LpItem::class,
9015
            ];
9016
            break;
9017
        case 'course':
9018
            $allowedClasses = [
9019
                Course::class,
9020
                Announcement::class,
9021
                Attendance::class,
9022
                CalendarEvent::class,
9023
                CourseCopyLearnpath::class,
9024
                CourseCopyTestCategory::class,
9025
                CourseDescription::class,
9026
                CourseSession::class,
9027
                Document::class,
9028
                Forum::class,
9029
                ForumCategory::class,
9030
                ForumPost::class,
9031
                ForumTopic::class,
9032
                Glossary::class,
9033
                GradeBookBackup::class,
9034
                Link::class,
9035
                LinkCategory::class,
9036
                Quiz::class,
9037
                QuizQuestion::class,
9038
                QuizQuestionOption::class,
9039
                ScormDocument::class,
9040
                Survey::class,
9041
                SurveyInvitation::class,
9042
                SurveyQuestion::class,
9043
                Thematic::class,
9044
                ToolIntro::class,
9045
                Wiki::class,
9046
                Work::class,
9047
                stdClass::class,
9048
            ];
9049
            break;
9050
        case 'not_allowed_classes':
9051
        default:
9052
            $allowedClasses = false;
9053
    }
9054
9055
    if ($ignoreErrors) {
9056
        return @Unserialize::unserialize(
9057
            $serialized,
9058
            ['allowed_classes' => $allowedClasses]
9059
        );
9060
    }
9061
9062
    return Unserialize::unserialize(
9063
        $serialized,
9064
        ['allowed_classes' => $allowedClasses]
9065
    );
9066
}
9067
9068
/**
9069
 * @param string $template
9070
 *
9071
 * @return string
9072
 */
9073
function api_find_template($template)
9074
{
9075
    return Template::findTemplateFilePath($template);
9076
}
9077
9078
/**
9079
 * @return array
9080
 */
9081
function api_get_language_list_for_flag()
9082
{
9083
    $table = Database::get_main_table(TABLE_MAIN_LANGUAGE);
9084
    $sql = "SELECT english_name, isocode FROM $table
9085
            ORDER BY original_name ASC";
9086
    static $languages = [];
9087
    if (empty($languages)) {
9088
        $result = Database::query($sql);
9089
        while ($row = Database::fetch_array($result)) {
9090
            $languages[$row['english_name']] = $row['isocode'];
9091
        }
9092
        $languages['english'] = 'gb';
9093
    }
9094
9095
    return $languages;
9096
}
9097
9098
/**
9099
 * @param string $name
9100
 *
9101
 * @return \ZipStream\ZipStream
9102
 */
9103
function api_create_zip($name)
9104
{
9105
    $zipStreamOptions = new \ZipStream\Option\Archive();
9106
    $zipStreamOptions->setSendHttpHeaders(true);
9107
    $zipStreamOptions->setContentDisposition('attachment');
9108
    $zipStreamOptions->setContentType('application/x-zip');
9109
9110
    $zip = new \ZipStream\ZipStream($name, $zipStreamOptions);
9111
9112
    return $zip;
9113
}
9114
9115
/**
9116
 * @return string
9117
 */
9118
function api_get_language_translate_html()
9119
{
9120
    $translate = api_get_configuration_value('translate_html');
9121
9122
    if (!$translate) {
9123
        return '';
9124
    }
9125
9126
    $languageList = api_get_languages();
9127
    $hideAll = '';
9128
    foreach ($languageList['all'] as $language) {
9129
        $hideAll .= '
9130
        $("span:lang('.$language['isocode'].')").filter(
9131
            function(e, val) {
9132
                // Only find the spans if they have set the lang
9133
                if ($(this).attr("lang") == null) {
9134
                    return false;
9135
                }
9136
9137
                // Ignore ckeditor classes
9138
                return !this.className.match(/cke(.*)/);
9139
        }).hide();'."\n";
9140
    }
9141
9142
    $userInfo = api_get_user_info();
9143
    $languageId = api_get_language_id($userInfo['language']);
9144
    $languageInfo = api_get_language_info($languageId);
9145
    $isoCode = 'en';
9146
9147
    if (!empty($languageInfo)) {
9148
        $isoCode = $languageInfo['isocode'];
9149
    }
9150
9151
    return '
9152
            $(function() {
9153
                '.$hideAll.'
9154
                var defaultLanguageFromUser = "'.$isoCode.'";
9155
9156
                $("span:lang('.$isoCode.')").filter(
9157
                    function() {
9158
                        // Ignore ckeditor classes
9159
                        return !this.className.match(/cke(.*)/);
9160
                }).show();
9161
9162
                var defaultLanguage = "";
9163
                var langFromUserFound = false;
9164
9165
                $(this).find("span").filter(
9166
                    function() {
9167
                        // Ignore ckeditor classes
9168
                        return !this.className.match(/cke(.*)/);
9169
                }).each(function() {
9170
                    defaultLanguage = $(this).attr("lang");
9171
                    if (defaultLanguage) {
9172
                        $(this).before().next("br").remove();
9173
                        if (defaultLanguageFromUser == defaultLanguage) {
9174
                            langFromUserFound = true;
9175
                        }
9176
                    }
9177
                });
9178
9179
                // Show default language
9180
                if (langFromUserFound == false && defaultLanguage) {
9181
                    $("span:lang("+defaultLanguage+")").filter(
9182
                    function() {
9183
                            // Ignore ckeditor classes
9184
                            return !this.className.match(/cke(.*)/);
9185
                    }).show();
9186
                }
9187
            });
9188
    ';
9189
}
9190