Passed
Push — master ( 93c132...8f17a5 )
by Julito
12:54
created

api_not_allowed()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 23
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

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

1261
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...
1262
{
1263
    // Get out if not integer
1264
    if ($userId != strval(intval($userId))) {
1265
        return [];
1266
    }
1267
1268
    $t_course = Database::get_main_table(TABLE_MAIN_COURSE);
1269
    $t_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
1270
1271
    $sql = "SELECT cc.id as real_id, cc.code code, cc.directory dir, cu.status status
1272
            FROM $t_course cc, $t_course_user cu
1273
            WHERE
1274
                cc.id = cu.c_id AND
1275
                cu.user_id = $userId AND
1276
                cu.relation_type <> ".COURSE_RELATION_TYPE_RRHH;
1277
    $result = Database::query($sql);
1278
    if ($result === false) {
1279
        return [];
1280
    }
1281
1282
    $courses = [];
1283
    while ($row = Database::fetch_array($result)) {
1284
        // we only need the database name of the course
1285
        $courses[] = $row;
1286
    }
1287
1288
    return $courses;
1289
}
1290
1291
/**
1292
 * Formats user information into a standard array
1293
 * This function should be only used inside api_get_user_info().
1294
 *
1295
 * @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...
1296
 * @param bool $add_password
1297
 * @param bool $loadAvatars  turn off to improve performance
1298
 *
1299
 * @return array Standard user array
1300
 */
1301
function _api_format_user($user, $add_password = false, $loadAvatars = true)
1302
{
1303
    $result = [];
1304
1305
    if (!isset($user['user_id'])) {
1306
        return [];
1307
    }
1308
1309
    $result['firstname'] = null;
1310
    $result['lastname'] = null;
1311
1312
    if (isset($user['firstname']) && isset($user['lastname'])) {
1313
        // with only lowercase
1314
        $result['firstname'] = $user['firstname'];
1315
        $result['lastname'] = $user['lastname'];
1316
    } elseif (isset($user['firstName']) && isset($user['lastName'])) {
1317
        // with uppercase letters
1318
        $result['firstname'] = isset($user['firstName']) ? $user['firstName'] : null;
1319
        $result['lastname'] = isset($user['lastName']) ? $user['lastName'] : null;
1320
    }
1321
1322
    if (isset($user['email'])) {
1323
        $result['mail'] = isset($user['email']) ? $user['email'] : null;
1324
        $result['email'] = isset($user['email']) ? $user['email'] : null;
1325
    } else {
1326
        $result['mail'] = isset($user['mail']) ? $user['mail'] : null;
1327
        $result['email'] = isset($user['mail']) ? $user['mail'] : null;
1328
    }
1329
1330
    $result['complete_name'] = api_get_person_name($result['firstname'], $result['lastname']);
1331
    $result['complete_name_with_username'] = $result['complete_name'];
1332
1333
    if (!empty($user['username']) && api_get_setting('profile.hide_username_with_complete_name') === 'false') {
1334
        $result['complete_name_with_username'] = $result['complete_name'].' ('.$user['username'].')';
1335
    }
1336
1337
    $showEmail = api_get_setting('show_email_addresses') === 'true';
1338
    if (!empty($user['email'])) {
1339
        $result['complete_name_with_email_forced'] = $result['complete_name'].' ('.$user['email'].')';
1340
        if ($showEmail) {
1341
            $result['complete_name_with_email'] = $result['complete_name'].' ('.$user['email'].')';
1342
        }
1343
    } else {
1344
        $result['complete_name_with_email'] = $result['complete_name'];
1345
        $result['complete_name_with_email_forced'] = $result['complete_name'];
1346
    }
1347
1348
    // Kept for historical reasons
1349
    $result['firstName'] = $result['firstname'];
1350
    $result['lastName'] = $result['lastname'];
1351
1352
    $attributes = [
1353
        'phone',
1354
        'address',
1355
        'picture_uri',
1356
        'official_code',
1357
        'status',
1358
        'active',
1359
        'auth_source',
1360
        'username',
1361
        'theme',
1362
        'language',
1363
        'creator_id',
1364
        'registration_date',
1365
        'hr_dept_id',
1366
        'expiration_date',
1367
        'last_login',
1368
        'user_is_online',
1369
    ];
1370
1371
    if (api_get_setting('extended_profile') === 'true') {
1372
        $attributes[] = 'competences';
1373
        $attributes[] = 'diplomas';
1374
        $attributes[] = 'teach';
1375
        $attributes[] = 'openarea';
1376
    }
1377
1378
    foreach ($attributes as $attribute) {
1379
        $result[$attribute] = isset($user[$attribute]) ? $user[$attribute] : null;
1380
    }
1381
1382
    $user_id = (int) $user['user_id'];
1383
    // Maintain the user_id index for backwards compatibility
1384
    $result['user_id'] = $result['id'] = $user_id;
1385
1386
    $hasCertificates = Certificate::getCertificateByUser($user_id);
1387
    $result['has_certificates'] = 0;
1388
    if (!empty($hasCertificates)) {
1389
        $result['has_certificates'] = 1;
1390
    }
1391
1392
    $result['icon_status'] = '';
1393
    $result['icon_status_medium'] = '';
1394
1395
    $result['is_admin'] = UserManager::is_admin($user_id);
1396
1397
    // Getting user avatar.
1398
    if ($loadAvatars) {
1399
        $result['avatar'] = '';
1400
        $result['avatar_no_query'] = '';
1401
        $result['avatar_small'] = '';
1402
        $result['avatar_medium'] = '';
1403
1404
        if (!isset($user['avatar'])) {
1405
            $originalFile = UserManager::getUserPicture(
1406
                $user_id,
1407
                USER_IMAGE_SIZE_ORIGINAL,
1408
                null,
1409
                $result
1410
            );
1411
            $result['avatar'] = $originalFile;
1412
            $avatarString = explode('?', $result['avatar']);
1413
            $result['avatar_no_query'] = reset($avatarString);
1414
        } else {
1415
            $result['avatar'] = $user['avatar'];
1416
            $avatarString = explode('?', $user['avatar']);
1417
            $result['avatar_no_query'] = reset($avatarString);
1418
        }
1419
1420
        if (!isset($user['avatar_small'])) {
1421
            $smallFile = UserManager::getUserPicture(
1422
                $user_id,
1423
                USER_IMAGE_SIZE_SMALL,
1424
                null,
1425
                $result
1426
            );
1427
            $result['avatar_small'] = $smallFile;
1428
        } else {
1429
            $result['avatar_small'] = $user['avatar_small'];
1430
        }
1431
1432
        if (!isset($user['avatar_medium'])) {
1433
            $mediumFile = UserManager::getUserPicture(
1434
                $user_id,
1435
                USER_IMAGE_SIZE_MEDIUM,
1436
                null,
1437
                $result
1438
            );
1439
            $result['avatar_medium'] = $mediumFile;
1440
        } else {
1441
            $result['avatar_medium'] = $user['avatar_medium'];
1442
        }
1443
1444
        $urlImg = api_get_path(WEB_IMG_PATH);
1445
        $iconStatus = '';
1446
        $iconStatusMedium = '';
1447
1448
        switch ($result['status']) {
1449
            case STUDENT:
1450
                if ($result['has_certificates']) {
1451
                    $iconStatus = $urlImg.'icons/svg/identifier_graduated.svg';
1452
                } else {
1453
                    $iconStatus = $urlImg.'icons/svg/identifier_student.svg';
1454
                }
1455
                break;
1456
            case COURSEMANAGER:
1457
                if ($result['is_admin']) {
1458
                    $iconStatus = $urlImg.'icons/svg/identifier_admin.svg';
1459
                } else {
1460
                    $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1461
                }
1462
                break;
1463
            case STUDENT_BOSS:
1464
                $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1465
                break;
1466
        }
1467
1468
        if (!empty($iconStatus)) {
1469
            $iconStatusMedium = '<img src="'.$iconStatus.'" width="32px" height="32px">';
1470
            $iconStatus = '<img src="'.$iconStatus.'" width="22px" height="22px">';
1471
        }
1472
1473
        $result['icon_status'] = $iconStatus;
1474
        $result['icon_status_medium'] = $iconStatusMedium;
1475
    }
1476
1477
    if (isset($user['user_is_online'])) {
1478
        $result['user_is_online'] = $user['user_is_online'] == true ? 1 : 0;
1479
    }
1480
    if (isset($user['user_is_online_in_chat'])) {
1481
        $result['user_is_online_in_chat'] = (int) $user['user_is_online_in_chat'];
1482
    }
1483
1484
    if ($add_password) {
1485
        $result['password'] = $user['password'];
1486
    }
1487
1488
    if (isset($result['profile_completed'])) {
1489
        $result['profile_completed'] = $user['profile_completed'];
1490
    }
1491
1492
    $result['profile_url'] = api_get_path(WEB_CODE_PATH).'social/profile.php?u='.$user_id;
1493
1494
    // Send message link
1495
    $sendMessage = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&user_id='.$user_id;
1496
    $result['complete_name_with_message_link'] = Display::url(
1497
        $result['complete_name_with_username'],
1498
        $sendMessage,
1499
        ['class' => 'ajax']
1500
    );
1501
1502
    if (isset($user['extra'])) {
1503
        $result['extra'] = $user['extra'];
1504
    }
1505
1506
    return $result;
1507
}
1508
1509
/**
1510
 * Finds all the information about a user.
1511
 * If no parameter is passed you find all the information about the current user.
1512
 *
1513
 * @param int  $user_id
1514
 * @param bool $checkIfUserOnline
1515
 * @param bool $showPassword
1516
 * @param bool $loadExtraData
1517
 * @param bool $loadOnlyVisibleExtraData Get the user extra fields that are visible
1518
 * @param bool $loadAvatars              turn off to improve performance and if avatars are not needed
1519
 * @param bool $updateCache              update apc cache if exists
1520
 *
1521
 * @return mixed $user_info user_id, lastname, firstname, username, email, etc or false on error
1522
 *
1523
 * @author Patrick Cool <[email protected]>
1524
 * @author Julio Montoya
1525
 *
1526
 * @version 21 September 2004
1527
 */
1528
function api_get_user_info(
1529
    $user_id = 0,
1530
    $checkIfUserOnline = false,
1531
    $showPassword = false,
1532
    $loadExtraData = false,
1533
    $loadOnlyVisibleExtraData = false,
1534
    $loadAvatars = true,
1535
    $updateCache = false
1536
) {
1537
    $apcVar = null;
1538
    $user = false;
1539
    $cacheAvailable = api_get_configuration_value('apc');
1540
1541
    if (empty($user_id)) {
1542
        $userFromSession = Session::read('_user');
1543
1544
        if (isset($userFromSession)) {
1545
            if ($cacheAvailable === true &&
1546
                (
1547
                    empty($userFromSession['is_anonymous']) &&
1548
                    (isset($userFromSession['status']) && $userFromSession['status'] != ANONYMOUS)
1549
                )
1550
            ) {
1551
                $apcVar = api_get_configuration_value('apc_prefix').'userinfo_'.$userFromSession['user_id'];
1552
                if (apcu_exists($apcVar)) {
1553
                    if ($updateCache) {
1554
                        apcu_store($apcVar, $userFromSession, 60);
1555
                    }
1556
                    $user = apcu_fetch($apcVar);
1557
                } else {
1558
                    $user = _api_format_user(
1559
                        $userFromSession,
1560
                        $showPassword,
1561
                        $loadAvatars
1562
                    );
1563
                    apcu_store($apcVar, $user, 60);
1564
                }
1565
            } else {
1566
                $user = _api_format_user(
1567
                    $userFromSession,
1568
                    $showPassword,
1569
                    $loadAvatars
1570
                );
1571
            }
1572
1573
            return $user;
1574
        }
1575
1576
        return false;
1577
    }
1578
1579
    // Make sure user_id is safe
1580
    $user_id = (int) $user_id;
1581
1582
    // Re-use user information if not stale and already stored in APCu
1583
    if ($cacheAvailable === true) {
1584
        $apcVar = api_get_configuration_value('apc_prefix').'userinfo_'.$user_id;
1585
        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...
1586
            $user = apcu_fetch($apcVar);
1587
1588
            return $user;
1589
        }
1590
    }
1591
1592
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1593
            WHERE id = $user_id";
1594
    $result = Database::query($sql);
1595
    if (Database::num_rows($result) > 0) {
1596
        $result_array = Database::fetch_array($result);
1597
        $result_array['user_is_online_in_chat'] = 0;
1598
        if ($checkIfUserOnline) {
1599
            $use_status_in_platform = user_is_online($user_id);
1600
            $result_array['user_is_online'] = $use_status_in_platform;
1601
            $user_online_in_chat = 0;
1602
            if ($use_status_in_platform) {
1603
                $user_status = UserManager::get_extra_user_data_by_field(
1604
                    $user_id,
1605
                    'user_chat_status',
1606
                    false,
1607
                    true
1608
                );
1609
                if ((int) $user_status['user_chat_status'] == 1) {
1610
                    $user_online_in_chat = 1;
1611
                }
1612
            }
1613
            $result_array['user_is_online_in_chat'] = $user_online_in_chat;
1614
        }
1615
1616
        if ($loadExtraData) {
1617
            $fieldValue = new ExtraFieldValue('user');
1618
            $result_array['extra'] = $fieldValue->getAllValuesForAnItem(
1619
                $user_id,
1620
                $loadOnlyVisibleExtraData
1621
            );
1622
        }
1623
        $user = _api_format_user($result_array, $showPassword, $loadAvatars);
1624
    }
1625
1626
    if ($cacheAvailable === true) {
1627
        apcu_store($apcVar, $user, 60);
1628
    }
1629
1630
    return $user;
1631
}
1632
1633
/**
1634
 * @param int $userId
1635
 *
1636
 * @return User
1637
 */
1638
function api_get_user_entity($userId)
1639
{
1640
    $userId = (int) $userId;
1641
    $repo = UserManager::getRepository();
1642
1643
    /** @var User $user */
1644
    $user = $repo->find($userId);
1645
1646
    return $user;
1647
}
1648
1649
/**
1650
 * @return User|null
1651
 */
1652
function api_get_current_user()
1653
{
1654
    $isLoggedIn = Container::$container->get('security.authorization_checker')->isGranted('IS_AUTHENTICATED_REMEMBERED');
1655
    if ($isLoggedIn === false) {
1656
        return null;
1657
    }
1658
1659
    $token = Container::$container->get('security.token_storage')->getToken();
1660
1661
    if (null !== $token) {
1662
        return $token->getUser();
1663
    }
1664
1665
    return null;
1666
}
1667
1668
/**
1669
 * Finds all the information about a user from username instead of user id.
1670
 *
1671
 * @param string $username
1672
 *
1673
 * @return mixed $user_info array user_id, lastname, firstname, username, email or false on error
1674
 *
1675
 * @author Yannick Warnier <[email protected]>
1676
 */
1677
function api_get_user_info_from_username($username = '')
1678
{
1679
    if (empty($username)) {
1680
        return false;
1681
    }
1682
    $username = trim($username);
1683
1684
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1685
            WHERE username='".Database::escape_string($username)."'";
1686
    $result = Database::query($sql);
1687
    if (Database::num_rows($result) > 0) {
1688
        $resultArray = Database::fetch_array($result);
1689
1690
        return _api_format_user($resultArray);
1691
    }
1692
1693
    return false;
1694
}
1695
1696
/**
1697
 * Get first user with an email.
1698
 *
1699
 * @param string $email
1700
 *
1701
 * @return array|bool
1702
 */
1703
function api_get_user_info_from_email($email = '')
1704
{
1705
    if (empty($email)) {
1706
        return false;
1707
    }
1708
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1709
            WHERE email ='".Database::escape_string($email)."' LIMIT 1";
1710
    $result = Database::query($sql);
1711
    if (Database::num_rows($result) > 0) {
1712
        $resultArray = Database::fetch_array($result);
1713
1714
        return _api_format_user($resultArray);
1715
    }
1716
1717
    return false;
1718
}
1719
1720
/**
1721
 * @return string
1722
 */
1723
function api_get_course_id()
1724
{
1725
    return Session::read('_cid', null);
1726
}
1727
1728
/**
1729
 * Returns the current course id (integer).
1730
 *
1731
 * @param string $code Optional course code
1732
 *
1733
 * @return int
1734
 */
1735
function api_get_course_int_id($code = null)
1736
{
1737
    if (!empty($code)) {
1738
        $code = Database::escape_string($code);
1739
        $row = Database::select(
1740
            'id',
1741
            Database::get_main_table(TABLE_MAIN_COURSE),
1742
            ['where' => ['code = ?' => [$code]]],
1743
            'first'
1744
        );
1745
1746
        if (is_array($row) && isset($row['id'])) {
1747
            return $row['id'];
1748
        } else {
1749
            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...
1750
        }
1751
    }
1752
1753
    return Session::read('_real_cid', 0);
1754
}
1755
1756
/**
1757
 * Returns the current course directory.
1758
 *
1759
 * This function relies on api_get_course_info()
1760
 *
1761
 * @param string    The course code - optional (takes it from session if not given)
1762
 *
1763
 * @return string The directory where the course is located inside the Chamilo "courses" directory
1764
 *
1765
 * @author Yannick Warnier <[email protected]>
1766
 */
1767
function api_get_course_path($course_code = null)
1768
{
1769
    $info = !empty($course_code) ? api_get_course_info($course_code) : api_get_course_info();
1770
1771
    return $info['path'];
1772
}
1773
1774
/**
1775
 * Gets a course setting from the current course_setting table. Try always using integer values.
1776
 *
1777
 * @param string $settingName The name of the setting we want from the table
1778
 * @param array  $courseInfo
1779
 * @param bool   $force       force checking the value in the database
1780
 *
1781
 * @return mixed The value of that setting in that table. Return -1 if not found.
1782
 */
1783
function api_get_course_setting($settingName, $courseInfo = [], $force = false)
1784
{
1785
    if (empty($courseInfo)) {
1786
        $courseInfo = api_get_course_info();
1787
    }
1788
1789
    if (empty($courseInfo) || empty($settingName)) {
1790
        return -1;
1791
    }
1792
1793
    $courseId = isset($courseInfo['real_id']) && !empty($courseInfo['real_id']) ? $courseInfo['real_id'] : 0;
1794
1795
    if (empty($courseId)) {
1796
        return -1;
1797
    }
1798
1799
    static $courseSettingInfo = [];
1800
1801
    if ($force) {
1802
        $courseSettingInfo = [];
1803
    }
1804
1805
    if (!isset($courseSettingInfo[$courseId])) {
1806
        $table = Database::get_course_table(TABLE_COURSE_SETTING);
1807
        $settingName = Database::escape_string($settingName);
1808
1809
        $sql = "SELECT variable, value FROM $table
1810
                WHERE c_id = $courseId ";
1811
        $res = Database::query($sql);
1812
        if (Database::num_rows($res) > 0) {
1813
            $result = Database::store_result($res, 'ASSOC');
1814
            $courseSettingInfo[$courseId] = array_column($result, 'value', 'variable');
1815
1816
            if (isset($courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'])) {
1817
                $value = $courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'];
1818
                if (!is_null($value)) {
1819
                    $result = explode(',', $value);
1820
                    $courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'] = $result;
1821
                }
1822
            }
1823
        }
1824
    }
1825
1826
    if (isset($courseSettingInfo[$courseId]) && isset($courseSettingInfo[$courseId][$settingName])) {
1827
        return $courseSettingInfo[$courseId][$settingName];
1828
    }
1829
1830
    return -1;
1831
}
1832
1833
/**
1834
 * Gets an anonymous user ID.
1835
 *
1836
 * For some tools that need tracking, like the learnpath tool, it is necessary
1837
 * to have a usable user-id to enable some kind of tracking, even if not
1838
 * perfect. An anonymous ID is taken from the users table by looking for a
1839
 * status of "6" (anonymous).
1840
 *
1841
 * @return int User ID of the anonymous user, or O if no anonymous user found
1842
 */
1843
function api_get_anonymous_id()
1844
{
1845
    // Find if another anon is connected now
1846
    $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
1847
    $tableU = Database::get_main_table(TABLE_MAIN_USER);
1848
    $ip = Database::escape_string(api_get_real_ip());
1849
    $max = (int) api_get_configuration_value('max_anonymous_users');
1850
    if ($max >= 2) {
1851
        $sql = "SELECT * FROM $table as TEL
1852
                JOIN $tableU as U
1853
                ON U.user_id = TEL.login_user_id
1854
                WHERE TEL.user_ip = '$ip'
1855
                    AND U.status = ".ANONYMOUS."
1856
                    AND U.user_id != 2 ";
1857
1858
        $result = Database::query($sql);
1859
        if (empty(Database::num_rows($result))) {
1860
            $login = uniqid('anon_');
1861
            $anonList = UserManager::get_user_list(['status' => ANONYMOUS], ['registration_date ASC']);
1862
            if (count($anonList) >= $max) {
1863
                foreach ($anonList as $userToDelete) {
1864
                    UserManager::delete_user($userToDelete['user_id']);
1865
                    break;
1866
                }
1867
            }
1868
            $userId = UserManager::create_user(
1869
                $login,
1870
                'anon',
1871
                ANONYMOUS,
1872
                ' anonymous@localhost',
1873
                $login,
1874
                $login
1875
            );
1876
1877
            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...
1878
        } else {
1879
            $row = Database::fetch_array($result, 'ASSOC');
1880
1881
            return $row['user_id'];
1882
        }
1883
    }
1884
1885
    $table = Database::get_main_table(TABLE_MAIN_USER);
1886
    $sql = "SELECT user_id
1887
            FROM $table
1888
            WHERE status = ".ANONYMOUS." ";
1889
    $res = Database::query($sql);
1890
    if (Database::num_rows($res) > 0) {
1891
        $row = Database::fetch_array($res, 'ASSOC');
1892
1893
        return $row['user_id'];
1894
    }
1895
1896
    // No anonymous user was found.
1897
    return 0;
1898
}
1899
1900
/**
1901
 * @param string $courseCode
1902
 * @param int    $sessionId
1903
 * @param int    $groupId
1904
 *
1905
 * @return string
1906
 */
1907
function api_get_cidreq_params($courseCode, $sessionId = 0, $groupId = 0)
1908
{
1909
    $courseCode = !empty($courseCode) ? htmlspecialchars($courseCode) : '';
1910
    $sessionId = !empty($sessionId) ? (int) $sessionId : 0;
1911
    $groupId = !empty($groupId) ? (int) $groupId : 0;
1912
1913
    $url = 'cidReq='.$courseCode;
1914
    $url .= '&id_session='.$sessionId;
1915
    $url .= '&gidReq='.$groupId;
1916
1917
    return $url;
1918
}
1919
1920
/**
1921
 * Returns the current course url part including session, group, and gradebook params.
1922
 *
1923
 * @param bool   $addSessionId
1924
 * @param bool   $addGroupId
1925
 * @param string $origin
1926
 *
1927
 * @return string Course & session references to add to a URL
1928
 */
1929
function api_get_cidreq($addSessionId = true, $addGroupId = true, $origin = '')
1930
{
1931
    $courseId = api_get_course_int_id();
1932
    $url = empty($courseId) ? '' : 'cid='.$courseId;
1933
    $origin = empty($origin) ? api_get_origin() : Security::remove_XSS($origin);
1934
1935
    if ($addSessionId) {
1936
        if (!empty($url)) {
1937
            $url .= api_get_session_id() == 0 ? '&sid=0' : '&sid='.api_get_session_id();
1938
        }
1939
    }
1940
1941
    if ($addGroupId) {
1942
        if (!empty($url)) {
1943
            $url .= api_get_group_id() == 0 ? '&gid=0' : '&gid='.api_get_group_id();
1944
        }
1945
    }
1946
1947
    if (!empty($url)) {
1948
        $url .= '&gradebook='.(int) api_is_in_gradebook();
1949
        $url .= '&origin='.$origin;
1950
    }
1951
1952
    return $url;
1953
}
1954
1955
/**
1956
 * Get if we visited a gradebook page.
1957
 *
1958
 * @return bool
1959
 */
1960
function api_is_in_gradebook()
1961
{
1962
    return Session::read('in_gradebook', false);
1963
}
1964
1965
/**
1966
 * Set that we are in a page inside a gradebook.
1967
 */
1968
function api_set_in_gradebook()
1969
{
1970
    Session::write('in_gradebook', true);
1971
}
1972
1973
/**
1974
 * Remove gradebook session.
1975
 */
1976
function api_remove_in_gradebook()
1977
{
1978
    Session::erase('in_gradebook');
1979
}
1980
1981
/**
1982
 * Returns the current course info array see api_format_course_array()
1983
 * If the course_code is given, the returned array gives info about that
1984
 * particular course, if none given it gets the course info from the session.
1985
 *
1986
 * @param string $course_code
1987
 *
1988
 * @return array
1989
 */
1990
function api_get_course_info($course_code = null)
1991
{
1992
    if (!empty($course_code)) {
1993
        $course = Container::getCourseRepository()->findOneByCode($course_code);
1994
        if (empty($course)) {
1995
            return [];
1996
        }
1997
1998
        $courseInfo = api_format_course_array($course);
1999
2000
        return $courseInfo;
2001
    }
2002
2003
    /*$course_code = Database::escape_string($course_code);
2004
    $courseId = api_get_course_int_id($course_code);
2005
    if (empty($courseId)) {
2006
        return [];
2007
    }
2008
2009
    $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
2010
    $course_cat_table = Database::get_main_table(TABLE_MAIN_CATEGORY);
2011
    $sql = "SELECT
2012
                course.*,
2013
                course_category.code faCode,
2014
                course_category.name faName
2015
            FROM $course_table
2016
            LEFT JOIN $course_cat_table
2017
            ON course.category_code = course_category.code
2018
            WHERE course.id = $courseId";
2019
    $result = Database::query($sql);
2020
    $courseInfo = [];
2021
    if (Database::num_rows($result) > 0) {
2022
        $data = Database::fetch_array($result);
2023
        $courseInfo = api_format_course_array($data);
2024
    }
2025
2026
    return $courseInfo;*/
2027
2028
    $course = Session::read('_course');
2029
    if ($course == '-1') {
2030
        $course = [];
2031
    }
2032
2033
    return $course;
2034
}
2035
2036
/**
2037
 * @param int $courseId
2038
 *
2039
 * @return Course
2040
 */
2041
function api_get_course_entity($courseId = 0)
2042
{
2043
    if (empty($courseId)) {
2044
        $courseId = api_get_course_int_id();
2045
    }
2046
2047
    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

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

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

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

5081
            $files = copyr("$source/$entry", "$dest/$entry", $exclude, /** @scrutinizer ignore-type */ $copied_files);
Loading history...
5082
        }
5083
    }
5084
    // Clean up.
5085
    $dir->close();
5086
5087
    return true;
5088
}
5089
5090
/**
5091
 * @todo: Using DIRECTORY_SEPARATOR is not recommended, this is an obsolete approach.
5092
 * Documentation header to be added here.
5093
 *
5094
 * @param string $pathname
5095
 * @param string $base_path_document
5096
 * @param int    $session_id
5097
 *
5098
 * @return mixed True if directory already exists, false if a file already exists at
5099
 *               the destination and null if everything goes according to plan
5100
 */
5101
function copy_folder_course_session(
5102
    $pathname,
5103
    $base_path_document,
5104
    $session_id,
5105
    $course_info,
5106
    $document,
5107
    $source_course_id
5108
) {
5109
    $table = Database::get_course_table(TABLE_DOCUMENT);
5110
    $session_id = intval($session_id);
5111
    $source_course_id = intval($source_course_id);
5112
5113
    // Check whether directory already exists.
5114
    if (is_dir($pathname) || empty($pathname)) {
5115
        return true;
5116
    }
5117
5118
    // Ensure that a file with the same name does not already exist.
5119
    if (is_file($pathname)) {
5120
        trigger_error('copy_folder_course_session(): File exists', E_USER_WARNING);
5121
5122
        return false;
5123
    }
5124
5125
    $course_id = $course_info['real_id'];
5126
    $folders = explode(DIRECTORY_SEPARATOR, str_replace($base_path_document.DIRECTORY_SEPARATOR, '', $pathname));
5127
    $new_pathname = $base_path_document;
5128
    $path = '';
5129
5130
    foreach ($folders as $folder) {
5131
        $new_pathname .= DIRECTORY_SEPARATOR.$folder;
5132
        $path .= DIRECTORY_SEPARATOR.$folder;
5133
5134
        if (!file_exists($new_pathname)) {
5135
            $path = Database::escape_string($path);
5136
5137
            $sql = "SELECT * FROM $table
5138
                    WHERE
5139
                        c_id = $source_course_id AND
5140
                        path = '$path' AND
5141
                        filetype = 'folder' AND
5142
                        session_id = '$session_id'";
5143
            $rs1 = Database::query($sql);
5144
            $num_rows = Database::num_rows($rs1);
5145
5146
            if ($num_rows == 0) {
5147
                mkdir($new_pathname, api_get_permissions_for_new_directories());
5148
5149
                // Insert new folder with destination session_id.
5150
                $params = [
5151
                    'c_id' => $course_id,
5152
                    'path' => $path,
5153
                    'comment' => $document->comment,
5154
                    'title' => basename($new_pathname),
5155
                    'filetype' => 'folder',
5156
                    'size' => '0',
5157
                    'session_id' => $session_id,
5158
                ];
5159
                $document_id = Database::insert($table, $params);
5160
                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...
5161
                    $sql = "UPDATE $table SET id = iid WHERE iid = $document_id";
5162
                    Database::query($sql);
5163
5164
                    api_item_property_update(
5165
                        $course_info,
5166
                        TOOL_DOCUMENT,
5167
                        $document_id,
5168
                        'FolderCreated',
5169
                        api_get_user_id(),
5170
                        0,
5171
                        0,
5172
                        null,
5173
                        null,
5174
                        $session_id
5175
                    );
5176
                }
5177
            }
5178
        }
5179
    } // en foreach
5180
}
5181
5182
// TODO: chmodr() is a better name. Some corrections are needed. Documentation header to be added here.
5183
/**
5184
 * @param string $path
5185
 */
5186
function api_chmod_R($path, $filemode)
5187
{
5188
    if (!is_dir($path)) {
5189
        return chmod($path, $filemode);
5190
    }
5191
5192
    $handler = opendir($path);
5193
    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

5193
    while ($file = readdir(/** @scrutinizer ignore-type */ $handler)) {
Loading history...
5194
        if ($file != '.' && $file != '..') {
5195
            $fullpath = "$path/$file";
5196
            if (!is_dir($fullpath)) {
5197
                if (!chmod($fullpath, $filemode)) {
5198
                    return false;
5199
                }
5200
            } else {
5201
                if (!api_chmod_R($fullpath, $filemode)) {
5202
                    return false;
5203
                }
5204
            }
5205
        }
5206
    }
5207
5208
    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

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

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

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

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

8464
        fclose(/** @scrutinizer ignore-type */ $fp);
Loading history...
8465
    }
8466
8467
    return $isCreated;
8468
}
8469
8470
/**
8471
 * Sends an email
8472
 * Sender name and email can be specified, if not specified
8473
 * name and email of the platform admin are used.
8474
 *
8475
 * @param string    name of recipient
8476
 * @param string    email of recipient
8477
 * @param string    email subject
8478
 * @param string    email body
8479
 * @param string    sender name
8480
 * @param string    sender e-mail
8481
 * @param array     extra headers in form $headers = array($name => $value) to allow parsing
8482
 * @param array     data file (path and filename)
8483
 * @param bool      True for attaching a embedded file inside content html (optional)
8484
 * @param array     Additional parameters
8485
 *
8486
 * @return bool true if mail was sent
8487
 */
8488
function api_mail_html(
8489
    $recipientName,
8490
    $recipientEmail,
8491
    $subject,
8492
    $body,
8493
    $senderName = '',
8494
    $senderEmail = '',
8495
    $extra_headers = [],
8496
    $data_file = [],
8497
    $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

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