Passed
Push — master ( ef4281...937b2f )
by Julito
12:13
created

api_get_user_info()   B

Complexity

Conditions 9
Paths 11

Size

Total Lines 64
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 33
c 0
b 0
f 0
nc 11
nop 7
dl 0
loc 64
rs 8.0555

How to fix   Long Method   

Long Method

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

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

Commonly applied refactorings include:

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

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

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

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

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

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

3613
    /** @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...
3614
    $message = null,
3615
    $responseCode = 0
0 ignored issues
show
Unused Code introduced by
The parameter $responseCode 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

3615
    /** @scrutinizer ignore-unused */ $responseCode = 0

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...
3616
) {
3617
    $message = empty($message) ? get_lang('You are not allowed') : $message;
3618
    Session::write('error_message', $message);
3619
3620
    header('Location: '.api_get_path(WEB_PUBLIC_PATH).'error');
3621
    exit;
3622
}
3623
3624
/**
3625
 * Gets a UNIX timestamp from a database (MySQL) datetime format string.
3626
 *
3627
 * @param $last_post_datetime standard output date in a sql query
3628
 *
3629
 * @return int timestamp
3630
 *
3631
 * @author Toon Van Hoecke <[email protected]>
3632
 *
3633
 * @version October 2003
3634
 * @desc convert sql date to unix timestamp
3635
 */
3636
function convert_sql_date($last_post_datetime)
3637
{
3638
    list($last_post_date, $last_post_time) = explode(' ', $last_post_datetime);
3639
    list($year, $month, $day) = explode('-', $last_post_date);
3640
    list($hour, $min, $sec) = explode(':', $last_post_time);
3641
3642
    return mktime((int) $hour, (int) $min, (int) $sec, (int) $month, (int) $day, (int) $year);
3643
}
3644
3645
/**
3646
 * Gets item visibility from the item_property table.
3647
 *
3648
 * Getting the visibility is done by getting the last updated visibility entry,
3649
 * using the largest session ID found if session 0 and another was found (meaning
3650
 * the only one that is actually from the session, in case there are results from
3651
 * session 0 *AND* session n).
3652
 *
3653
 * @param array  $_course  Course properties array (result of api_get_course_info())
3654
 * @param string $tool     Tool (learnpath, document, etc)
3655
 * @param int    $id       The item ID in the given tool
3656
 * @param int    $session  The session ID (optional)
3657
 * @param int    $user_id
3658
 * @param string $type
3659
 * @param string $group_id
3660
 *
3661
 * @return int -1 on error, 0 if invisible, 1 if visible
3662
 */
3663
function api_get_item_visibility(
3664
    $_course,
3665
    $tool,
3666
    $id,
3667
    $session = 0,
3668
    $user_id = null,
3669
    $type = null,
3670
    $group_id = null
3671
) {
3672
    if (!is_array($_course) || 0 == count($_course) || empty($tool) || empty($id)) {
3673
        return -1;
3674
    }
3675
3676
    // 0 visible
3677
    // 1 visible
3678
    // 2 deleted
3679
3680
    switch ($tool) {
3681
        case 'learnpath':
3682
3683
            break;
3684
    }
3685
3686
    $tool = Database::escape_string($tool);
3687
    $id = (int) $id;
3688
    $session = (int) $session;
3689
    $TABLE_ITEMPROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY);
3690
    $course_id = (int) $_course['real_id'];
3691
3692
    $userCondition = '';
3693
    if (!empty($user_id)) {
3694
        $user_id = (int) $user_id;
3695
        $userCondition = " AND to_user_id = $user_id ";
3696
    }
3697
3698
    $typeCondition = '';
3699
    if (!empty($type)) {
3700
        $type = Database::escape_string($type);
3701
        $typeCondition = " AND lastedit_type = '$type' ";
3702
    }
3703
3704
    $groupCondition = '';
3705
    if (!empty($group_id)) {
3706
        $group_id = (int) $group_id;
3707
        $groupCondition = " AND to_group_id = '$group_id' ";
3708
    }
3709
3710
    $sql = "SELECT visibility
3711
            FROM $TABLE_ITEMPROPERTY
3712
            WHERE
3713
                c_id = $course_id AND
3714
                tool = '$tool' AND
3715
                ref = $id AND
3716
                (session_id = $session OR session_id = 0 OR session_id IS NULL)
3717
                $userCondition $typeCondition $groupCondition
3718
            ORDER BY session_id DESC, lastedit_date DESC
3719
            LIMIT 1";
3720
3721
    $res = Database::query($sql);
3722
    if (false === $res || 0 == Database::num_rows($res)) {
3723
        return -1;
3724
    }
3725
    $row = Database::fetch_array($res);
3726
3727
    return (int) $row['visibility'];
3728
}
3729
3730
/**
3731
 * Delete a row in the c_item_property table.
3732
 *
3733
 * @param array  $courseInfo
3734
 * @param string $tool
3735
 * @param int    $itemId
3736
 * @param int    $userId
3737
 * @param int    $groupId    group.iid
3738
 * @param int    $sessionId
3739
 *
3740
 * @return false|null
3741
 */
3742
function api_item_property_delete(
3743
    $courseInfo,
3744
    $tool,
3745
    $itemId,
3746
    $userId,
3747
    $groupId = 0,
3748
    $sessionId = 0
3749
) {
3750
    if (empty($courseInfo)) {
3751
        return false;
3752
    }
3753
3754
    $courseId = (int) $courseInfo['real_id'];
3755
3756
    if (empty($courseId) || empty($tool) || empty($itemId)) {
3757
        return false;
3758
    }
3759
3760
    $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
3761
    $tool = Database::escape_string($tool);
3762
    $itemId = intval($itemId);
3763
    $userId = intval($userId);
3764
    $groupId = intval($groupId);
3765
    $sessionId = intval($sessionId);
3766
3767
    $groupCondition = " AND to_group_id = $groupId ";
3768
    if (empty($groupId)) {
3769
        $groupCondition = " AND (to_group_id is NULL OR to_group_id = 0) ";
3770
    }
3771
3772
    $userCondition = " AND to_user_id = $userId ";
3773
    if (empty($userId)) {
3774
        $userCondition = " AND (to_user_id is NULL OR to_user_id = 0) ";
3775
    }
3776
    $sessionCondition = api_get_session_condition($sessionId, true, false, 'session_id');
3777
    $sql = "DELETE FROM $table
3778
            WHERE
3779
                c_id = $courseId AND
3780
                tool  = '$tool' AND
3781
                ref = $itemId
3782
                $sessionCondition
3783
                $userCondition
3784
                $groupCondition
3785
            ";
3786
3787
    Database::query($sql);
3788
}
3789
3790
/**
3791
 * Updates or adds item properties to the Item_propetry table
3792
 * Tool and lastedit_type are language independant strings (langvars->get_lang!).
3793
 *
3794
 * @param array  $_course        array with course properties
3795
 * @param string $tool           tool id, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
3796
 * @param int    $item_id        id of the item itself, linked to key of every tool ('id', ...)
3797
 * @param string $last_edit_type add or update action
3798
 *                               (1) message to be translated (in trad4all) : e.g. DocumentAdded, DocumentUpdated;
3799
 *                               (2) "delete"
3800
 *                               (3) "visible"
3801
 *                               (4) "invisible"
3802
 * @param int    $user_id        id of the editing/adding user
3803
 * @param array  $groupInfo      must include group.iid/group.od
3804
 * @param int    $to_user_id     id of the intended user (always has priority over $to_group_id !), only relevant for $type (1)
3805
 * @param string $start_visible  0000-00-00 00:00:00 format
3806
 * @param string $end_visible    0000-00-00 00:00:00 format
3807
 * @param int    $session_id     The session ID, if any, otherwise will default to 0
3808
 *
3809
 * @return bool false if update fails
3810
 *
3811
 * @author Toon Van Hoecke <[email protected]>, Ghent University
3812
 *
3813
 * @version January 2005
3814
 * @desc update the item_properties table (if entry not exists, insert) of the course
3815
 */
3816
function api_item_property_update(
3817
    $_course,
3818
    $tool,
3819
    $item_id,
3820
    $last_edit_type,
3821
    $user_id,
3822
    $groupInfo = [],
3823
    $to_user_id = null,
3824
    $start_visible = '',
3825
    $end_visible = '',
3826
    $session_id = 0
3827
) {
3828
    if (empty($_course)) {
3829
        return false;
3830
    }
3831
3832
    $course_id = $_course['real_id'];
3833
3834
    if (empty($course_id)) {
3835
        return false;
3836
    }
3837
3838
    $to_group_id = 0;
3839
    if (!empty($groupInfo) && isset($groupInfo['iid'])) {
3840
        $to_group_id = (int) $groupInfo['iid'];
3841
    }
3842
3843
    $em = Database::getManager();
3844
3845
    // Definition of variables.
3846
    $tool = Database::escape_string($tool);
3847
    $item_id = (int) $item_id;
3848
    $lastEditTypeNoFilter = $last_edit_type;
3849
    $last_edit_type = Database::escape_string($last_edit_type);
3850
    $user_id = (int) $user_id;
3851
3852
    $startVisible = "NULL";
3853
    if (!empty($start_visible)) {
3854
        $start_visible = Database::escape_string($start_visible);
3855
        $startVisible = "'$start_visible'";
3856
    }
3857
3858
    $endVisible = "NULL";
3859
    if (!empty($end_visible)) {
3860
        $end_visible = Database::escape_string($end_visible);
3861
        $endVisible = "'$end_visible'";
3862
    }
3863
3864
    $to_filter = '';
3865
    $time = api_get_utc_datetime();
3866
3867
    if (!empty($session_id)) {
3868
        $session_id = (int) $session_id;
3869
    } else {
3870
        $session_id = api_get_session_id();
3871
    }
3872
3873
    // Definition of tables.
3874
    $tableItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
3875
3876
    if ($to_user_id <= 0) {
3877
        $to_user_id = null; // No to_user_id set
3878
    }
3879
3880
    if (!is_null($to_user_id)) {
3881
        // $to_user_id has more priority than $to_group_id
3882
        $to_user_id = (int) $to_user_id;
3883
        $to_field = 'to_user_id';
3884
        $to_value = $to_user_id;
3885
    } else {
3886
        // $to_user_id is not set.
3887
        $to_field = 'to_group_id';
3888
        $to_value = $to_group_id;
3889
    }
3890
3891
    $toValueCondition = empty($to_value) ? 'NULL' : "'$to_value'";
3892
    // Set filters for $to_user_id and $to_group_id, with priority for $to_user_id
3893
    $condition_session = " AND session_id = $session_id ";
3894
    if (empty($session_id)) {
3895
        $condition_session = ' AND (session_id = 0 OR session_id IS NULL) ';
3896
    }
3897
3898
    $filter = " c_id = $course_id AND tool = '$tool' AND ref = $item_id $condition_session ";
3899
3900
    // Check whether $to_user_id and $to_group_id are passed in the function call.
3901
    // If both are not passed (both are null) then it is a message for everybody and $to_group_id should be 0 !
3902
    if (is_null($to_user_id) && is_null($to_group_id)) {
3903
        $to_group_id = 0;
3904
    }
3905
3906
    if (!is_null($to_user_id)) {
3907
        // Set filter to intended user.
3908
        $to_filter = " AND to_user_id = $to_user_id $condition_session";
3909
    } else {
3910
        // Set filter to intended group.
3911
        if ((0 != $to_group_id) && $to_group_id == strval(intval($to_group_id))) {
3912
            $to_filter = " AND to_group_id = $to_group_id $condition_session";
3913
        }
3914
    }
3915
3916
    // Adding filter if set.
3917
    $filter .= $to_filter;
3918
3919
    // Update if possible
3920
    $set_type = '';
3921
3922
    switch ($lastEditTypeNoFilter) {
3923
        case 'delete':
3924
            // delete = make item only visible for the platform admin.
3925
            $visibility = '2';
3926
            if (!empty($session_id)) {
3927
                // Check whether session id already exist into item_properties for updating visibility or add it.
3928
                $sql = "SELECT session_id FROM $tableItemProperty
3929
                        WHERE
3930
                            c_id = $course_id AND
3931
                            tool = '$tool' AND
3932
                            ref = $item_id AND
3933
                            session_id = $session_id";
3934
                $rs = Database::query($sql);
3935
                if (Database::num_rows($rs) > 0) {
3936
                    $sql = "UPDATE $tableItemProperty
3937
                            SET lastedit_type       = '".str_replace('_', '', ucwords($tool))."Deleted',
3938
                                lastedit_date       = '$time',
3939
                                lastedit_user_id    = $user_id,
3940
                                visibility          = $visibility,
3941
                                session_id          = $session_id $set_type
3942
                            WHERE $filter";
3943
                    $result = Database::query($sql);
3944
                } else {
3945
                    $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)
3946
                            VALUES ($course_id, '$tool',$item_id, '$time', $user_id, '$time', '$last_edit_type',$user_id, $toValueCondition, $visibility, $startVisible, $endVisible, $session_id)";
3947
                    $result = Database::query($sql);
3948
                    $id = Database::insert_id();
3949
                    if ($id) {
3950
                        $sql = "UPDATE $tableItemProperty SET id = iid WHERE iid = $id";
3951
                        Database::query($sql);
3952
                    }
3953
                }
3954
            } else {
3955
                $sql = "UPDATE $tableItemProperty
3956
                        SET
3957
                            lastedit_type='".str_replace('_', '', ucwords($tool))."Deleted',
3958
                            lastedit_date='$time',
3959
                            lastedit_user_id = $user_id,
3960
                            visibility = $visibility $set_type
3961
                        WHERE $filter";
3962
                $result = Database::query($sql);
3963
            }
3964
            break;
3965
        case 'visible': // Change item to visible.
3966
            $visibility = '1';
3967
            if (!empty($session_id)) {
3968
                // Check whether session id already exist into item_properties for updating visibility or add it.
3969
                $sql = "SELECT session_id FROM $tableItemProperty
3970
                        WHERE
3971
                            c_id = $course_id AND
3972
                            tool = '$tool' AND
3973
                            ref = $item_id AND
3974
                            session_id = $session_id";
3975
                $rs = Database::query($sql);
3976
                if (Database::num_rows($rs) > 0) {
3977
                    $sql = "UPDATE $tableItemProperty
3978
                            SET
3979
                                lastedit_type='".str_replace('_', '', ucwords($tool))."Visible',
3980
                                lastedit_date='$time',
3981
                                lastedit_user_id = $user_id,
3982
                                visibility = $visibility,
3983
                                session_id = $session_id $set_type
3984
                            WHERE $filter";
3985
                    $result = Database::query($sql);
3986
                } else {
3987
                    $sql = "INSERT INTO $tableItemProperty (c_id, tool, ref, insert_date, insert_user_id, lastedit_date, lastedit_type, lastedit_user_id, $to_field, visibility, start_visible, end_visible, session_id)
3988
                            VALUES ($course_id, '$tool', $item_id, '$time', $user_id, '$time', '$last_edit_type', $user_id, $toValueCondition, $visibility, $startVisible, $endVisible, $session_id)";
3989
                    $result = Database::query($sql);
3990
                    $id = Database::insert_id();
3991
                    if ($id) {
3992
                        $sql = "UPDATE $tableItemProperty SET id = iid WHERE iid = $id";
3993
                        Database::query($sql);
3994
                    }
3995
                }
3996
            } else {
3997
                $sql = "UPDATE $tableItemProperty
3998
                        SET
3999
                            lastedit_type='".str_replace('_', '', ucwords($tool))."Visible',
4000
                            lastedit_date='$time',
4001
                            lastedit_user_id = $user_id,
4002
                            visibility = $visibility $set_type
4003
                        WHERE $filter";
4004
                $result = Database::query($sql);
4005
            }
4006
            break;
4007
        case 'invisible': // Change item to invisible.
4008
            $visibility = '0';
4009
            if (!empty($session_id)) {
4010
                // Check whether session id already exist into item_properties for updating visibility or add it
4011
                $sql = "SELECT session_id FROM $tableItemProperty
4012
                        WHERE
4013
                            c_id = $course_id AND
4014
                            tool = '$tool' AND
4015
                            ref = $item_id AND
4016
                            session_id = $session_id";
4017
                $rs = Database::query($sql);
4018
                if (Database::num_rows($rs) > 0) {
4019
                    $sql = "UPDATE $tableItemProperty
4020
                            SET
4021
                                lastedit_type = '".str_replace('_', '', ucwords($tool))."Invisible',
4022
                                lastedit_date = '$time',
4023
                                lastedit_user_id = $user_id,
4024
                                visibility = $visibility,
4025
                                session_id = $session_id $set_type
4026
                            WHERE $filter";
4027
                    $result = Database::query($sql);
4028
                } else {
4029
                    $sql = "INSERT INTO $tableItemProperty (c_id, tool, ref, insert_date, insert_user_id, lastedit_date, lastedit_type, lastedit_user_id,$to_field, visibility, start_visible, end_visible, session_id)
4030
                            VALUES ($course_id, '$tool', $item_id, '$time', $user_id, '$time', '$last_edit_type', $user_id, $toValueCondition, $visibility, $startVisible, $endVisible, $session_id)";
4031
                    $result = Database::query($sql);
4032
                    $id = Database::insert_id();
4033
                    if ($id) {
4034
                        $sql = "UPDATE $tableItemProperty SET id = iid WHERE iid = $id";
4035
                        Database::query($sql);
4036
                    }
4037
                }
4038
            } else {
4039
                $sql = "UPDATE $tableItemProperty
4040
                        SET
4041
                            lastedit_type = '".str_replace('_', '', ucwords($tool))."Invisible',
4042
                            lastedit_date = '$time',
4043
                            lastedit_user_id = $user_id,
4044
                            visibility = $visibility $set_type
4045
                        WHERE $filter";
4046
                $result = Database::query($sql);
4047
            }
4048
            break;
4049
        default: // The item will be added or updated.
4050
            $set_type = ", lastedit_type = '$last_edit_type' ";
4051
            $visibility = '1';
4052
            //$filter .= $to_filter; already added
4053
            $sql = "UPDATE $tableItemProperty
4054
                    SET
4055
                      lastedit_date = '$time',
4056
                      lastedit_user_id = $user_id $set_type
4057
                    WHERE $filter";
4058
            $result = Database::query($sql);
4059
    }
4060
4061
    // Insert if no entries are found (can only happen in case of $last_edit_type switch is 'default').
4062
    if (false == $result || 0 == Database::affected_rows($result)) {
4063
        $objCourse = $em->find('ChamiloCoreBundle:Course', intval($course_id));
4064
        $objTime = new DateTime('now', new DateTimeZone('UTC'));
4065
        $objUser = api_get_user_entity($user_id);
4066
        if (empty($objUser)) {
4067
            // Use anonymous
4068
            $user_id = api_get_anonymous_id();
4069
            $objUser = api_get_user_entity($user_id);
4070
        }
4071
4072
        $objGroup = null;
4073
        if (!empty($to_group_id)) {
4074
            $objGroup = $em->find('ChamiloCourseBundle:CGroupInfo', $to_group_id);
4075
        }
4076
4077
        $objToUser = api_get_user_entity($to_user_id);
4078
        $objSession = $em->find('ChamiloCoreBundle:Session', intval($session_id));
4079
4080
        $startVisibleDate = !empty($start_visible) ? new DateTime($start_visible, new DateTimeZone('UTC')) : null;
4081
        $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...
4082
4083
        $cItemProperty = new CItemProperty($objCourse);
4084
        $cItemProperty
4085
            ->setTool($tool)
4086
            ->setRef($item_id)
4087
            ->setInsertDate($objTime)
4088
            ->setInsertUser($objUser)
4089
            ->setLasteditDate($objTime)
4090
            ->setLasteditType($last_edit_type)
4091
            ->setGroup($objGroup)
4092
            ->setToUser($objToUser)
4093
            ->setVisibility($visibility)
4094
            ->setStartVisible($startVisibleDate)
4095
            ->setEndVisible($endVisibleDate)
4096
            ->setSession($objSession);
4097
4098
        $em->persist($cItemProperty);
4099
        $em->flush();
4100
4101
        $id = $cItemProperty->getIid();
4102
4103
        if ($id) {
4104
            $cItemProperty->setId($id);
4105
            $em->merge($cItemProperty);
4106
            $em->flush();
4107
4108
            return false;
4109
        }
4110
    }
4111
4112
    return true;
4113
}
4114
4115
/**
4116
 * Gets item property by tool.
4117
 *
4118
 * @param string    course code
4119
 * @param string    tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4120
 * @param int       id of the item itself, linked to key of every tool ('id', ...), "*" = all items of the tool
4121
 * @param int    $session_id
4122
 * @param string $tool
4123
 * @param string $course_code
4124
 *
4125
 * @return array All fields from c_item_property (all rows found) or empty array
4126
 */
4127
function api_get_item_property_by_tool($tool, $course_code, $session_id = null)
4128
{
4129
    $course_info = api_get_course_info($course_code);
4130
    $tool = Database::escape_string($tool);
4131
4132
    // Definition of tables.
4133
    $item_property_table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4134
    $session_id = (int) $session_id;
4135
    $session_condition = ' AND session_id = '.$session_id;
4136
    if (empty($session_id)) {
4137
        $session_condition = " AND (session_id = 0 OR session_id IS NULL) ";
4138
    }
4139
    $course_id = $course_info['real_id'];
4140
4141
    $sql = "SELECT * FROM $item_property_table
4142
            WHERE
4143
                c_id = $course_id AND
4144
                tool = '$tool'
4145
                $session_condition ";
4146
    $rs = Database::query($sql);
4147
    $list = [];
4148
    if (Database::num_rows($rs) > 0) {
4149
        while ($row = Database::fetch_array($rs, 'ASSOC')) {
4150
            $list[] = $row;
4151
        }
4152
    }
4153
4154
    return $list;
4155
}
4156
4157
/**
4158
 * Gets item property by tool and user.
4159
 *
4160
 * @param int $userId
4161
 * @param int $tool
4162
 * @param int $courseId
4163
 * @param int $session_id
4164
 *
4165
 * @return array
4166
 */
4167
function api_get_item_property_list_by_tool_by_user(
4168
    $userId,
4169
    $tool,
4170
    $courseId,
4171
    $session_id = 0
4172
) {
4173
    $userId = intval($userId);
4174
    $tool = Database::escape_string($tool);
4175
    $session_id = intval($session_id);
4176
    $courseId = intval($courseId);
4177
4178
    // Definition of tables.
4179
    $item_property_table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4180
    $session_condition = ' AND session_id = '.$session_id;
4181
    if (empty($session_id)) {
4182
        $session_condition = " AND (session_id = 0 OR session_id IS NULL) ";
4183
    }
4184
    $sql = "SELECT * FROM $item_property_table
4185
            WHERE
4186
                insert_user_id = $userId AND
4187
                c_id = $courseId AND
4188
                tool = '$tool'
4189
                $session_condition ";
4190
4191
    $rs = Database::query($sql);
4192
    $list = [];
4193
    if (Database::num_rows($rs) > 0) {
4194
        while ($row = Database::fetch_array($rs, 'ASSOC')) {
4195
            $list[] = $row;
4196
        }
4197
    }
4198
4199
    return $list;
4200
}
4201
4202
/**
4203
 * Gets item property id from tool of a course.
4204
 *
4205
 * @param string $course_code course code
4206
 * @param string $tool        tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4207
 * @param int    $ref         id of the item itself, linked to key of every tool ('id', ...), "*" = all items of the tool
4208
 * @param int    $sessionId   Session ID (optional)
4209
 *
4210
 * @return int
4211
 */
4212
function api_get_item_property_id($course_code, $tool, $ref, $sessionId = 0)
4213
{
4214
    $course_info = api_get_course_info($course_code);
4215
    $tool = Database::escape_string($tool);
4216
    $ref = (int) $ref;
4217
4218
    // Definition of tables.
4219
    $tableItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
4220
    $course_id = $course_info['real_id'];
4221
    $sessionId = (int) $sessionId;
4222
    $sessionCondition = " AND session_id = $sessionId ";
4223
    if (empty($sessionId)) {
4224
        $sessionCondition = ' AND (session_id = 0 OR session_id IS NULL) ';
4225
    }
4226
    $sql = "SELECT id FROM $tableItemProperty
4227
            WHERE
4228
                c_id = $course_id AND
4229
                tool = '$tool' AND
4230
                ref = $ref
4231
                $sessionCondition";
4232
    $rs = Database::query($sql);
4233
    $item_property_id = '';
4234
    if (Database::num_rows($rs) > 0) {
4235
        $row = Database::fetch_array($rs);
4236
        $item_property_id = $row['id'];
4237
    }
4238
4239
    return $item_property_id;
4240
}
4241
4242
/**
4243
 * Inserts a record in the track_e_item_property table (No update).
4244
 *
4245
 * @param string $tool
4246
 * @param int    $ref
4247
 * @param string $title
4248
 * @param string $content
4249
 * @param int    $progress
4250
 *
4251
 * @return bool|int
4252
 */
4253
function api_track_item_property_update($tool, $ref, $title, $content, $progress)
4254
{
4255
    $tbl_stats_item_property = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ITEM_PROPERTY);
4256
    $course_id = api_get_course_int_id(); //numeric
4257
    $course_code = api_get_course_id(); //alphanumeric
4258
    $item_property_id = api_get_item_property_id($course_code, $tool, $ref);
4259
    if (!empty($item_property_id)) {
4260
        $sql = "INSERT IGNORE INTO $tbl_stats_item_property SET
4261
                course_id           = '$course_id',
4262
                item_property_id    = '$item_property_id',
4263
                title               = '".Database::escape_string($title)."',
4264
                content             = '".Database::escape_string($content)."',
4265
                progress            = '".intval($progress)."',
4266
                lastedit_date       = '".api_get_utc_datetime()."',
4267
                lastedit_user_id    = '".api_get_user_id()."',
4268
                session_id          = '".api_get_session_id()."'";
4269
        $result = Database::query($sql);
4270
        $affected_rows = Database::affected_rows($result);
4271
4272
        return $affected_rows;
4273
    }
4274
4275
    return false;
4276
}
4277
4278
/**
4279
 * @param string $tool
4280
 * @param int    $ref
4281
 *
4282
 * @return array|resource
4283
 */
4284
function api_get_track_item_property_history($tool, $ref)
4285
{
4286
    $tbl_stats_item_property = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ITEM_PROPERTY);
4287
    $course_id = api_get_course_int_id(); //numeric
4288
    $course_code = api_get_course_id(); //alphanumeric
4289
    $item_property_id = api_get_item_property_id($course_code, $tool, $ref);
4290
    $sql = "SELECT * FROM $tbl_stats_item_property
4291
            WHERE item_property_id = $item_property_id AND course_id = $course_id
4292
            ORDER BY lastedit_date DESC";
4293
    $result = Database::query($sql);
4294
    if (false === $result or null === $result) {
4295
        $result = [];
4296
    } else {
4297
        $result = Database::store_result($result, 'ASSOC');
4298
    }
4299
4300
    return $result;
4301
}
4302
4303
/**
4304
 * Gets item property data from tool of a course id.
4305
 *
4306
 * @param int    $course_id
4307
 * @param string $tool       tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4308
 * @param int    $ref        id of the item itself, linked to key of every tool ('id', ...), "*" = all items of the tool
4309
 * @param int    $session_id
4310
 * @param int    $groupId
4311
 *
4312
 * @return array with all fields from c_item_property, empty array if not found or false if course could not be found
4313
 */
4314
function api_get_item_property_info($course_id, $tool, $ref, $session_id = 0, $groupId = 0)
4315
{
4316
    $courseInfo = api_get_course_info_by_id($course_id);
4317
4318
    if (empty($courseInfo)) {
4319
        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...
4320
    }
4321
4322
    $tool = Database::escape_string($tool);
4323
    $course_id = $courseInfo['real_id'];
4324
    $ref = (int) $ref;
4325
    $session_id = (int) $session_id;
4326
4327
    $sessionCondition = " session_id = $session_id";
4328
    if (empty($session_id)) {
4329
        $sessionCondition = ' (session_id = 0 OR session_id IS NULL) ';
4330
    }
4331
4332
    // Definition of tables.
4333
    $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4334
4335
    $sql = "SELECT * FROM $table
4336
            WHERE
4337
                c_id = $course_id AND
4338
                tool = '$tool' AND
4339
                ref = $ref AND
4340
                $sessionCondition ";
4341
4342
    if (!empty($groupId)) {
4343
        $groupId = (int) $groupId;
4344
        $sql .= " AND to_group_id = $groupId ";
4345
    }
4346
4347
    $rs = Database::query($sql);
4348
    $row = [];
4349
    if (Database::num_rows($rs) > 0) {
4350
        $row = Database::fetch_array($rs, 'ASSOC');
4351
    }
4352
4353
    return $row;
4354
}
4355
4356
/**
4357
 * Displays a combo box so the user can select his/her preferred language.
4358
 *
4359
 * @param string The desired name= value for the select
4360
 * @param bool Whether we use the JQuery Chozen library or not
4361
 * (in some cases, like the indexing language picker, it can alter the presentation)
4362
 *
4363
 * @deprecated
4364
 *
4365
 * @return string
4366
 */
4367
function api_get_languages_combo($name = 'language')
4368
{
4369
    $ret = '';
4370
    $platformLanguage = api_get_setting('platformLanguage');
4371
4372
    // Retrieve a complete list of all the languages.
4373
    $language_list = api_get_languages();
4374
4375
    if (count($language_list) < 2) {
4376
        return $ret;
4377
    }
4378
4379
    // The the current language of the user so that his/her language occurs as selected in the dropdown menu.
4380
    if (isset($_SESSION['user_language_choice'])) {
4381
        $default = $_SESSION['user_language_choice'];
4382
    } else {
4383
        $default = $platformLanguage;
4384
    }
4385
4386
    $ret .= '<select name="'.$name.'" id="language_chosen" class="selectpicker show-tick form-control">';
4387
    foreach ($language_list as $key => $value) {
4388
        if ($key == $default) {
4389
            $selected = ' selected="selected"';
4390
        } else {
4391
            $selected = '';
4392
        }
4393
        $ret .= sprintf('<option value=%s" %s>%s</option>', $key, $selected, $value);
4394
    }
4395
    $ret .= '</select>';
4396
4397
    return $ret;
4398
}
4399
4400
/**
4401
 * Displays a form (drop down menu) so the user can select his/her preferred language.
4402
 * The form works with or without javascript.
4403
 *
4404
 * @param  bool Hide form if only one language available (defaults to false = show the box anyway)
4405
 * @param bool $showAsButton
4406
 *
4407
 * @return string|null Display the box directly
4408
 */
4409
function api_display_language_form($hide_if_no_choice = false, $showAsButton = false)
4410
{
4411
    // Retrieve a complete list of all the languages.
4412
    $language_list = api_get_languages();
4413
    if (count($language_list['name']) <= 1 && $hide_if_no_choice) {
4414
        return; //don't show any form
4415
    }
4416
4417
    // The the current language of the user so that his/her language occurs as selected in the dropdown menu.
4418
    if (isset($_SESSION['user_language_choice'])) {
4419
        $user_selected_language = $_SESSION['user_language_choice'];
4420
    }
4421
    if (empty($user_selected_language)) {
4422
        $user_selected_language = api_get_setting('platformLanguage');
4423
    }
4424
4425
    $currentLanguageId = api_get_language_id($user_selected_language);
4426
    $currentLanguageInfo = api_get_language_info($currentLanguageId);
4427
    $countryCode = languageToCountryIsoCode($currentLanguageInfo['isocode']);
4428
    $url = api_get_self();
4429
    if ($showAsButton) {
4430
        $html = '<div class="btn-group">
4431
              <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
4432
                <span class="flag-icon flag-icon-'.$countryCode.'"></span>
4433
                '.$currentLanguageInfo['original_name'].'
4434
                <span class="caret">
4435
                </span>
4436
              </button>';
4437
    } else {
4438
        $html = '
4439
            <a href="'.$url.'" class="dropdown-toggle" data-toggle="dropdown" role="button">
4440
                <span class="flag-icon flag-icon-'.$countryCode.'"></span>
4441
                '.$currentLanguageInfo['original_name'].'
4442
                <span class="caret"></span>
4443
            </a>
4444
            ';
4445
    }
4446
4447
    $html .= '<ul class="dropdown-menu" role="menu">';
4448
    foreach ($language_list['all'] as $key => $data) {
4449
        $urlLink = $url.'?language='.$data['english_name'];
4450
        $html .= '<li><a href="'.$urlLink.'"><span class="flag-icon flag-icon-'.languageToCountryIsoCode($data['isocode']).'"></span> '.$data['original_name'].'</a></li>';
4451
    }
4452
    $html .= '</ul>';
4453
4454
    if ($showAsButton) {
4455
        $html .= '</div>';
4456
    }
4457
4458
    return $html;
4459
}
4460
4461
/**
4462
 * @param string $languageIsoCode
4463
 *
4464
 * @return string
4465
 */
4466
function languageToCountryIsoCode($languageIsoCode)
4467
{
4468
    $allow = api_get_configuration_value('language_flags_by_country');
4469
4470
    // @todo save in DB
4471
    switch ($languageIsoCode) {
4472
        case 'ko':
4473
            $country = 'kr';
4474
            break;
4475
        case 'ja':
4476
            $country = 'jp';
4477
            break;
4478
        case 'ca':
4479
            $country = 'es';
4480
            if ($allow) {
4481
                $country = 'catalan';
4482
            }
4483
            break;
4484
        case 'gl': // galego
4485
            $country = 'es';
4486
            if ($allow) {
4487
                $country = 'galician';
4488
            }
4489
            break;
4490
        case 'ka':
4491
            $country = 'ge';
4492
            break;
4493
        case 'sl':
4494
            $country = 'si';
4495
            break;
4496
        case 'eu': // Euskera
4497
            $country = 'es';
4498
            if ($allow) {
4499
                $country = 'basque';
4500
            }
4501
            break;
4502
        case 'cs':
4503
            $country = 'cz';
4504
            break;
4505
        case 'el':
4506
            $country = 'ae';
4507
            break;
4508
        case 'ar':
4509
            $country = 'ae';
4510
            break;
4511
        case 'en_US':
4512
        case 'en':
4513
            $country = 'gb';
4514
            break;
4515
        case 'he':
4516
            $country = 'il';
4517
            break;
4518
        case 'uk': // Ukraine
4519
            $country = 'ua';
4520
            break;
4521
        case 'da':
4522
            $country = 'dk';
4523
            break;
4524
        case 'pt-BR':
4525
            $country = 'br';
4526
            break;
4527
        case 'qu':
4528
            $country = 'pe';
4529
            break;
4530
        case 'sv':
4531
            $country = 'se';
4532
            break;
4533
        case 'zh-TW':
4534
        case 'zh':
4535
            $country = 'cn';
4536
            break;
4537
        default:
4538
            $country = $languageIsoCode;
4539
            break;
4540
    }
4541
    $country = strtolower($country);
4542
4543
    return $country;
4544
}
4545
4546
/**
4547
 * Returns a list of all the languages that are made available by the admin.
4548
 *
4549
 * @return array An array with all languages. Structure of the array is
4550
 *               array['name'] = An array with the name of every language
4551
 *               array['folder'] = An array with the corresponding names of the language-folders in the filesystem
4552
 */
4553
function api_get_languages()
4554
{
4555
    $table = Database::get_main_table(TABLE_MAIN_LANGUAGE);
4556
    $sql = "SELECT * FROM $table WHERE available='1'
4557
            ORDER BY original_name ASC";
4558
    $result = Database::query($sql);
4559
    $languages = [];
4560
    while ($row = Database::fetch_array($result, 'ASSOC')) {
4561
        $languages[$row['isocode']] = $row['original_name'];
4562
    }
4563
4564
    return $languages;
4565
}
4566
4567
/**
4568
 * Returns a list of all the languages that are made available by the admin.
4569
 *
4570
 * @return array
4571
 */
4572
function api_get_languages_to_array()
4573
{
4574
    $tbl_language = Database::get_main_table(TABLE_MAIN_LANGUAGE);
4575
    $sql = "SELECT * FROM $tbl_language WHERE available='1' ORDER BY original_name ASC";
4576
    $result = Database::query($sql);
4577
    $languages = [];
4578
    while ($row = Database::fetch_array($result)) {
4579
        $languages[$row['dokeos_folder']] = $row['original_name'];
4580
    }
4581
4582
    return $languages;
4583
}
4584
4585
/**
4586
 * Returns the id (the database id) of a language.
4587
 *
4588
 * @param   string  language name (the corresponding name of the language-folder in the filesystem)
4589
 *
4590
 * @return int id of the language
4591
 */
4592
function api_get_language_id($language)
4593
{
4594
    $tbl_language = Database::get_main_table(TABLE_MAIN_LANGUAGE);
4595
    if (empty($language)) {
4596
        return null;
4597
    }
4598
    $language = Database::escape_string($language);
4599
    $sql = "SELECT id FROM $tbl_language
4600
            WHERE dokeos_folder = '$language' LIMIT 1";
4601
    $result = Database::query($sql);
4602
    $row = Database::fetch_array($result);
4603
4604
    return $row['id'];
4605
}
4606
4607
/**
4608
 * Get the language information by its id.
4609
 *
4610
 * @param int $languageId
4611
 *
4612
 * @throws Exception
4613
 *
4614
 * @return array
4615
 */
4616
function api_get_language_info($languageId)
4617
{
4618
    if (empty($languageId)) {
4619
        return [];
4620
    }
4621
4622
    $language = Database::getManager()
4623
        ->find('ChamiloCoreBundle:Language', $languageId);
4624
4625
    if (!$language) {
4626
        return [];
4627
    }
4628
4629
    return [
4630
        'id' => $language->getId(),
4631
        'original_name' => $language->getOriginalName(),
4632
        'english_name' => $language->getEnglishName(),
4633
        'isocode' => $language->getIsocode(),
4634
        'dokeos_folder' => $language->getDokeosFolder(),
4635
        'available' => $language->getAvailable(),
4636
        'parent_id' => $language->getParent() ? $language->getParent()->getId() : null,
4637
    ];
4638
}
4639
4640
/**
4641
 * @param string $code
4642
 *
4643
 * @return \Chamilo\CoreBundle\Entity\Language
4644
 */
4645
function api_get_language_from_iso($code)
4646
{
4647
    $em = Database::getManager();
4648
    $language = $em->getRepository('ChamiloCoreBundle:Language')->findOneBy(['isocode' => $code]);
4649
4650
    return $language;
4651
}
4652
4653
/**
4654
 * Returns the name of the visual (CSS) theme to be applied on the current page.
4655
 * The returned name depends on the platform, course or user -wide settings.
4656
 *
4657
 * @return string The visual theme's name, it is the name of a folder inside web/css/themes
4658
 */
4659
function api_get_visual_theme()
4660
{
4661
    static $visual_theme;
4662
    if (!isset($visual_theme)) {
4663
        // Get style directly from DB
4664
        $styleFromDatabase = api_get_settings_params_simple(
4665
            [
4666
                'variable = ? AND access_url = ?' => [
4667
                    'stylesheets',
4668
                    api_get_current_access_url_id(),
4669
                ],
4670
            ]
4671
        );
4672
        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...
4673
            $platform_theme = $styleFromDatabase['selected_value'];
4674
        } else {
4675
            $platform_theme = api_get_setting('stylesheets');
4676
        }
4677
4678
        // Platform's theme.
4679
        $visual_theme = $platform_theme;
4680
        if ('true' == api_get_setting('user_selected_theme')) {
4681
            $user_info = api_get_user_info();
4682
            if (isset($user_info['theme'])) {
4683
                $user_theme = $user_info['theme'];
4684
4685
                if (!empty($user_theme)) {
4686
                    $visual_theme = $user_theme;
4687
                    // User's theme.
4688
                }
4689
            }
4690
        }
4691
4692
        $course_id = api_get_course_id();
4693
        if (!empty($course_id)) {
4694
            if ('true' == api_get_setting('allow_course_theme')) {
4695
                $course_theme = api_get_course_setting('course_theme', $course_id);
4696
4697
                if (!empty($course_theme) && -1 != $course_theme) {
4698
                    if (!empty($course_theme)) {
4699
                        // Course's theme.
4700
                        $visual_theme = $course_theme;
4701
                    }
4702
                }
4703
4704
                $allow_lp_theme = api_get_course_setting('allow_learning_path_theme');
4705
                if (1 == $allow_lp_theme) {
4706
                    global $lp_theme_css, $lp_theme_config;
4707
                    // These variables come from the file lp_controller.php.
4708
                    if (!$lp_theme_config) {
4709
                        if (!empty($lp_theme_css)) {
4710
                            // LP's theme.
4711
                            $visual_theme = $lp_theme_css;
4712
                        }
4713
                    }
4714
                }
4715
            }
4716
        }
4717
4718
        if (empty($visual_theme)) {
4719
            $visual_theme = 'chamilo';
4720
        }
4721
4722
        global $lp_theme_log;
4723
        if ($lp_theme_log) {
4724
            $visual_theme = $platform_theme;
4725
        }
4726
    }
4727
4728
    return $visual_theme;
4729
}
4730
4731
/**
4732
 * Returns a list of CSS themes currently available in the CSS folder
4733
 * The folder must have a default.css file.
4734
 *
4735
 * @param bool $getOnlyThemeFromVirtualInstance Used by the vchamilo plugin
4736
 *
4737
 * @return array list of themes directories from the css folder
4738
 *               Note: Directory names (names of themes) in the file system should contain ASCII-characters only
4739
 */
4740
function api_get_themes($getOnlyThemeFromVirtualInstance = false)
4741
{
4742
    // This configuration value is set by the vchamilo plugin
4743
    $virtualTheme = api_get_configuration_value('virtual_css_theme_folder');
4744
4745
    $readCssFolder = function ($dir) use ($virtualTheme) {
4746
        $finder = new Finder();
4747
        $themes = $finder->directories()->in($dir)->depth(0)->sortByName();
4748
        $list = [];
4749
        /** @var Symfony\Component\Finder\SplFileInfo $theme */
4750
        foreach ($themes as $theme) {
4751
            $folder = $theme->getFilename();
4752
            // A theme folder is consider if there's a default.css file
4753
            if (!file_exists($theme->getPathname().'/default.css')) {
4754
                continue;
4755
            }
4756
            $name = ucwords(str_replace('_', ' ', $folder));
4757
            if ($folder == $virtualTheme) {
4758
                continue;
4759
            }
4760
            $list[$folder] = $name;
4761
        }
4762
4763
        return $list;
4764
    };
4765
4766
    $dir = api_get_path(SYS_CSS_PATH).'themes/';
4767
    $list = $readCssFolder($dir);
4768
4769
    if (!empty($virtualTheme)) {
4770
        $newList = $readCssFolder($dir.'/'.$virtualTheme);
4771
        if ($getOnlyThemeFromVirtualInstance) {
4772
            return $newList;
4773
        }
4774
        $list = $list + $newList;
4775
        asort($list);
4776
    }
4777
4778
    return $list;
4779
}
4780
4781
/**
4782
 * Find the largest sort value in a given user_course_category
4783
 * This function is used when we are moving a course to a different category
4784
 * and also when a user subscribes to courses (the new course is added at the end of the main category.
4785
 *
4786
 * @author Patrick Cool <[email protected]>, Ghent University
4787
 *
4788
 * @param int $user_course_category the id of the user_course_category
4789
 * @param int $user_id
4790
 *
4791
 * @return int the value of the highest sort of the user_course_category
4792
 */
4793
function api_max_sort_value($user_course_category, $user_id)
4794
{
4795
    $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4796
    $sql = "SELECT max(sort) as max_sort FROM $tbl_course_user
4797
            WHERE
4798
                user_id='".intval($user_id)."' AND
4799
                relation_type<>".COURSE_RELATION_TYPE_RRHH." AND
4800
                user_course_cat='".intval($user_course_category)."'";
4801
    $result_max = Database::query($sql);
4802
    if (1 == Database::num_rows($result_max)) {
4803
        $row_max = Database::fetch_array($result_max);
4804
4805
        return $row_max['max_sort'];
4806
    }
4807
4808
    return 0;
4809
}
4810
4811
/**
4812
 * Transforms a number of seconds in hh:mm:ss format.
4813
 *
4814
 * @author Julian Prud'homme
4815
 *
4816
 * @param int    $seconds      number of seconds
4817
 * @param string $space
4818
 * @param bool   $showSeconds
4819
 * @param bool   $roundMinutes
4820
 *
4821
 * @return string the formatted time
4822
 */
4823
function api_time_to_hms($seconds, $space = ':', $showSeconds = true, $roundMinutes = false)
4824
{
4825
    // $seconds = -1 means that we have wrong data in the db.
4826
    if (-1 == $seconds) {
4827
        return
4828
            get_lang('Unknown').
4829
            Display::return_icon(
4830
                'info2.gif',
4831
                get_lang('The datas about this user were registered when the calculation of time spent on the platform wasn\'t possible.'),
4832
                ['align' => 'absmiddle', 'hspace' => '3px']
4833
            );
4834
    }
4835
4836
    // How many hours ?
4837
    $hours = floor($seconds / 3600);
4838
4839
    // How many minutes ?
4840
    $min = floor(($seconds - ($hours * 3600)) / 60);
4841
4842
    if ($roundMinutes) {
4843
        if ($min >= 45) {
4844
            $min = 45;
4845
        }
4846
4847
        if ($min >= 30 && $min <= 44) {
4848
            $min = 30;
4849
        }
4850
4851
        if ($min >= 15 && $min <= 29) {
4852
            $min = 15;
4853
        }
4854
4855
        if ($min >= 0 && $min <= 14) {
4856
            $min = 0;
4857
        }
4858
    }
4859
4860
    // How many seconds
4861
    $sec = floor($seconds - ($hours * 3600) - ($min * 60));
4862
4863
    if ($hours < 10) {
4864
        $hours = "0$hours";
4865
    }
4866
4867
    if ($sec < 10) {
4868
        $sec = "0$sec";
4869
    }
4870
4871
    if ($min < 10) {
4872
        $min = "0$min";
4873
    }
4874
4875
    $seconds = '';
4876
    if ($showSeconds) {
4877
        $seconds = $space.$sec;
4878
    }
4879
4880
    return $hours.$space.$min.$seconds;
4881
}
4882
4883
/* FILE SYSTEM RELATED FUNCTIONS */
4884
4885
/**
4886
 * Returns the permissions to be assigned to every newly created directory by the web-server.
4887
 * The return value is based on the platform administrator's setting
4888
 * "Administration > Configuration settings > Security > Permissions for new directories".
4889
 *
4890
 * @return int returns the permissions in the format "Owner-Group-Others, Read-Write-Execute", as an integer value
4891
 */
4892
function api_get_permissions_for_new_directories()
4893
{
4894
    static $permissions;
4895
    if (!isset($permissions)) {
4896
        $permissions = trim(api_get_setting('permissions_for_new_directories'));
4897
        // The default value 0777 is according to that in the platform administration panel after fresh system installation.
4898
        $permissions = octdec(!empty($permissions) ? $permissions : '0777');
4899
    }
4900
4901
    return $permissions;
4902
}
4903
4904
/**
4905
 * Returns the permissions to be assigned to every newly created directory by the web-server.
4906
 * The return value is based on the platform administrator's setting
4907
 * "Administration > Configuration settings > Security > Permissions for new files".
4908
 *
4909
 * @return int returns the permissions in the format
4910
 *             "Owner-Group-Others, Read-Write-Execute", as an integer value
4911
 */
4912
function api_get_permissions_for_new_files()
4913
{
4914
    static $permissions;
4915
    if (!isset($permissions)) {
4916
        $permissions = trim(api_get_setting('permissions_for_new_files'));
4917
        // The default value 0666 is according to that in the platform
4918
        // administration panel after fresh system installation.
4919
        $permissions = octdec(!empty($permissions) ? $permissions : '0666');
4920
    }
4921
4922
    return $permissions;
4923
}
4924
4925
/**
4926
 * Deletes a file, or a folder and its contents.
4927
 *
4928
 * @author      Aidan Lister <[email protected]>
4929
 *
4930
 * @version     1.0.3
4931
 *
4932
 * @param string $dirname Directory to delete
4933
 * @param       bool     Deletes only the content or not
4934
 * @param bool $strict if one folder/file fails stop the loop
4935
 *
4936
 * @return bool Returns TRUE on success, FALSE on failure
4937
 *
4938
 * @see http://aidanlister.com/2004/04/recursively-deleting-a-folder-in-php/
4939
 *
4940
 * @author      Yannick Warnier, adaptation for the Chamilo LMS, April, 2008
4941
 * @author      Ivan Tcholakov, a sanity check about Directory class creation has been added, September, 2009
4942
 */
4943
function rmdirr($dirname, $delete_only_content_in_folder = false, $strict = false)
4944
{
4945
    $res = true;
4946
    // A sanity check.
4947
    if (!file_exists($dirname)) {
4948
        return false;
4949
    }
4950
    $php_errormsg = '';
4951
    // Simple delete for a file.
4952
    if (is_file($dirname) || is_link($dirname)) {
4953
        $res = unlink($dirname);
4954
        if (false === $res) {
4955
            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);
4956
        }
4957
4958
        return $res;
4959
    }
4960
4961
    // Loop through the folder.
4962
    $dir = dir($dirname);
4963
    // A sanity check.
4964
    $is_object_dir = is_object($dir);
4965
    if ($is_object_dir) {
4966
        while (false !== $entry = $dir->read()) {
4967
            // Skip pointers.
4968
            if ('.' == $entry || '..' == $entry) {
4969
                continue;
4970
            }
4971
4972
            // Recurse.
4973
            if ($strict) {
4974
                $result = rmdirr("$dirname/$entry");
4975
                if (false == $result) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

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

Loading history...
4976
                    $res = false;
4977
                    break;
4978
                }
4979
            } else {
4980
                rmdirr("$dirname/$entry");
4981
            }
4982
        }
4983
    }
4984
4985
    // Clean up.
4986
    if ($is_object_dir) {
4987
        $dir->close();
4988
    }
4989
4990
    if (false == $delete_only_content_in_folder) {
4991
        $res = rmdir($dirname);
4992
        if (false === $res) {
4993
            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);
4994
        }
4995
    }
4996
4997
    return $res;
4998
}
4999
5000
// TODO: This function is to be simplified. File access modes to be implemented.
5001
/**
5002
 * function adapted from a php.net comment
5003
 * copy recursively a folder.
5004
 *
5005
 * @param the source folder
5006
 * @param the dest folder
5007
 * @param an array of excluded file_name (without extension)
5008
 * @param copied_files the returned array of copied files
5009
 * @param string $source
5010
 * @param string $dest
5011
 */
5012
function copyr($source, $dest, $exclude = [], $copied_files = [])
5013
{
5014
    if (empty($dest)) {
5015
        return false;
5016
    }
5017
    // Simple copy for a file
5018
    if (is_file($source)) {
5019
        $path_info = pathinfo($source);
5020
        if (!in_array($path_info['filename'], $exclude)) {
5021
            copy($source, $dest);
5022
        }
5023
5024
        return true;
5025
    } elseif (!is_dir($source)) {
5026
        //then source is not a dir nor a file, return
5027
        return false;
5028
    }
5029
5030
    // Make destination directory.
5031
    if (!is_dir($dest)) {
5032
        mkdir($dest, api_get_permissions_for_new_directories());
5033
    }
5034
5035
    // Loop through the folder.
5036
    $dir = dir($source);
5037
    while (false !== $entry = $dir->read()) {
5038
        // Skip pointers
5039
        if ('.' == $entry || '..' == $entry) {
5040
            continue;
5041
        }
5042
5043
        // Deep copy directories.
5044
        if ($dest !== "$source/$entry") {
5045
            $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

5045
            $files = copyr("$source/$entry", "$dest/$entry", $exclude, /** @scrutinizer ignore-type */ $copied_files);
Loading history...
5046
        }
5047
    }
5048
    // Clean up.
5049
    $dir->close();
5050
5051
    return true;
5052
}
5053
5054
/**
5055
 * @todo: Using DIRECTORY_SEPARATOR is not recommended, this is an obsolete approach.
5056
 * Documentation header to be added here.
5057
 *
5058
 * @param string $pathname
5059
 * @param string $base_path_document
5060
 * @param int    $session_id
5061
 *
5062
 * @return mixed True if directory already exists, false if a file already exists at
5063
 *               the destination and null if everything goes according to plan
5064
 */
5065
function copy_folder_course_session(
5066
    $pathname,
5067
    $base_path_document,
5068
    $session_id,
5069
    $course_info,
5070
    $document,
5071
    $source_course_id
5072
) {
5073
    $table = Database::get_course_table(TABLE_DOCUMENT);
5074
    $session_id = intval($session_id);
5075
    $source_course_id = intval($source_course_id);
5076
5077
    // Check whether directory already exists.
5078
    if (is_dir($pathname) || empty($pathname)) {
5079
        return true;
5080
    }
5081
5082
    // Ensure that a file with the same name does not already exist.
5083
    if (is_file($pathname)) {
5084
        trigger_error('copy_folder_course_session(): File exists', E_USER_WARNING);
5085
5086
        return false;
5087
    }
5088
5089
    $course_id = $course_info['real_id'];
5090
    $folders = explode(DIRECTORY_SEPARATOR, str_replace($base_path_document.DIRECTORY_SEPARATOR, '', $pathname));
5091
    $new_pathname = $base_path_document;
5092
    $path = '';
5093
5094
    foreach ($folders as $folder) {
5095
        $new_pathname .= DIRECTORY_SEPARATOR.$folder;
5096
        $path .= DIRECTORY_SEPARATOR.$folder;
5097
5098
        if (!file_exists($new_pathname)) {
5099
            $path = Database::escape_string($path);
5100
5101
            $sql = "SELECT * FROM $table
5102
                    WHERE
5103
                        c_id = $source_course_id AND
5104
                        path = '$path' AND
5105
                        filetype = 'folder' AND
5106
                        session_id = '$session_id'";
5107
            $rs1 = Database::query($sql);
5108
            $num_rows = Database::num_rows($rs1);
5109
5110
            if (0 == $num_rows) {
5111
                mkdir($new_pathname, api_get_permissions_for_new_directories());
5112
5113
                // Insert new folder with destination session_id.
5114
                $params = [
5115
                    'c_id' => $course_id,
5116
                    'path' => $path,
5117
                    'comment' => $document->comment,
5118
                    'title' => basename($new_pathname),
5119
                    'filetype' => 'folder',
5120
                    'size' => '0',
5121
                    'session_id' => $session_id,
5122
                ];
5123
                $document_id = Database::insert($table, $params);
5124
                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...
5125
                    $sql = "UPDATE $table SET id = iid WHERE iid = $document_id";
5126
                    Database::query($sql);
5127
5128
                    api_item_property_update(
5129
                        $course_info,
5130
                        TOOL_DOCUMENT,
5131
                        $document_id,
5132
                        'FolderCreated',
5133
                        api_get_user_id(),
5134
                        0,
5135
                        0,
5136
                        null,
5137
                        null,
5138
                        $session_id
5139
                    );
5140
                }
5141
            }
5142
        }
5143
    } // en foreach
5144
}
5145
5146
// TODO: chmodr() is a better name. Some corrections are needed. Documentation header to be added here.
5147
/**
5148
 * @param string $path
5149
 */
5150
function api_chmod_R($path, $filemode)
5151
{
5152
    if (!is_dir($path)) {
5153
        return chmod($path, $filemode);
5154
    }
5155
5156
    $handler = opendir($path);
5157
    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

5157
    while ($file = readdir(/** @scrutinizer ignore-type */ $handler)) {
Loading history...
5158
        if ('.' != $file && '..' != $file) {
5159
            $fullpath = "$path/$file";
5160
            if (!is_dir($fullpath)) {
5161
                if (!chmod($fullpath, $filemode)) {
5162
                    return false;
5163
                }
5164
            } else {
5165
                if (!api_chmod_R($fullpath, $filemode)) {
5166
                    return false;
5167
                }
5168
            }
5169
        }
5170
    }
5171
5172
    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

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

5273
            $last = array_pop(/** @scrutinizer ignore-type */ $keys);
Loading history...
5274
            $parent = &$info;
5275
5276
            // Create nested arrays.
5277
            foreach ($keys as $key) {
5278
                if ('' == $key) {
5279
                    $key = count($parent);
5280
                }
5281
                if (!isset($parent[$key]) || !is_array($parent[$key])) {
5282
                    $parent[$key] = [];
5283
                }
5284
                $parent = &$parent[$key];
5285
            }
5286
5287
            // Handle PHP constants.
5288
            if (defined($value)) {
5289
                $value = constant($value);
5290
            }
5291
5292
            // Insert actual value.
5293
            if ('' == $last) {
5294
                $last = count($parent);
5295
            }
5296
            $parent[$last] = $value;
5297
        }
5298
    }
5299
5300
    return $info;
5301
}
5302
5303
/**
5304
 * Gets Chamilo version from the configuration files.
5305
 *
5306
 * @return string A string of type "1.8.4", or an empty string if the version could not be found
5307
 */
5308
function api_get_version()
5309
{
5310
    return (string) api_get_configuration_value('system_version');
5311
}
5312
5313
/**
5314
 * Gets the software name (the name/brand of the Chamilo-based customized system).
5315
 *
5316
 * @return string
5317
 */
5318
function api_get_software_name()
5319
{
5320
    $name = api_get_configuration_value('software_name');
5321
    if (!empty($name)) {
5322
        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...
5323
    } else {
5324
        return 'Chamilo';
5325
    }
5326
}
5327
5328
function api_get_status_list()
5329
{
5330
    $list = [];
5331
    // Table of status
5332
    $list[COURSEMANAGER] = 'teacher'; // 1
5333
    $list[SESSIONADMIN] = 'session_admin'; // 3
5334
    $list[DRH] = 'drh'; // 4
5335
    $list[STUDENT] = 'user'; // 5
5336
    $list[ANONYMOUS] = 'anonymous'; // 6
5337
    $list[INVITEE] = 'invited'; // 20
5338
5339
    return $list;
5340
}
5341
5342
/**
5343
 * Checks whether status given in parameter exists in the platform.
5344
 *
5345
 * @param mixed the status (can be either int either string)
5346
 *
5347
 * @return bool if the status exists, else returns false
5348
 */
5349
function api_status_exists($status_asked)
5350
{
5351
    $list = api_get_status_list();
5352
5353
    return in_array($status_asked, $list) ? true : isset($list[$status_asked]);
5354
}
5355
5356
/**
5357
 * Checks whether status given in parameter exists in the platform. The function
5358
 * returns the status ID or false if it does not exist, but given the fact there
5359
 * is no "0" status, the return value can be checked against
5360
 * if(api_status_key()) to know if it exists.
5361
 *
5362
 * @param   mixed   The status (can be either int or string)
5363
 *
5364
 * @return mixed Status ID if exists, false otherwise
5365
 */
5366
function api_status_key($status)
5367
{
5368
    $list = api_get_status_list();
5369
5370
    return isset($list[$status]) ? $status : array_search($status, $list);
5371
}
5372
5373
/**
5374
 * Gets the status langvars list.
5375
 *
5376
 * @return string[] the list of status with their translations
5377
 */
5378
function api_get_status_langvars()
5379
{
5380
    return [
5381
        COURSEMANAGER => get_lang('Teacher'),
5382
        SESSIONADMIN => get_lang('SessionsAdmin'),
5383
        DRH => get_lang('Human Resources Manager'),
5384
        STUDENT => get_lang('Learner'),
5385
        ANONYMOUS => get_lang('Anonymous'),
5386
        STUDENT_BOSS => get_lang('RoleStudentBoss'),
5387
        INVITEE => get_lang('Invited'),
5388
    ];
5389
}
5390
5391
/**
5392
 * The function that retrieves all the possible settings for a certain config setting.
5393
 *
5394
 * @author Patrick Cool <[email protected]>, Ghent University
5395
 */
5396
function api_get_settings_options($var)
5397
{
5398
    $table_settings_options = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
5399
    $var = Database::escape_string($var);
5400
    $sql = "SELECT * FROM $table_settings_options
5401
            WHERE variable = '$var'
5402
            ORDER BY id";
5403
    $result = Database::query($sql);
5404
    $settings_options_array = [];
5405
    while ($row = Database::fetch_array($result, 'ASSOC')) {
5406
        $settings_options_array[] = $row;
5407
    }
5408
5409
    return $settings_options_array;
5410
}
5411
5412
/**
5413
 * @param array $params
5414
 */
5415
function api_set_setting_option($params)
5416
{
5417
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
5418
    if (empty($params['id'])) {
5419
        Database::insert($table, $params);
5420
    } else {
5421
        Database::update($table, $params, ['id = ? ' => $params['id']]);
5422
    }
5423
}
5424
5425
/**
5426
 * @param array $params
5427
 */
5428
function api_set_setting_simple($params)
5429
{
5430
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5431
    $url_id = api_get_current_access_url_id();
5432
5433
    if (empty($params['id'])) {
5434
        $params['access_url'] = $url_id;
5435
        Database::insert($table, $params);
5436
    } else {
5437
        Database::update($table, $params, ['id = ? ' => [$params['id']]]);
5438
    }
5439
}
5440
5441
/**
5442
 * @param int $id
5443
 */
5444
function api_delete_setting_option($id)
5445
{
5446
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
5447
    if (!empty($id)) {
5448
        Database::delete($table, ['id = ? ' => $id]);
5449
    }
5450
}
5451
5452
/**
5453
 * Sets a platform configuration setting to a given value.
5454
 *
5455
 * @param string    The variable we want to update
5456
 * @param string    The value we want to record
5457
 * @param string    The sub-variable if any (in most cases, this will remain null)
5458
 * @param string    The category if any (in most cases, this will remain null)
5459
 * @param int       The access_url for which this parameter is valid
5460
 * @param string $cat
5461
 *
5462
 * @return bool|null
5463
 */
5464
function api_set_setting($var, $value, $subvar = null, $cat = null, $access_url = 1)
5465
{
5466
    if (empty($var)) {
5467
        return false;
5468
    }
5469
    $t_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5470
    $var = Database::escape_string($var);
5471
    $value = Database::escape_string($value);
5472
    $access_url = (int) $access_url;
5473
    if (empty($access_url)) {
5474
        $access_url = 1;
5475
    }
5476
    $select = "SELECT id FROM $t_settings WHERE variable = '$var' ";
5477
    if (!empty($subvar)) {
5478
        $subvar = Database::escape_string($subvar);
5479
        $select .= " AND subkey = '$subvar'";
5480
    }
5481
    if (!empty($cat)) {
5482
        $cat = Database::escape_string($cat);
5483
        $select .= " AND category = '$cat'";
5484
    }
5485
    if ($access_url > 1) {
5486
        $select .= " AND access_url = $access_url";
5487
    } else {
5488
        $select .= " AND access_url = 1 ";
5489
    }
5490
5491
    $res = Database::query($select);
5492
    if (Database::num_rows($res) > 0) {
5493
        // Found item for this access_url.
5494
        $row = Database::fetch_array($res);
5495
        $sql = "UPDATE $t_settings SET selected_value = '$value'
5496
                WHERE id = ".$row['id'];
5497
        Database::query($sql);
5498
    } else {
5499
        // Item not found for this access_url, we have to check if it exist with access_url = 1
5500
        $select = "SELECT * FROM $t_settings
5501
                   WHERE variable = '$var' AND access_url = 1 ";
5502
        // Just in case
5503
        if (1 == $access_url) {
5504
            if (!empty($subvar)) {
5505
                $select .= " AND subkey = '$subvar'";
5506
            }
5507
            if (!empty($cat)) {
5508
                $select .= " AND category = '$cat'";
5509
            }
5510
            $res = Database::query($select);
5511
            if (Database::num_rows($res) > 0) {
5512
                // We have a setting for access_url 1, but none for the current one, so create one.
5513
                $row = Database::fetch_array($res);
5514
                $insert = "INSERT INTO $t_settings (variable, subkey, type,category, selected_value, title, comment, scope, subkeytext, access_url)
5515
                        VALUES
5516
                        ('".$row['variable']."',".(!empty($row['subkey']) ? "'".$row['subkey']."'" : "NULL").",".
5517
                    "'".$row['type']."','".$row['category']."',".
5518
                    "'$value','".$row['title']."',".
5519
                    "".(!empty($row['comment']) ? "'".$row['comment']."'" : "NULL").",".(!empty($row['scope']) ? "'".$row['scope']."'" : "NULL").",".
5520
                    "".(!empty($row['subkeytext']) ? "'".$row['subkeytext']."'" : "NULL").",$access_url)";
5521
                Database::query($insert);
5522
            } else {
5523
                // Such a setting does not exist.
5524
                //error_log(__FILE__.':'.__LINE__.': Attempting to update setting '.$var.' ('.$subvar.') which does not exist at all', 0);
5525
            }
5526
        } else {
5527
            // Other access url.
5528
            if (!empty($subvar)) {
5529
                $select .= " AND subkey = '$subvar'";
5530
            }
5531
            if (!empty($cat)) {
5532
                $select .= " AND category = '$cat'";
5533
            }
5534
            $res = Database::query($select);
5535
5536
            if (Database::num_rows($res) > 0) {
5537
                // We have a setting for access_url 1, but none for the current one, so create one.
5538
                $row = Database::fetch_array($res);
5539
                if (1 == $row['access_url_changeable']) {
5540
                    $insert = "INSERT INTO $t_settings (variable,subkey, type,category, selected_value,title, comment,scope, subkeytext,access_url, access_url_changeable) VALUES
5541
                            ('".$row['variable']."',".
5542
                        (!empty($row['subkey']) ? "'".$row['subkey']."'" : "NULL").",".
5543
                        "'".$row['type']."','".$row['category']."',".
5544
                        "'$value','".$row['title']."',".
5545
                        "".(!empty($row['comment']) ? "'".$row['comment']."'" : "NULL").",".
5546
                        (!empty($row['scope']) ? "'".$row['scope']."'" : "NULL").",".
5547
                        "".(!empty($row['subkeytext']) ? "'".$row['subkeytext']."'" : "NULL").",$access_url,".$row['access_url_changeable'].")";
5548
                    Database::query($insert);
5549
                }
5550
            } else { // Such a setting does not exist.
5551
                //error_log(__FILE__.':'.__LINE__.': Attempting to update setting '.$var.' ('.$subvar.') which does not exist at all. The access_url is: '.$access_url.' ',0);
5552
            }
5553
        }
5554
    }
5555
}
5556
5557
/**
5558
 * Sets a whole category of settings to one specific value.
5559
 *
5560
 * @param string    Category
5561
 * @param string    Value
5562
 * @param int       Access URL. Optional. Defaults to 1
5563
 * @param array     Optional array of filters on field type
5564
 * @param string $category
5565
 * @param string $value
5566
 *
5567
 * @return bool
5568
 */
5569
function api_set_settings_category($category, $value = null, $access_url = 1, $fieldtype = [])
5570
{
5571
    if (empty($category)) {
5572
        return false;
5573
    }
5574
    $category = Database::escape_string($category);
5575
    $t_s = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5576
    $access_url = (int) $access_url;
5577
    if (empty($access_url)) {
5578
        $access_url = 1;
5579
    }
5580
    if (isset($value)) {
5581
        $value = Database::escape_string($value);
5582
        $sql = "UPDATE $t_s SET selected_value = '$value'
5583
                WHERE category = '$category' AND access_url = $access_url";
5584
        if (is_array($fieldtype) && count($fieldtype) > 0) {
5585
            $sql .= " AND ( ";
5586
            $i = 0;
5587
            foreach ($fieldtype as $type) {
5588
                if ($i > 0) {
5589
                    $sql .= ' OR ';
5590
                }
5591
                $type = Database::escape_string($type);
5592
                $sql .= " type='".$type."' ";
5593
                $i++;
5594
            }
5595
            $sql .= ")";
5596
        }
5597
        $res = Database::query($sql);
5598
5599
        return false !== $res;
5600
    } else {
5601
        $sql = "UPDATE $t_s SET selected_value = NULL
5602
                WHERE category = '$category' AND access_url = $access_url";
5603
        if (is_array($fieldtype) && count($fieldtype) > 0) {
5604
            $sql .= " AND ( ";
5605
            $i = 0;
5606
            foreach ($fieldtype as $type) {
5607
                if ($i > 0) {
5608
                    $sql .= ' OR ';
5609
                }
5610
                $type = Database::escape_string($type);
5611
                $sql .= " type='".$type."' ";
5612
                $i++;
5613
            }
5614
            $sql .= ")";
5615
        }
5616
        $res = Database::query($sql);
5617
5618
        return false !== $res;
5619
    }
5620
}
5621
5622
/**
5623
 * Gets all available access urls in an array (as in the database).
5624
 *
5625
 * @return array An array of database records
5626
 */
5627
function api_get_access_urls($from = 0, $to = 1000000, $order = 'url', $direction = 'ASC')
5628
{
5629
    $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5630
    $from = (int) $from;
5631
    $to = (int) $to;
5632
    $order = Database::escape_string($order, null, false);
5633
    $direction = Database::escape_string($direction, null, false);
5634
    $sql = "SELECT id, url, description, active, created_by, tms
5635
            FROM $table
5636
            ORDER BY $order $direction
5637
            LIMIT $to OFFSET $from";
5638
    $res = Database::query($sql);
5639
5640
    return Database::store_result($res);
5641
}
5642
5643
/**
5644
 * Gets the access url info in an array.
5645
 *
5646
 * @param int  $id            Id of the access url
5647
 * @param bool $returnDefault Set to false if you want the real URL if URL 1 is still 'http://localhost/'
5648
 *
5649
 * @return array All the info (url, description, active, created_by, tms)
5650
 *               from the access_url table
5651
 *
5652
 * @author Julio Montoya
5653
 */
5654
function api_get_access_url($id, $returnDefault = true)
5655
{
5656
    static $staticResult;
5657
    $id = (int) $id;
5658
5659
    if (isset($staticResult[$id])) {
5660
        $result = $staticResult[$id];
5661
    } else {
5662
        // Calling the Database:: library dont work this is handmade.
5663
        $table_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5664
        $sql = "SELECT url, description, active, created_by, tms
5665
                FROM $table_access_url WHERE id = '$id' ";
5666
        $res = Database::query($sql);
5667
        $result = @Database::fetch_array($res);
5668
        $staticResult[$id] = $result;
5669
    }
5670
5671
    // If the result url is 'http://localhost/' (the default) and the root_web
5672
    // (=current url) is different, and the $id is = 1 (which might mean
5673
    // api_get_current_access_url_id() returned 1 by default), then return the
5674
    // root_web setting instead of the current URL
5675
    // This is provided as an option to avoid breaking the storage of URL-specific
5676
    // homepages in home/localhost/
5677
    if (1 === $id && false === $returnDefault) {
5678
        $currentUrl = api_get_current_access_url_id();
5679
        // only do this if we are on the main URL (=1), otherwise we could get
5680
        // information on another URL instead of the one asked as parameter
5681
        if (1 === $currentUrl) {
5682
            $rootWeb = api_get_path(WEB_PATH);
5683
            $default = 'http://localhost/';
5684
            if ($result['url'] === $default && $rootWeb != $default) {
5685
                $result['url'] = $rootWeb;
5686
            }
5687
        }
5688
    }
5689
5690
    return $result;
5691
}
5692
5693
/**
5694
 * Gets all the current settings for a specific access url.
5695
 *
5696
 * @param string    The category, if any, that we want to get
5697
 * @param string    Whether we want a simple list (display a category) or
5698
 * a grouped list (group by variable as in settings.php default). Values: 'list' or 'group'
5699
 * @param int       Access URL's ID. Optional. Uses 1 by default, which is the unique URL
5700
 *
5701
 * @return array Array of database results for the current settings of the current access URL
5702
 */
5703
function &api_get_settings($cat = null, $ordering = 'list', $access_url = 1, $url_changeable = 0)
5704
{
5705
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5706
    $access_url = (int) $access_url;
5707
    $where_condition = '';
5708
    if (1 == $url_changeable) {
5709
        $where_condition = " AND access_url_changeable= '1' ";
5710
    }
5711
    if (empty($access_url) || -1 == $access_url) {
5712
        $access_url = 1;
5713
    }
5714
    $sql = "SELECT * FROM $table
5715
            WHERE access_url = $access_url  $where_condition ";
5716
5717
    if (!empty($cat)) {
5718
        $cat = Database::escape_string($cat);
5719
        $sql .= " AND category='$cat' ";
5720
    }
5721
    if ('group' == $ordering) {
5722
        $sql .= " ORDER BY id ASC";
5723
    } else {
5724
        $sql .= " ORDER BY 1,2 ASC";
5725
    }
5726
    $result = Database::query($sql);
5727
    if (null === $result) {
5728
        return [];
5729
    }
5730
    $result = Database::store_result($result, 'ASSOC');
5731
5732
    return $result;
5733
}
5734
5735
/**
5736
 * @param string $value       The value we want to record
5737
 * @param string $variable    The variable name we want to insert
5738
 * @param string $subKey      The subkey for the variable we want to insert
5739
 * @param string $type        The type for the variable we want to insert
5740
 * @param string $category    The category for the variable we want to insert
5741
 * @param string $title       The title
5742
 * @param string $comment     The comment
5743
 * @param string $scope       The scope
5744
 * @param string $subKeyText  The subkey text
5745
 * @param int    $accessUrlId The access_url for which this parameter is valid
5746
 * @param int    $visibility  The changeability of this setting for non-master urls
5747
 *
5748
 * @return int The setting ID
5749
 */
5750
function api_add_setting(
5751
    $value,
5752
    $variable,
5753
    $subKey = '',
5754
    $type = 'textfield',
5755
    $category = '',
5756
    $title = '',
5757
    $comment = '',
5758
    $scope = '',
5759
    $subKeyText = '',
5760
    $accessUrlId = 1,
5761
    $visibility = 0
5762
) {
5763
    $em = Database::getManager();
5764
    $settingRepo = $em->getRepository('ChamiloCoreBundle:SettingsCurrent');
5765
    $accessUrlId = (int) $accessUrlId ?: 1;
5766
5767
    if (is_array($value)) {
5768
        $value = serialize($value);
5769
    } else {
5770
        $value = trim($value);
5771
    }
5772
5773
    $criteria = ['variable' => $variable, 'url' => $accessUrlId];
5774
5775
    if (!empty($subKey)) {
5776
        $criteria['subkey'] = $subKey;
5777
    }
5778
5779
    // Check if this variable doesn't exist already
5780
    /** @var SettingsCurrent $setting */
5781
    $setting = $settingRepo->findOneBy($criteria);
5782
5783
    if ($setting) {
0 ignored issues
show
introduced by
$setting is of type Chamilo\CoreBundle\Entity\SettingsCurrent, thus it always evaluated to true.
Loading history...
5784
        $setting->setSelectedValue($value);
5785
5786
        $em->persist($setting);
5787
        $em->flush();
5788
5789
        return $setting->getId();
5790
    }
5791
5792
    // Item not found for this access_url, we have to check if the whole thing is missing
5793
    // (in which case we ignore the insert) or if there *is* a record but just for access_url = 1
5794
    $setting = new SettingsCurrent();
5795
    $url = api_get_url_entity();
5796
5797
    $setting
5798
        ->setVariable($variable)
5799
        ->setSelectedValue($value)
5800
        ->setType($type)
5801
        ->setCategory($category)
5802
        ->setSubkey($subKey)
5803
        ->setTitle($title)
5804
        ->setComment($comment)
5805
        ->setScope($scope)
5806
        ->setSubkeytext($subKeyText)
5807
        ->setUrl(api_get_url_entity())
5808
        ->setAccessUrlChangeable($visibility);
5809
5810
    $em->persist($setting);
5811
    $em->flush();
5812
5813
    return $setting->getId();
5814
}
5815
5816
/**
5817
 * Checks wether a user can or can't view the contents of a course.
5818
 *
5819
 * @deprecated use CourseManager::is_user_subscribed_in_course
5820
 *
5821
 * @param int $userid User id or NULL to get it from $_SESSION
5822
 * @param int $cid    course id to check whether the user is allowed
5823
 *
5824
 * @return bool
5825
 */
5826
function api_is_course_visible_for_user($userid = null, $cid = null)
5827
{
5828
    if (null === $userid) {
5829
        $userid = api_get_user_id();
5830
    }
5831
    if (empty($userid) || strval(intval($userid)) != $userid) {
5832
        if (api_is_anonymous()) {
5833
            $userid = api_get_anonymous_id();
5834
        } else {
5835
            return false;
5836
        }
5837
    }
5838
    $cid = Database::escape_string($cid);
5839
5840
    $courseInfo = api_get_course_info($cid);
5841
    $courseId = $courseInfo['real_id'];
5842
    $is_platformAdmin = api_is_platform_admin();
5843
5844
    $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
5845
    $course_cat_table = Database::get_main_table(TABLE_MAIN_CATEGORY);
5846
5847
    $sql = "SELECT
5848
                $course_cat_table.code AS category_code,
5849
                $course_table.visibility,
5850
                $course_table.code,
5851
                $course_cat_table.code
5852
            FROM $course_table
5853
            LEFT JOIN $course_cat_table
5854
                ON $course_table.category_id = $course_cat_table.id
5855
            WHERE
5856
                $course_table.code = '$cid'
5857
            LIMIT 1";
5858
5859
    $result = Database::query($sql);
5860
5861
    if (Database::num_rows($result) > 0) {
5862
        $visibility = Database::fetch_array($result);
5863
        $visibility = $visibility['visibility'];
5864
    } else {
5865
        $visibility = 0;
5866
    }
5867
    // Shortcut permissions in case the visibility is "open to the world".
5868
    if (COURSE_VISIBILITY_OPEN_WORLD === $visibility) {
5869
        return true;
5870
    }
5871
5872
    $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
5873
5874
    $sql = "SELECT
5875
                is_tutor, status
5876
            FROM $tbl_course_user
5877
            WHERE
5878
                user_id  = '$userid' AND
5879
                relation_type <> '".COURSE_RELATION_TYPE_RRHH."' AND
5880
                c_id = $courseId
5881
            LIMIT 1";
5882
5883
    $result = Database::query($sql);
5884
5885
    if (Database::num_rows($result) > 0) {
5886
        // This user has got a recorded state for this course.
5887
        $cuData = Database::fetch_array($result);
5888
        $is_courseMember = true;
5889
        $is_courseAdmin = (1 == $cuData['status']);
5890
    }
5891
5892
    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...
5893
        // This user has no status related to this course.
5894
        // Is it the session coach or the session admin?
5895
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
5896
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
5897
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
5898
5899
        $sql = "SELECT
5900
                    session.id_coach, session_admin_id, session.id
5901
                FROM
5902
                    $tbl_session as session
5903
                INNER JOIN $tbl_session_course
5904
                    ON session_rel_course.session_id = session.id
5905
                    AND session_rel_course.c_id = '$courseId'
5906
                LIMIT 1";
5907
5908
        $result = Database::query($sql);
5909
        $row = Database::store_result($result);
5910
5911
        if ($row[0]['id_coach'] == $userid) {
5912
            $is_courseMember = true;
5913
            $is_courseAdmin = false;
5914
        } elseif ($row[0]['session_admin_id'] == $userid) {
5915
            $is_courseMember = false;
5916
            $is_courseAdmin = false;
5917
        } else {
5918
            // Check if the current user is the course coach.
5919
            $sql = "SELECT 1
5920
                    FROM $tbl_session_course
5921
                    WHERE session_rel_course.c_id = '$courseId'
5922
                    AND session_rel_course.id_coach = '$userid'
5923
                    LIMIT 1";
5924
5925
            $result = Database::query($sql);
5926
5927
            //if ($row = Database::fetch_array($result)) {
5928
            if (Database::num_rows($result) > 0) {
5929
                $is_courseMember = true;
5930
                $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
5931
5932
                $sql = "SELECT status FROM $tbl_user
5933
                        WHERE user_id = $userid
5934
                        LIMIT 1";
5935
5936
                $result = Database::query($sql);
5937
5938
                if (1 == Database::result($result, 0, 0)) {
5939
                    $is_courseAdmin = true;
5940
                } else {
5941
                    $is_courseAdmin = false;
5942
                }
5943
            } else {
5944
                // Check if the user is a student is this session.
5945
                $sql = "SELECT  id
5946
                        FROM $tbl_session_course_user
5947
                        WHERE
5948
                            user_id  = '$userid' AND
5949
                            c_id = '$courseId'
5950
                        LIMIT 1";
5951
5952
                if (Database::num_rows($result) > 0) {
5953
                    // This user haa got a recorded state for this course.
5954
                    while ($row = Database::fetch_array($result)) {
5955
                        $is_courseMember = true;
5956
                        $is_courseAdmin = false;
5957
                    }
5958
                }
5959
            }
5960
        }
5961
    }
5962
5963
    switch ($visibility) {
5964
        case COURSE_VISIBILITY_OPEN_WORLD:
5965
            return true;
5966
        case COURSE_VISIBILITY_OPEN_PLATFORM:
5967
            return isset($userid);
5968
        case COURSE_VISIBILITY_REGISTERED:
5969
        case COURSE_VISIBILITY_CLOSED:
5970
            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...
5971
        case COURSE_VISIBILITY_HIDDEN:
5972
            return $is_platformAdmin;
5973
    }
5974
5975
    return false;
5976
}
5977
5978
/**
5979
 * Returns whether an element (forum, message, survey ...) belongs to a session or not.
5980
 *
5981
 * @param string the tool of the element
5982
 * @param int the element id in database
5983
 * @param int the session_id to compare with element session id
5984
 *
5985
 * @return bool true if the element is in the session, false else
5986
 */
5987
function api_is_element_in_the_session($tool, $element_id, $session_id = null)
5988
{
5989
    if (is_null($session_id)) {
5990
        $session_id = api_get_session_id();
5991
    }
5992
5993
    $element_id = (int) $element_id;
5994
5995
    if (empty($element_id)) {
5996
        return false;
5997
    }
5998
5999
    // Get information to build query depending of the tool.
6000
    switch ($tool) {
6001
        case TOOL_SURVEY:
6002
            $table_tool = Database::get_course_table(TABLE_SURVEY);
6003
            $key_field = 'survey_id';
6004
            break;
6005
        case TOOL_ANNOUNCEMENT:
6006
            $table_tool = Database::get_course_table(TABLE_ANNOUNCEMENT);
6007
            $key_field = 'id';
6008
            break;
6009
        case TOOL_AGENDA:
6010
            $table_tool = Database::get_course_table(TABLE_AGENDA);
6011
            $key_field = 'id';
6012
            break;
6013
        case TOOL_GROUP:
6014
            $table_tool = Database::get_course_table(TABLE_GROUP);
6015
            $key_field = 'id';
6016
            break;
6017
        default:
6018
            return false;
6019
    }
6020
    $course_id = api_get_course_int_id();
6021
6022
    $sql = "SELECT session_id FROM $table_tool
6023
            WHERE c_id = $course_id AND $key_field =  ".$element_id;
6024
    $rs = Database::query($sql);
6025
    if ($element_session_id = Database::result($rs, 0, 0)) {
6026
        if ($element_session_id == intval($session_id)) {
6027
            // The element belongs to the session.
6028
            return true;
6029
        }
6030
    }
6031
6032
    return false;
6033
}
6034
6035
/**
6036
 * Replaces "forbidden" characters in a filename string.
6037
 *
6038
 * @param string $filename
6039
 * @param bool   $treat_spaces_as_hyphens
6040
 *
6041
 * @return string
6042
 */
6043
function api_replace_dangerous_char($filename, $treat_spaces_as_hyphens = true)
0 ignored issues
show
Unused Code introduced by
The parameter $treat_spaces_as_hyphens 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

6043
function api_replace_dangerous_char($filename, /** @scrutinizer ignore-unused */ $treat_spaces_as_hyphens = 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...
6044
{
6045
    // Some non-properly encoded file names can cause the whole file to be
6046
    // skipped when uploaded. Avoid this by detecting the encoding and
6047
    // converting to UTF-8, setting the source as ASCII (a reasonably
6048
    // limited characters set) if nothing could be found (BT#
6049
    $encoding = api_detect_encoding($filename);
6050
    if (empty($encoding)) {
6051
        $encoding = 'ASCII';
6052
        if (!api_is_valid_ascii($filename)) {
6053
            // try iconv and try non standard ASCII a.k.a CP437
6054
            // see BT#15022
6055
            if (function_exists('iconv')) {
6056
                $result = iconv('CP437', 'UTF-8', $filename);
6057
                if (api_is_valid_utf8($result)) {
6058
                    $filename = $result;
6059
                    $encoding = 'UTF-8';
6060
                }
6061
            }
6062
        }
6063
    }
6064
6065
    $filename = api_to_system_encoding($filename, $encoding);
6066
6067
    $url = URLify::filter(
6068
        $filename,
6069
        250,
6070
        '',
6071
        true,
6072
        false,
6073
        false,
6074
        false
6075
    );
6076
6077
    return $url;
6078
}
6079
6080
/**
6081
 * Fixes the $_SERVER['REQUEST_URI'] that is empty in IIS6.
6082
 *
6083
 * @author Ivan Tcholakov, 28-JUN-2006.
6084
 */
6085
function api_request_uri()
6086
{
6087
    if (!empty($_SERVER['REQUEST_URI'])) {
6088
        return $_SERVER['REQUEST_URI'];
6089
    }
6090
    $uri = $_SERVER['SCRIPT_NAME'];
6091
    if (!empty($_SERVER['QUERY_STRING'])) {
6092
        $uri .= '?'.$_SERVER['QUERY_STRING'];
6093
    }
6094
    $_SERVER['REQUEST_URI'] = $uri;
6095
6096
    return $uri;
6097
}
6098
6099
/** Gets the current access_url id of the Chamilo Platform
6100
 * @author Julio Montoya <[email protected]>
6101
 *
6102
 * @return int access_url_id of the current Chamilo Installation
6103
 */
6104
function api_get_current_access_url_id()
6105
{
6106
    if (false === api_get_multiple_access_url()) {
6107
        return 1;
6108
    }
6109
6110
    static $id;
6111
    if (!empty($id)) {
6112
        return $id;
6113
    }
6114
6115
    $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
6116
    $path = Database::escape_string(api_get_path(WEB_PATH));
6117
    $sql = "SELECT id FROM $table WHERE url = '".$path."'";
6118
    $result = Database::query($sql);
6119
    if (Database::num_rows($result) > 0) {
6120
        $id = Database::result($result, 0, 0);
6121
        if (false === $id) {
6122
            return -1;
6123
        }
6124
6125
        return (int) $id;
6126
    }
6127
6128
    $id = 1;
6129
6130
    //if the url in WEB_PATH was not found, it can only mean that there is
6131
    // either a configuration problem or the first URL has not been defined yet
6132
    // (by default it is http://localhost/). Thus the more sensible thing we can
6133
    // do is return 1 (the main URL) as the user cannot hack this value anyway
6134
    return 1;
6135
}
6136
6137
/**
6138
 * Gets the registered urls from a given user id.
6139
 *
6140
 * @author Julio Montoya <[email protected]>
6141
 *
6142
 * @param int $user_id
6143
 *
6144
 * @return array
6145
 */
6146
function api_get_access_url_from_user($user_id)
6147
{
6148
    $user_id = (int) $user_id;
6149
    $table_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
6150
    $table_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
6151
    $sql = "SELECT access_url_id
6152
            FROM $table_url_rel_user url_rel_user
6153
            INNER JOIN $table_url u
6154
            ON (url_rel_user.access_url_id = u.id)
6155
            WHERE user_id = ".$user_id;
6156
    $result = Database::query($sql);
6157
    $list = [];
6158
    while ($row = Database::fetch_array($result, 'ASSOC')) {
6159
        $list[] = $row['access_url_id'];
6160
    }
6161
6162
    return $list;
6163
}
6164
6165
/**
6166
 * Checks whether the curent user is in a group or not.
6167
 *
6168
 * @param string        The group id - optional (takes it from session if not given)
6169
 * @param string        The course code - optional (no additional check by course if course code is not given)
6170
 *
6171
 * @return bool
6172
 *
6173
 * @author Ivan Tcholakov
6174
 */
6175
function api_is_in_group($groupIdParam = null, $courseCodeParam = null)
6176
{
6177
    if (!empty($courseCodeParam)) {
6178
        $courseCode = api_get_course_id();
6179
        if (!empty($courseCode)) {
6180
            if ($courseCodeParam != $courseCode) {
6181
                return false;
6182
            }
6183
        } else {
6184
            return false;
6185
        }
6186
    }
6187
6188
    $groupId = api_get_group_id();
6189
6190
    if (isset($groupId) && '' != $groupId) {
6191
        if (!empty($groupIdParam)) {
6192
            return $groupIdParam == $groupId;
6193
        } else {
6194
            return true;
6195
        }
6196
    }
6197
6198
    return false;
6199
}
6200
6201
/**
6202
 * Checks whether a secret key is valid.
6203
 *
6204
 * @param string $original_key_secret - secret key from (webservice) client
6205
 * @param string $security_key        - security key from Chamilo
6206
 *
6207
 * @return bool - true if secret key is valid, false otherwise
6208
 */
6209
function api_is_valid_secret_key($original_key_secret, $security_key)
6210
{
6211
    return $original_key_secret == sha1($security_key);
6212
}
6213
6214
/**
6215
 * Checks whether a user is into course.
6216
 *
6217
 * @param int $course_id - the course id
6218
 * @param int $user_id   - the user id
6219
 *
6220
 * @return bool
6221
 */
6222
function api_is_user_of_course($course_id, $user_id)
6223
{
6224
    $tbl_course_rel_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
6225
    $sql = 'SELECT user_id FROM '.$tbl_course_rel_user.'
6226
            WHERE
6227
                c_id ="'.intval($course_id).'" AND
6228
                user_id = "'.intval($user_id).'" AND
6229
                relation_type <> '.COURSE_RELATION_TYPE_RRHH.' ';
6230
    $result = Database::query($sql);
6231
6232
    return 1 == Database::num_rows($result);
6233
}
6234
6235
/**
6236
 * Checks whether the server's operating system is Windows (TM).
6237
 *
6238
 * @return bool - true if the operating system is Windows, false otherwise
6239
 */
6240
function api_is_windows_os()
6241
{
6242
    if (function_exists('php_uname')) {
6243
        // php_uname() exists as of PHP 4.0.2, according to the documentation.
6244
        // We expect that this function will always work for Chamilo 1.8.x.
6245
        $os = php_uname();
6246
    }
6247
    // The following methods are not needed, but let them stay, just in case.
6248
    elseif (isset($_ENV['OS'])) {
6249
        // Sometimes $_ENV['OS'] may not be present (bugs?)
6250
        $os = $_ENV['OS'];
6251
    } elseif (defined('PHP_OS')) {
6252
        // PHP_OS means on which OS PHP was compiled, this is why
6253
        // using PHP_OS is the last choice for detection.
6254
        $os = PHP_OS;
6255
    } else {
6256
        return false;
6257
    }
6258
6259
    return 'win' == strtolower(substr((string) $os, 0, 3));
6260
}
6261
6262
/**
6263
 * This function informs whether the sent request is XMLHttpRequest.
6264
 */
6265
function api_is_xml_http_request()
6266
{
6267
    return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && 'xmlhttprequest' == strtolower($_SERVER['HTTP_X_REQUESTED_WITH']);
6268
}
6269
6270
/**
6271
 * This wrapper function has been implemented for avoiding some known problems about the function getimagesize().
6272
 *
6273
 * @see http://php.net/manual/en/function.getimagesize.php
6274
 * @see http://www.dokeos.com/forum/viewtopic.php?t=12345
6275
 * @see http://www.dokeos.com/forum/viewtopic.php?t=16355
6276
 *
6277
 * @return int
6278
 */
6279
function api_getimagesize($path)
6280
{
6281
    $image = new Image($path);
6282
6283
    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...
6284
}
6285
6286
/**
6287
 * This function resizes an image, with preserving its proportions (or aspect ratio).
6288
 *
6289
 * @author Ivan Tcholakov, MAY-2009.
6290
 *
6291
 * @param int $image         System path or URL of the image
6292
 * @param int $target_width  Targeted width
6293
 * @param int $target_height Targeted height
6294
 *
6295
 * @return array Calculated new width and height
6296
 */
6297
function api_resize_image($image, $target_width, $target_height)
6298
{
6299
    $image_properties = api_getimagesize($image);
6300
6301
    return api_calculate_image_size(
6302
        $image_properties['width'],
6303
        $image_properties['height'],
6304
        $target_width,
6305
        $target_height
6306
    );
6307
}
6308
6309
/**
6310
 * This function calculates new image size, with preserving image's proportions (or aspect ratio).
6311
 *
6312
 * @author Ivan Tcholakov, MAY-2009.
6313
 * @author The initial idea has been taken from code by Patrick Cool, MAY-2004.
6314
 *
6315
 * @param int $image_width   Initial width
6316
 * @param int $image_height  Initial height
6317
 * @param int $target_width  Targeted width
6318
 * @param int $target_height Targeted height
6319
 *
6320
 * @return array Calculated new width and height
6321
 */
6322
function api_calculate_image_size(
6323
    $image_width,
6324
    $image_height,
6325
    $target_width,
6326
    $target_height
6327
) {
6328
    // Only maths is here.
6329
    $result = ['width' => $image_width, 'height' => $image_height];
6330
    if ($image_width <= 0 || $image_height <= 0) {
6331
        return $result;
6332
    }
6333
    $resize_factor_width = $target_width / $image_width;
6334
    $resize_factor_height = $target_height / $image_height;
6335
    $delta_width = $target_width - $image_width * $resize_factor_height;
6336
    $delta_height = $target_height - $image_height * $resize_factor_width;
6337
    if ($delta_width > $delta_height) {
6338
        $result['width'] = ceil($image_width * $resize_factor_height);
6339
        $result['height'] = ceil($image_height * $resize_factor_height);
6340
    } elseif ($delta_width < $delta_height) {
6341
        $result['width'] = ceil($image_width * $resize_factor_width);
6342
        $result['height'] = ceil($image_height * $resize_factor_width);
6343
    } else {
6344
        $result['width'] = ceil($target_width);
6345
        $result['height'] = ceil($target_height);
6346
    }
6347
6348
    return $result;
6349
}
6350
6351
/**
6352
 * Returns a list of Chamilo's tools or
6353
 * checks whether a given identificator is a valid Chamilo's tool.
6354
 *
6355
 * @author Isaac flores paz
6356
 *
6357
 * @param string The tool name to filter
6358
 *
6359
 * @return mixed Filtered string or array
6360
 */
6361
function api_get_tools_lists($my_tool = null)
6362
{
6363
    $tools_list = [
6364
        TOOL_DOCUMENT,
6365
        TOOL_THUMBNAIL,
6366
        TOOL_HOTPOTATOES,
6367
        TOOL_CALENDAR_EVENT,
6368
        TOOL_LINK,
6369
        TOOL_COURSE_DESCRIPTION,
6370
        TOOL_SEARCH,
6371
        TOOL_LEARNPATH,
6372
        TOOL_ANNOUNCEMENT,
6373
        TOOL_FORUM,
6374
        TOOL_THREAD,
6375
        TOOL_POST,
6376
        TOOL_DROPBOX,
6377
        TOOL_QUIZ,
6378
        TOOL_USER,
6379
        TOOL_GROUP,
6380
        TOOL_BLOGS,
6381
        TOOL_CHAT,
6382
        TOOL_STUDENTPUBLICATION,
6383
        TOOL_TRACKING,
6384
        TOOL_HOMEPAGE_LINK,
6385
        TOOL_COURSE_SETTING,
6386
        TOOL_BACKUP,
6387
        TOOL_COPY_COURSE_CONTENT,
6388
        TOOL_RECYCLE_COURSE,
6389
        TOOL_COURSE_HOMEPAGE,
6390
        TOOL_COURSE_RIGHTS_OVERVIEW,
6391
        TOOL_UPLOAD,
6392
        TOOL_COURSE_MAINTENANCE,
6393
        TOOL_SURVEY,
6394
        TOOL_WIKI,
6395
        TOOL_GLOSSARY,
6396
        TOOL_GRADEBOOK,
6397
        TOOL_NOTEBOOK,
6398
        TOOL_ATTENDANCE,
6399
        TOOL_COURSE_PROGRESS,
6400
    ];
6401
    if (empty($my_tool)) {
6402
        return $tools_list;
6403
    }
6404
6405
    return in_array($my_tool, $tools_list) ? $my_tool : '';
6406
}
6407
6408
/**
6409
 * Checks whether we already approved the last version term and condition.
6410
 *
6411
 * @param int user id
6412
 *
6413
 * @return bool true if we pass false otherwise
6414
 */
6415
function api_check_term_condition($userId)
6416
{
6417
    if ('true' === api_get_setting('allow_terms_conditions')) {
6418
        // Check if exists terms and conditions
6419
        if (0 == LegalManager::count()) {
6420
            return true;
6421
        }
6422
6423
        $extraFieldValue = new ExtraFieldValue('user');
6424
        $data = $extraFieldValue->get_values_by_handler_and_field_variable(
6425
            $userId,
6426
            'legal_accept'
6427
        );
6428
6429
        if (!empty($data) && isset($data['value']) && !empty($data['value'])) {
6430
            $result = $data['value'];
6431
            $user_conditions = explode(':', $result);
6432
            $version = $user_conditions[0];
6433
            $langId = $user_conditions[1];
6434
            $realVersion = LegalManager::get_last_version($langId);
6435
6436
            return $version >= $realVersion;
6437
        }
6438
6439
        return false;
6440
    }
6441
6442
    return false;
6443
}
6444
6445
/**
6446
 * Gets all information of a tool into course.
6447
 *
6448
 * @param int The tool id
6449
 *
6450
 * @return array
6451
 */
6452
function api_get_tool_information_by_name($name)
6453
{
6454
    $t_tool = Database::get_course_table(TABLE_TOOL_LIST);
6455
    $course_id = api_get_course_int_id();
6456
6457
    $sql = "SELECT id FROM tool
6458
            WHERE name = '".Database::escape_string($name)."' ";
6459
    $rs = Database::query($sql);
6460
    $data = Database::fetch_array($rs);
6461
    $tool = $data['id'];
6462
6463
    $sql = "SELECT * FROM $t_tool
6464
            WHERE c_id = $course_id  AND tool_id = '".$tool."' ";
6465
    $rs = Database::query($sql);
6466
6467
    return Database::fetch_array($rs, 'ASSOC');
6468
}
6469
6470
/**
6471
 * Function used to protect a "global" admin script.
6472
 * The function blocks access when the user has no global platform admin rights.
6473
 * Global admins are the admins that are registered in the main.admin table
6474
 * AND the users who have access to the "principal" portal.
6475
 * That means that there is a record in the main.access_url_rel_user table
6476
 * with his user id and the access_url_id=1.
6477
 *
6478
 * @author Julio Montoya
6479
 *
6480
 * @param int $user_id
6481
 *
6482
 * @return bool
6483
 */
6484
function api_is_global_platform_admin($user_id = null)
6485
{
6486
    $user_id = (int) $user_id;
6487
    if (empty($user_id)) {
6488
        $user_id = api_get_user_id();
6489
    }
6490
    if (api_is_platform_admin_by_id($user_id)) {
6491
        $urlList = api_get_access_url_from_user($user_id);
6492
        // The admin is registered in the first "main" site with access_url_id = 1
6493
        if (in_array(1, $urlList)) {
6494
            return true;
6495
        } else {
6496
            return false;
6497
        }
6498
    }
6499
6500
    return false;
6501
}
6502
6503
/**
6504
 * @param int  $admin_id_to_check
6505
 * @param int  $my_user_id
6506
 * @param bool $allow_session_admin
6507
 *
6508
 * @return bool
6509
 */
6510
function api_global_admin_can_edit_admin(
6511
    $admin_id_to_check,
6512
    $my_user_id = null,
6513
    $allow_session_admin = false
6514
) {
6515
    if (empty($my_user_id)) {
6516
        $my_user_id = api_get_user_id();
6517
    }
6518
6519
    $iam_a_global_admin = api_is_global_platform_admin($my_user_id);
6520
    $user_is_global_admin = api_is_global_platform_admin($admin_id_to_check);
6521
6522
    if ($iam_a_global_admin) {
6523
        // Global admin can edit everything
6524
        return true;
6525
    } else {
6526
        // If i'm a simple admin
6527
        $is_platform_admin = api_is_platform_admin_by_id($my_user_id);
6528
6529
        if ($allow_session_admin) {
6530
            $is_platform_admin = api_is_platform_admin_by_id($my_user_id) || (SESSIONADMIN == api_get_user_status($my_user_id));
6531
        }
6532
6533
        if ($is_platform_admin) {
6534
            if ($user_is_global_admin) {
6535
                return false;
6536
            } else {
6537
                return true;
6538
            }
6539
        } else {
6540
            return false;
6541
        }
6542
    }
6543
}
6544
6545
/**
6546
 * @param int  $admin_id_to_check
6547
 * @param int  $my_user_id
6548
 * @param bool $allow_session_admin
6549
 *
6550
 * @return bool|null
6551
 */
6552
function api_protect_super_admin($admin_id_to_check, $my_user_id = null, $allow_session_admin = false)
6553
{
6554
    if (api_global_admin_can_edit_admin($admin_id_to_check, $my_user_id, $allow_session_admin)) {
6555
        return true;
6556
    } else {
6557
        api_not_allowed();
6558
    }
6559
}
6560
6561
/**
6562
 * Function used to protect a global admin script.
6563
 * The function blocks access when the user has no global platform admin rights.
6564
 * See also the api_is_global_platform_admin() function wich defines who's a "global" admin.
6565
 *
6566
 * @author Julio Montoya
6567
 */
6568
function api_protect_global_admin_script()
6569
{
6570
    if (!api_is_global_platform_admin()) {
6571
        api_not_allowed();
6572
6573
        return false;
6574
    }
6575
6576
    return true;
6577
}
6578
6579
/**
6580
 * Check browser support for specific file types or features
6581
 * This function checks if the user's browser supports a file format or given
6582
 * feature, or returns the current browser and major version when
6583
 * $format=check_browser. Only a limited number of formats and features are
6584
 * checked by this method. Make sure you check its definition first.
6585
 *
6586
 * @param string $format Can be a file format (extension like svg, webm, ...) or a feature (like autocapitalize, ...)
6587
 *
6588
 * @deprecated
6589
 *
6590
 * @return bool or return text array if $format=check_browser
6591
 *
6592
 * @author Juan Carlos Raña Trabado
6593
 */
6594
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

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

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

8415
        fclose(/** @scrutinizer ignore-type */ $fp);
Loading history...
8416
    }
8417
8418
    return $isCreated;
8419
}
8420
8421
/**
8422
 * Sends an email
8423
 * Sender name and email can be specified, if not specified
8424
 * name and email of the platform admin are used.
8425
 *
8426
 * @param string    name of recipient
8427
 * @param string    email of recipient
8428
 * @param string    email subject
8429
 * @param string    email body
8430
 * @param string    sender name
8431
 * @param string    sender e-mail
8432
 * @param array     extra headers in form $headers = array($name => $value) to allow parsing
8433
 * @param array     data file (path and filename)
8434
 * @param bool      True for attaching a embedded file inside content html (optional)
8435
 * @param array     Additional parameters
8436
 *
8437
 * @return bool true if mail was sent
8438
 */
8439
function api_mail_html(
8440
    $recipientName,
8441
    $recipientEmail,
8442
    $subject,
8443
    $body,
8444
    $senderName = '',
8445
    $senderEmail = '',
8446
    $extra_headers = [],
8447
    $data_file = [],
8448
    $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

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