Passed
Push — master ( a9538a...f34bea )
by Julito
11:21
created

api_get_bytes_memory_limit()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 24
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 18
nc 5
nop 1
dl 0
loc 24
rs 9.3554
c 0
b 0
f 0
1
<?php
2
/* For licensing terms, see /license.txt */
3
4
use Chamilo\CoreBundle\Entity\AccessUrl;
5
use Chamilo\CoreBundle\Entity\Course;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Course. Consider defining an alias.

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

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

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

// Bar.php
namespace OtherDir;

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

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

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

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

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
6
use Chamilo\CoreBundle\Entity\Session as SessionEntity;
7
use Chamilo\CoreBundle\Entity\SettingsCurrent;
8
use Chamilo\CoreBundle\Framework\Container;
9
use Chamilo\CourseBundle\Entity\CGroupInfo;
10
use Chamilo\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 ($isAllowedInCourse && api_get_user_id() && !api_is_anonymous()) {
1027
                    $is_visible = true;
1028
                }
1029
                break;
1030
            case COURSE_VISIBILITY_REGISTERED:
1031
                // Private - access authorized to course members only - 1
1032
                if ($isAllowedInCourse && api_get_user_id() && !api_is_anonymous()) {
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 ($isAllowedInCourse && api_get_user_id() && !api_is_anonymous()) {
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
1151
    if (!(isset($user['user_id']) && $user['user_id']) || api_is_anonymous($user['user_id'], true)) {
1152
        api_not_allowed($printHeaders);
1153
1154
        return false;
1155
    }
1156
1157
    return true;
1158
}
1159
1160
/**
1161
 * Returns a rough evaluation of the browser's name and version based on very
1162
 * simple regexp.
1163
 *
1164
 * @return array with the navigator name and version ['name' => '...', 'version' => '...']
1165
 */
1166
function api_get_navigator()
1167
{
1168
    $navigator = 'Unknown';
1169
    $version = 0;
1170
1171
    if (!isset($_SERVER['HTTP_USER_AGENT'])) {
1172
        return ['name' => 'Unknown', 'version' => '0.0.0'];
1173
    }
1174
1175
    if (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Opera')) {
1176
        $navigator = 'Opera';
1177
        list(, $version) = explode('Opera', $_SERVER['HTTP_USER_AGENT']);
1178
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Edge')) {
1179
        $navigator = 'Edge';
1180
        list(, $version) = explode('Edge', $_SERVER['HTTP_USER_AGENT']);
1181
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE')) {
1182
        $navigator = 'Internet Explorer';
1183
        list(, $version) = explode('MSIE ', $_SERVER['HTTP_USER_AGENT']);
1184
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Chrome')) {
1185
        $navigator = 'Chrome';
1186
        list(, $version) = explode('Chrome', $_SERVER['HTTP_USER_AGENT']);
1187
    } elseif (false !== stripos($_SERVER['HTTP_USER_AGENT'], 'Safari')) {
1188
        $navigator = 'Safari';
1189
        if (false !== stripos($_SERVER['HTTP_USER_AGENT'], 'Version/')) {
1190
            // If this Safari does have the "Version/" string in its user agent
1191
            // then use that as a version indicator rather than what's after
1192
            // "Safari/" which is rather a "build number" or something
1193
            list(, $version) = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1194
        } else {
1195
            list(, $version) = explode('Safari/', $_SERVER['HTTP_USER_AGENT']);
1196
        }
1197
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Firefox')) {
1198
        $navigator = 'Firefox';
1199
        list(, $version) = explode('Firefox', $_SERVER['HTTP_USER_AGENT']);
1200
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Netscape')) {
1201
        $navigator = 'Netscape';
1202
        if (false !== stripos($_SERVER['HTTP_USER_AGENT'], 'Netscape/')) {
1203
            list(, $version) = explode('Netscape', $_SERVER['HTTP_USER_AGENT']);
1204
        } else {
1205
            list(, $version) = explode('Navigator', $_SERVER['HTTP_USER_AGENT']);
1206
        }
1207
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Konqueror')) {
1208
        $navigator = 'Konqueror';
1209
        list(, $version) = explode('Konqueror', $_SERVER['HTTP_USER_AGENT']);
1210
    } elseif (false !== stripos($_SERVER['HTTP_USER_AGENT'], 'applewebkit')) {
1211
        $navigator = 'AppleWebKit';
1212
        list(, $version) = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1213
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Gecko')) {
1214
        $navigator = 'Mozilla';
1215
        list(, $version) = explode('; rv:', $_SERVER['HTTP_USER_AGENT']);
1216
    }
1217
1218
    // Now cut extra stuff around (mostly *after*) the version number
1219
    $version = preg_replace('/^([\/\s])?([\d\.]+)?.*/', '\2', $version);
1220
1221
    if (false === strpos($version, '.')) {
1222
        $version = number_format(doubleval($version), 1);
1223
    }
1224
    $return = ['name' => $navigator, 'version' => $version];
1225
1226
    return $return;
1227
}
1228
1229
/**
1230
 * @return true if user self registration is allowed, false otherwise
1231
 */
1232
function api_is_self_registration_allowed()
1233
{
1234
    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...
1235
}
1236
1237
/**
1238
 * This function returns the id of the user which is stored in the $_user array.
1239
 *
1240
 * example: The function can be used to check if a user is logged in
1241
 *          if (api_get_user_id())
1242
 *
1243
 * @return int the id of the current user, 0 if is empty
1244
 */
1245
function api_get_user_id()
1246
{
1247
    $userInfo = Session::read('_user');
1248
    if ($userInfo && isset($userInfo['user_id'])) {
1249
        return (int) $userInfo['user_id'];
1250
    }
1251
1252
    return 0;
1253
}
1254
1255
/**
1256
 * Gets the list of courses a specific user is subscribed to.
1257
 *
1258
 * @param int       User ID
1259
 * @param bool $fetch_session Whether to get session courses or not - NOT YET IMPLEMENTED
1260
 *
1261
 * @return array Array of courses in the form [0]=>('code'=>xxx,'db'=>xxx,'dir'=>xxx,'status'=>d)
1262
 *
1263
 * @deprecated use CourseManager::get_courses_list_by_user_id()
1264
 */
1265
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

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

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

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

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

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

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

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

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

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

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

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

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

8335
        fclose(/** @scrutinizer ignore-type */ $fp);
Loading history...
8336
    }
8337
8338
    return $isCreated;
8339
}
8340
8341
/**
8342
 * Sends an email
8343
 * Sender name and email can be specified, if not specified
8344
 * name and email of the platform admin are used.
8345
 *
8346
 * @param string    name of recipient
8347
 * @param string    email of recipient
8348
 * @param string    email subject
8349
 * @param string    email body
8350
 * @param string    sender name
8351
 * @param string    sender e-mail
8352
 * @param array     extra headers in form $headers = array($name => $value) to allow parsing
8353
 * @param array     data file (path and filename)
8354
 * @param bool      True for attaching a embedded file inside content html (optional)
8355
 * @param array     Additional parameters
8356
 *
8357
 * @return bool true if mail was sent
8358
 */
8359
function api_mail_html(
8360
    $recipientName,
8361
    $recipientEmail,
8362
    $subject,
8363
    $body,
8364
    $senderName = '',
8365
    $senderEmail = '',
8366
    $extra_headers = [],
8367
    $data_file = [],
8368
    $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

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