Passed
Push — master ( 3be753...7af7b8 )
by Julito
10:23
created

api_get_current_user()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

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

1135
function api_protect_course_script($print_headers = false, $allow_session_admins = false, /** @scrutinizer ignore-unused */ $allow_drh = 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...
1136
{
1137
    $is_allowed_in_course = api_is_allowed_in_course();
1138
1139
    $is_visible = false;
1140
    $course_info = api_get_course_info();
1141
1142
    if (empty($course_info)) {
1143
        api_not_allowed($print_headers);
1144
1145
        return false;
1146
    }
1147
1148
    if (api_is_drh()) {
1149
        return true;
1150
    }
1151
1152
    // Session admin has access to course
1153
    $sessionAccess = api_get_configuration_value('session_admins_access_all_content');
1154
    if ($sessionAccess) {
1155
        $allow_session_admins = true;
1156
    }
1157
1158
    if (api_is_platform_admin($allow_session_admins)) {
1159
        return true;
1160
    }
1161
1162
    if (isset($course_info) && isset($course_info['visibility'])) {
1163
        switch ($course_info['visibility']) {
1164
            default:
1165
            case COURSE_VISIBILITY_CLOSED:
1166
                // Completely closed: the course is only accessible to the teachers. - 0
1167
                if (api_get_user_id() && !api_is_anonymous() && $is_allowed_in_course) {
1168
                    $is_visible = true;
1169
                }
1170
                break;
1171
            case COURSE_VISIBILITY_REGISTERED:
1172
                // Private - access authorized to course members only - 1
1173
                if (api_get_user_id() && !api_is_anonymous() && $is_allowed_in_course) {
1174
                    $is_visible = true;
1175
                }
1176
                break;
1177
            case COURSE_VISIBILITY_OPEN_PLATFORM:
1178
                // Open - access allowed for users registered on the platform - 2
1179
                if (api_get_user_id() && !api_is_anonymous() && $is_allowed_in_course) {
1180
                    $is_visible = true;
1181
                }
1182
                break;
1183
            case COURSE_VISIBILITY_OPEN_WORLD:
1184
                //Open - access allowed for the whole world - 3
1185
                $is_visible = true;
1186
                break;
1187
            case COURSE_VISIBILITY_HIDDEN:
1188
                //Completely closed: the course is only accessible to the teachers. - 0
1189
                if (api_is_platform_admin()) {
1190
                    $is_visible = true;
1191
                }
1192
                break;
1193
        }
1194
1195
        //If password is set and user is not registered to the course then the course is not visible
1196
        if ($is_allowed_in_course == false &&
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

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

Loading history...
1197
            isset($course_info['registration_code']) &&
1198
            !empty($course_info['registration_code'])
1199
        ) {
1200
            $is_visible = false;
1201
        }
1202
    }
1203
1204
    // Check session visibility
1205
    $session_id = api_get_session_id();
1206
1207
    if (!empty($session_id)) {
1208
        //$is_allowed_in_course was set in local.inc.php
1209
        if (!$is_allowed_in_course) {
1210
            $is_visible = false;
1211
        }
1212
    }
1213
1214
    if (!$is_visible) {
1215
        api_not_allowed($print_headers);
1216
1217
        return false;
1218
    }
1219
1220
    return true;
1221
}
1222
1223
/**
1224
 * Function used to protect an admin script.
1225
 *
1226
 * The function blocks access when the user has no platform admin rights
1227
 * with an error message printed on default output
1228
 *
1229
 * @param bool Whether to allow session admins as well
1230
 * @param bool Whether to allow HR directors as well
1231
 * @param string An optional message (already passed through get_lang)
1232
 *
1233
 * @return bool True if user is allowed, false otherwise.
1234
 *              The function also outputs an error message in case not allowed
1235
 *
1236
 * @author Roan Embrechts (original author)
1237
 */
1238
function api_protect_admin_script($allow_sessions_admins = false, $allow_drh = false, $message = null)
1239
{
1240
    if (!api_is_platform_admin($allow_sessions_admins, $allow_drh)) {
1241
        api_not_allowed(true, $message);
1242
1243
        return false;
1244
    }
1245
1246
    return true;
1247
}
1248
1249
/**
1250
 * Function used to protect a teacher script.
1251
 * The function blocks access when the user has no teacher rights.
1252
 *
1253
 * @author Yoselyn Castillo
1254
 */
1255
function api_protect_teacher_script($allow_sessions_admins = false)
0 ignored issues
show
Unused Code introduced by
The parameter $allow_sessions_admins 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

1255
function api_protect_teacher_script(/** @scrutinizer ignore-unused */ $allow_sessions_admins = 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...
1256
{
1257
    if (!api_is_allowed_to_edit()) {
1258
        api_not_allowed(true);
1259
1260
        return false;
1261
    }
1262
1263
    return true;
1264
}
1265
1266
/**
1267
 * Function used to prevent anonymous users from accessing a script.
1268
 *
1269
 * @param bool|true $printHeaders
1270
 *
1271
 * @author Roan Embrechts
1272
 *
1273
 * @return bool
1274
 */
1275
function api_block_anonymous_users($printHeaders = true)
1276
{
1277
    $user = api_get_user_info();
1278
    if (!(isset($user['user_id']) && $user['user_id']) || api_is_anonymous($user['user_id'], true)) {
1279
        api_not_allowed($printHeaders);
1280
1281
        return false;
1282
    }
1283
1284
    return true;
1285
}
1286
1287
/**
1288
 * Returns a rough evaluation of the browser's name and version based on very
1289
 * simple regexp.
1290
 *
1291
 * @return array with the navigator name and version ['name' => '...', 'version' => '...']
1292
 */
1293
function api_get_navigator()
1294
{
1295
    $navigator = 'Unknown';
1296
    $version = 0;
1297
1298
    if (!isset($_SERVER['HTTP_USER_AGENT'])) {
1299
        return ['name' => 'Unknown', 'version' => '0.0.0'];
1300
    }
1301
1302
    if (strpos($_SERVER['HTTP_USER_AGENT'], 'Opera') !== false) {
1303
        $navigator = 'Opera';
1304
        list(, $version) = explode('Opera', $_SERVER['HTTP_USER_AGENT']);
1305
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Edge') !== false) {
1306
        $navigator = 'Edge';
1307
        list(, $version) = explode('Edge', $_SERVER['HTTP_USER_AGENT']);
1308
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== false) {
1309
        $navigator = 'Internet Explorer';
1310
        list(, $version) = explode('MSIE ', $_SERVER['HTTP_USER_AGENT']);
1311
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Chrome') !== false) {
1312
        $navigator = 'Chrome';
1313
        list(, $version) = explode('Chrome', $_SERVER['HTTP_USER_AGENT']);
1314
    } elseif (stripos($_SERVER['HTTP_USER_AGENT'], 'Safari') !== false) {
1315
        $navigator = 'Safari';
1316
        if (stripos($_SERVER['HTTP_USER_AGENT'], 'Version/') !== false) {
1317
            // If this Safari does have the "Version/" string in its user agent
1318
            // then use that as a version indicator rather than what's after
1319
            // "Safari/" which is rather a "build number" or something
1320
            list(, $version) = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1321
        } else {
1322
            list(, $version) = explode('Safari/', $_SERVER['HTTP_USER_AGENT']);
1323
        }
1324
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Firefox') !== false) {
1325
        $navigator = 'Firefox';
1326
        list(, $version) = explode('Firefox', $_SERVER['HTTP_USER_AGENT']);
1327
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Netscape') !== false) {
1328
        $navigator = 'Netscape';
1329
        if (stripos($_SERVER['HTTP_USER_AGENT'], 'Netscape/') !== false) {
1330
            list(, $version) = explode('Netscape', $_SERVER['HTTP_USER_AGENT']);
1331
        } else {
1332
            list(, $version) = explode('Navigator', $_SERVER['HTTP_USER_AGENT']);
1333
        }
1334
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Konqueror') !== false) {
1335
        $navigator = 'Konqueror';
1336
        list(, $version) = explode('Konqueror', $_SERVER['HTTP_USER_AGENT']);
1337
    } elseif (stripos($_SERVER['HTTP_USER_AGENT'], 'applewebkit') !== false) {
1338
        $navigator = 'AppleWebKit';
1339
        list(, $version) = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1340
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Gecko') !== false) {
1341
        $navigator = 'Mozilla';
1342
        list(, $version) = explode('; rv:', $_SERVER['HTTP_USER_AGENT']);
1343
    }
1344
1345
    // Now cut extra stuff around (mostly *after*) the version number
1346
    $version = preg_replace('/^([\/\s])?([\d\.]+)?.*/', '\2', $version);
1347
1348
    if (strpos($version, '.') === false) {
1349
        $version = number_format(doubleval($version), 1);
1350
    }
1351
    $return = ['name' => $navigator, 'version' => $version];
1352
1353
    return $return;
1354
}
1355
1356
/**
1357
 * @return true if user self registration is allowed, false otherwise
1358
 */
1359
function api_is_self_registration_allowed()
1360
{
1361
    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...
1362
}
1363
1364
/**
1365
 * This function returns the id of the user which is stored in the $_user array.
1366
 *
1367
 * example: The function can be used to check if a user is logged in
1368
 *          if (api_get_user_id())
1369
 *
1370
 * @return int the id of the current user, 0 if is empty
1371
 */
1372
function api_get_user_id()
1373
{
1374
    $userInfo = Session::read('_user');
1375
    if ($userInfo && isset($userInfo['user_id'])) {
1376
        return (int) $userInfo['user_id'];
1377
    }
1378
1379
    return 0;
1380
}
1381
1382
/**
1383
 * Gets the list of courses a specific user is subscribed to.
1384
 *
1385
 * @param int       User ID
1386
 * @param bool $fetch_session Whether to get session courses or not - NOT YET IMPLEMENTED
1387
 *
1388
 * @return array Array of courses in the form [0]=>('code'=>xxx,'db'=>xxx,'dir'=>xxx,'status'=>d)
1389
 *
1390
 * @deprecated use CourseManager::get_courses_list_by_user_id()
1391
 */
1392
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

1392
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...
1393
{
1394
    // Get out if not integer
1395
    if ($userId != strval(intval($userId))) {
1396
        return [];
1397
    }
1398
1399
    $t_course = Database::get_main_table(TABLE_MAIN_COURSE);
1400
    $t_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
1401
1402
    $sql = "SELECT cc.id as real_id, cc.code code, cc.directory dir, cu.status status
1403
            FROM $t_course cc, $t_course_user cu
1404
            WHERE
1405
                cc.id = cu.c_id AND
1406
                cu.user_id = $userId AND
1407
                cu.relation_type <> ".COURSE_RELATION_TYPE_RRHH;
1408
    $result = Database::query($sql);
1409
    if ($result === false) {
1410
        return [];
1411
    }
1412
1413
    $courses = [];
1414
    while ($row = Database::fetch_array($result)) {
1415
        // we only need the database name of the course
1416
        $courses[] = $row;
1417
    }
1418
1419
    return $courses;
1420
}
1421
1422
/**
1423
 * Formats user information into a standard array
1424
 * This function should be only used inside api_get_user_info().
1425
 *
1426
 * @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...
1427
 * @param bool $add_password
1428
 * @param bool $loadAvatars  turn off to improve performance
1429
 *
1430
 * @return array Standard user array
1431
 */
1432
function _api_format_user($user, $add_password = false, $loadAvatars = true)
1433
{
1434
    $result = [];
1435
1436
    if (!isset($user['user_id'])) {
1437
        return [];
1438
    }
1439
1440
    $result['firstname'] = null;
1441
    $result['lastname'] = null;
1442
1443
    if (isset($user['firstname']) && isset($user['lastname'])) {
1444
        // with only lowercase
1445
        $result['firstname'] = $user['firstname'];
1446
        $result['lastname'] = $user['lastname'];
1447
    } elseif (isset($user['firstName']) && isset($user['lastName'])) {
1448
        // with uppercase letters
1449
        $result['firstname'] = isset($user['firstName']) ? $user['firstName'] : null;
1450
        $result['lastname'] = isset($user['lastName']) ? $user['lastName'] : null;
1451
    }
1452
1453
    if (isset($user['email'])) {
1454
        $result['mail'] = isset($user['email']) ? $user['email'] : null;
1455
        $result['email'] = isset($user['email']) ? $user['email'] : null;
1456
    } else {
1457
        $result['mail'] = isset($user['mail']) ? $user['mail'] : null;
1458
        $result['email'] = isset($user['mail']) ? $user['mail'] : null;
1459
    }
1460
1461
    $result['complete_name'] = api_get_person_name($result['firstname'], $result['lastname']);
1462
    $result['complete_name_with_username'] = $result['complete_name'];
1463
1464
    if (!empty($user['username']) && api_get_setting('profile.hide_username_with_complete_name') === 'false') {
1465
        $result['complete_name_with_username'] = $result['complete_name'].' ('.$user['username'].')';
1466
    }
1467
1468
    $showEmail = api_get_setting('show_email_addresses') === 'true';
1469
    if (!empty($user['email'])) {
1470
        $result['complete_name_with_email_forced'] = $result['complete_name'].' ('.$user['email'].')';
1471
        if ($showEmail) {
1472
            $result['complete_name_with_email'] = $result['complete_name'].' ('.$user['email'].')';
1473
        }
1474
    } else {
1475
        $result['complete_name_with_email'] = $result['complete_name'];
1476
        $result['complete_name_with_email_forced'] = $result['complete_name'];
1477
    }
1478
1479
    // Kept for historical reasons
1480
    $result['firstName'] = $result['firstname'];
1481
    $result['lastName'] = $result['lastname'];
1482
1483
    $attributes = [
1484
        'phone',
1485
        'address',
1486
        'picture_uri',
1487
        'official_code',
1488
        'status',
1489
        'active',
1490
        'auth_source',
1491
        'username',
1492
        'theme',
1493
        'language',
1494
        'creator_id',
1495
        'registration_date',
1496
        'hr_dept_id',
1497
        'expiration_date',
1498
        'last_login',
1499
        'user_is_online',
1500
    ];
1501
1502
    if (api_get_setting('extended_profile') === 'true') {
1503
        $attributes[] = 'competences';
1504
        $attributes[] = 'diplomas';
1505
        $attributes[] = 'teach';
1506
        $attributes[] = 'openarea';
1507
    }
1508
1509
    foreach ($attributes as $attribute) {
1510
        $result[$attribute] = isset($user[$attribute]) ? $user[$attribute] : null;
1511
    }
1512
1513
    $user_id = (int) $user['user_id'];
1514
    // Maintain the user_id index for backwards compatibility
1515
    $result['user_id'] = $result['id'] = $user_id;
1516
1517
    // Getting user avatar.
1518
    if ($loadAvatars) {
1519
        $result['avatar'] = '';
1520
        $result['avatar_no_query'] = '';
1521
        $result['avatar_small'] = '';
1522
        $result['avatar_medium'] = '';
1523
1524
        if (!isset($user['avatar'])) {
1525
            $originalFile = UserManager::getUserPicture(
1526
                $user_id,
1527
                USER_IMAGE_SIZE_ORIGINAL,
1528
                null,
1529
                $result
1530
            );
1531
            $result['avatar'] = $originalFile;
1532
            $avatarString = explode('?', $result['avatar']);
1533
            $result['avatar_no_query'] = reset($avatarString);
1534
        } else {
1535
            $result['avatar'] = $user['avatar'];
1536
            $avatarString = explode('?', $user['avatar']);
1537
            $result['avatar_no_query'] = reset($avatarString);
1538
        }
1539
1540
        if (!isset($user['avatar_small'])) {
1541
            $smallFile = UserManager::getUserPicture(
1542
                $user_id,
1543
                USER_IMAGE_SIZE_SMALL,
1544
                null,
1545
                $result
1546
            );
1547
            $result['avatar_small'] = $smallFile;
1548
        } else {
1549
            $result['avatar_small'] = $user['avatar_small'];
1550
        }
1551
1552
        if (!isset($user['avatar_medium'])) {
1553
            $mediumFile = UserManager::getUserPicture(
1554
                $user_id,
1555
                USER_IMAGE_SIZE_MEDIUM,
1556
                null,
1557
                $result
1558
            );
1559
            $result['avatar_medium'] = $mediumFile;
1560
        } else {
1561
            $result['avatar_medium'] = $user['avatar_medium'];
1562
        }
1563
    }
1564
1565
    if (isset($user['user_is_online'])) {
1566
        $result['user_is_online'] = $user['user_is_online'] == true ? 1 : 0;
1567
    }
1568
    if (isset($user['user_is_online_in_chat'])) {
1569
        $result['user_is_online_in_chat'] = (int) $user['user_is_online_in_chat'];
1570
    }
1571
1572
    if ($add_password) {
1573
        $result['password'] = $user['password'];
1574
    }
1575
1576
    if (isset($result['profile_completed'])) {
1577
        $result['profile_completed'] = $user['profile_completed'];
1578
    }
1579
1580
    $result['profile_url'] = api_get_path(WEB_CODE_PATH).'social/profile.php?u='.$user_id;
1581
1582
    // Send message link
1583
    $sendMessage = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&user_id='.$user_id;
1584
    $result['complete_name_with_message_link'] = Display::url(
1585
        $result['complete_name_with_username'],
1586
        $sendMessage,
1587
        ['class' => 'ajax']
1588
    );
1589
1590
    if (isset($user['extra'])) {
1591
        $result['extra'] = $user['extra'];
1592
    }
1593
1594
    return $result;
1595
}
1596
1597
/**
1598
 * Finds all the information about a user.
1599
 * If no parameter is passed you find all the information about the current user.
1600
 *
1601
 * @param int  $user_id
1602
 * @param bool $checkIfUserOnline
1603
 * @param bool $showPassword
1604
 * @param bool $loadExtraData
1605
 * @param bool $loadOnlyVisibleExtraData Get the user extra fields that are visible
1606
 * @param bool $loadAvatars              turn off to improve performance and if avatars are not needed
1607
 * @param bool $updateCache              update apc cache if exists
1608
 *
1609
 * @return array $user_info user_id, lastname, firstname, username, email, etc
1610
 *
1611
 * @author Patrick Cool <[email protected]>
1612
 * @author Julio Montoya
1613
 *
1614
 * @version 21 September 2004
1615
 */
1616
function api_get_user_info(
1617
    $user_id = 0,
1618
    $checkIfUserOnline = false,
1619
    $showPassword = false,
1620
    $loadExtraData = false,
1621
    $loadOnlyVisibleExtraData = false,
1622
    $loadAvatars = true,
1623
    $updateCache = false
1624
) {
1625
    $apcVar = null;
1626
    $user = false;
1627
    $cacheAvailable = api_get_configuration_value('apc');
1628
1629
    if (empty($user_id)) {
1630
        $userFromSession = Session::read('_user');
1631
1632
        if (isset($userFromSession)) {
1633
            if ($cacheAvailable === true) {
1634
                $apcVar = api_get_configuration_value('apc_prefix').'userinfo_'.$userFromSession['user_id'];
1635
                if (apcu_exists($apcVar)) {
1636
                    if ($updateCache) {
1637
                        apcu_store($apcVar, $userFromSession, 60);
1638
                    }
1639
                    $user = apcu_fetch($apcVar);
1640
                } else {
1641
                    $user = _api_format_user(
1642
                        $userFromSession,
1643
                        $showPassword,
1644
                        $loadAvatars
1645
                    );
1646
                    apcu_store($apcVar, $user, 60);
1647
                }
1648
            } else {
1649
                $user = _api_format_user(
1650
                    $userFromSession,
1651
                    $showPassword,
1652
                    $loadAvatars
1653
                );
1654
            }
1655
1656
            return $user;
1657
        }
1658
1659
        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...
1660
    }
1661
1662
    // Make sure user_id is safe
1663
    $user_id = (int) $user_id;
1664
1665
    // Re-use user information if not stale and already stored in APCu
1666
    if ($cacheAvailable === true) {
1667
        $apcVar = api_get_configuration_value('apc_prefix').'userinfo_'.$user_id;
1668
        if (apcu_exists($apcVar) && $updateCache == false && $checkIfUserOnline == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

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

Loading history...
1669
            $user = apcu_fetch($apcVar);
1670
1671
            return $user;
1672
        }
1673
    }
1674
1675
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1676
            WHERE id = $user_id";
1677
    $result = Database::query($sql);
1678
    if (Database::num_rows($result) > 0) {
1679
        $result_array = Database::fetch_array($result);
1680
        if ($checkIfUserOnline) {
1681
            $use_status_in_platform = user_is_online($user_id);
1682
            $result_array['user_is_online'] = $use_status_in_platform;
1683
            $user_online_in_chat = 0;
1684
1685
            if ($use_status_in_platform) {
1686
                $user_status = UserManager::get_extra_user_data_by_field(
1687
                    $user_id,
1688
                    'user_chat_status',
1689
                    false,
1690
                    true
1691
                );
1692
                if ((int) $user_status['user_chat_status'] == 1) {
1693
                    $user_online_in_chat = 1;
1694
                }
1695
            }
1696
            $result_array['user_is_online_in_chat'] = $user_online_in_chat;
1697
        }
1698
1699
        if ($loadExtraData) {
1700
            $fieldValue = new ExtraFieldValue('user');
1701
            $result_array['extra'] = $fieldValue->getAllValuesForAnItem(
1702
                $user_id,
1703
                $loadOnlyVisibleExtraData
1704
            );
1705
        }
1706
        $user = _api_format_user($result_array, $showPassword, $loadAvatars);
1707
    }
1708
1709
    if ($cacheAvailable === true) {
1710
        apcu_store($apcVar, $user, 60);
1711
    }
1712
1713
    return $user;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $user could also return false which is incompatible with the documented return type array. 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...
1714
}
1715
1716
/**
1717
 * @param int $userId
1718
 *
1719
 * @return User
1720
 */
1721
function api_get_user_entity($userId)
1722
{
1723
    $userId = (int) $userId;
1724
    $repo = UserManager::getRepository();
1725
1726
    /** @var User $user */
1727
    $user = $repo->find($userId);
1728
1729
    return $user;
1730
}
1731
1732
/**
1733
 * @return null|User
1734
 */
1735
function api_get_current_user()
1736
{
1737
    $token = Container::$container->get('security.token_storage')->getToken();
1738
    if (null !== $token) {
1739
        return $token->getUser();
1740
    }
1741
1742
    return null;
1743
}
1744
1745
/**
1746
 * Finds all the information about a user from username instead of user id.
1747
 *
1748
 * @param string $username
1749
 *
1750
 * @return mixed $user_info array user_id, lastname, firstname, username, email or false on error
1751
 *
1752
 * @author Yannick Warnier <[email protected]>
1753
 */
1754
function api_get_user_info_from_username($username = '')
1755
{
1756
    if (empty($username)) {
1757
        return false;
1758
    }
1759
    $username = trim($username);
1760
1761
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1762
            WHERE username='".Database::escape_string($username)."'";
1763
    $result = Database::query($sql);
1764
    if (Database::num_rows($result) > 0) {
1765
        $resultArray = Database::fetch_array($result);
1766
1767
        return _api_format_user($resultArray);
1768
    }
1769
1770
    return false;
1771
}
1772
1773
/**
1774
 * Get first user with an email.
1775
 *
1776
 * @param string $email
1777
 *
1778
 * @return array|bool
1779
 */
1780
function api_get_user_info_from_email($email = '')
1781
{
1782
    if (empty($email)) {
1783
        return false;
1784
    }
1785
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1786
            WHERE email ='".Database::escape_string($email)."' LIMIT 1";
1787
    $result = Database::query($sql);
1788
    if (Database::num_rows($result) > 0) {
1789
        $resultArray = Database::fetch_array($result);
1790
1791
        return _api_format_user($resultArray);
1792
    }
1793
1794
    return false;
1795
}
1796
1797
/**
1798
 * @return string
1799
 */
1800
function api_get_course_id()
1801
{
1802
    return Session::read('_cid', null);
1803
}
1804
1805
/**
1806
 * Returns the current course id (integer).
1807
 *
1808
 * @param string $code Optional course code
1809
 *
1810
 * @return int
1811
 */
1812
function api_get_course_int_id($code = null)
1813
{
1814
    if (!empty($code)) {
1815
        $code = Database::escape_string($code);
1816
        $row = Database::select(
1817
            'id',
1818
            Database::get_main_table(TABLE_MAIN_COURSE),
1819
            ['where' => ['code = ?' => [$code]]],
1820
            'first'
1821
        );
1822
1823
        if (is_array($row) && isset($row['id'])) {
1824
            return $row['id'];
1825
        } else {
1826
            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...
1827
        }
1828
    }
1829
1830
    return Session::read('_real_cid', 0);
1831
}
1832
1833
/**
1834
 * Returns the current course directory.
1835
 *
1836
 * This function relies on api_get_course_info()
1837
 *
1838
 * @param string    The course code - optional (takes it from session if not given)
1839
 *
1840
 * @return string The directory where the course is located inside the Chamilo "courses" directory
1841
 *
1842
 * @author Yannick Warnier <[email protected]>
1843
 */
1844
function api_get_course_path($course_code = null)
1845
{
1846
    $info = !empty($course_code) ? api_get_course_info($course_code) : api_get_course_info();
1847
1848
    return $info['path'];
1849
}
1850
1851
/**
1852
 * Gets a course setting from the current course_setting table. Try always using integer values.
1853
 *
1854
 * @param string    The name of the setting we want from the table
1855
 * @param string    Optional: course code
1856
 * @param string $setting_name
1857
 *
1858
 * @return mixed The value of that setting in that table. Return -1 if not found.
1859
 */
1860
function api_get_course_setting($setting_name, $course_code = null)
1861
{
1862
    $course_info = api_get_course_info($course_code);
1863
    $table = Database::get_course_table(TABLE_COURSE_SETTING);
1864
    $setting_name = Database::escape_string($setting_name);
1865
    if (!empty($course_info['real_id']) && !empty($setting_name)) {
1866
        $sql = "SELECT value FROM $table
1867
                WHERE c_id = {$course_info['real_id']} AND variable = '$setting_name'";
1868
        $res = Database::query($sql);
1869
        if (Database::num_rows($res) > 0) {
1870
            $row = Database::fetch_array($res);
1871
            if ($setting_name === 'email_alert_manager_on_new_quiz') {
1872
                if (!is_null($row['value'])) {
1873
                    $result = explode(',', $row['value']);
1874
                    $row['value'] = $result;
1875
                }
1876
            }
1877
1878
            return $row['value'];
1879
        }
1880
    }
1881
1882
    return -1;
1883
}
1884
1885
/**
1886
 * Gets an anonymous user ID.
1887
 *
1888
 * For some tools that need tracking, like the learnpath tool, it is necessary
1889
 * to have a usable user-id to enable some kind of tracking, even if not
1890
 * perfect. An anonymous ID is taken from the users table by looking for a
1891
 * status of "6" (anonymous).
1892
 *
1893
 * @return int User ID of the anonymous user, or O if no anonymous user found
1894
 */
1895
function api_get_anonymous_id()
1896
{
1897
    // Find if another anon is connected now
1898
    $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
1899
    $tableU = Database::get_main_table(TABLE_MAIN_USER);
1900
    $ip = Database::escape_string(api_get_real_ip());
1901
    $max = api_get_configuration_value('max_anonymous_users');
1902
    if ($max >= 2) {
1903
        $sql = "SELECT * FROM $table as TEL 
1904
                JOIN $tableU as U
1905
                ON U.user_id = TEL.login_user_id
1906
                WHERE TEL.user_ip = '$ip'
1907
                    AND U.status = ".ANONYMOUS."
1908
                    AND U.user_id != 2 ";
1909
1910
        $result = Database::query($sql);
1911
        if (empty(Database::num_rows($result))) {
1912
            $login = uniqid('anon_');
1913
            $anonList = UserManager::get_user_list(['status' => ANONYMOUS], ['registration_date ASC']);
1914
            if (count($anonList) == $max) {
1915
                foreach ($anonList as $userToDelete) {
1916
                    UserManager::delete_user($userToDelete['user_id']);
1917
                    break;
1918
                }
1919
            }
1920
            $userId = UserManager::create_user(
1921
                $login,
1922
                'anon',
1923
                ANONYMOUS,
1924
                ' anonymous@localhost',
1925
                $login,
1926
                $login
1927
            );
1928
1929
            return $userId;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $userId could also return false which is incompatible with the documented return type integer. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
1930
        } else {
1931
            $row = Database::fetch_array($result, 'ASSOC');
1932
1933
            return $row['user_id'];
1934
        }
1935
    }
1936
1937
    $table = Database::get_main_table(TABLE_MAIN_USER);
1938
    $sql = "SELECT user_id 
1939
            FROM $table 
1940
            WHERE status = ".ANONYMOUS." ";
1941
    $res = Database::query($sql);
1942
    if (Database::num_rows($res) > 0) {
1943
        $row = Database::fetch_array($res, 'ASSOC');
1944
1945
        return $row['user_id'];
1946
    }
1947
1948
    // No anonymous user was found.
1949
    return 0;
1950
}
1951
1952
/**
1953
 * @param string $courseCode
1954
 * @param int    $sessionId
1955
 * @param int    $groupId
1956
 *
1957
 * @return string
1958
 */
1959
function api_get_cidreq_params($courseCode, $sessionId = 0, $groupId = 0)
1960
{
1961
    $courseCode = !empty($courseCode) ? htmlspecialchars($courseCode) : '';
1962
    $sessionId = !empty($sessionId) ? (int) $sessionId : 0;
1963
    $groupId = !empty($groupId) ? (int) $groupId : 0;
1964
1965
    $url = 'cidReq='.$courseCode;
1966
    $url .= '&id_session='.$sessionId;
1967
    $url .= '&gidReq='.$groupId;
1968
1969
    return $url;
1970
}
1971
1972
/**
1973
 * Returns the current course url part including session, group, and gradebook params.
1974
 *
1975
 * @param bool   $addSessionId
1976
 * @param bool   $addGroupId
1977
 * @param string $origin
1978
 *
1979
 * @return string Course & session references to add to a URL
1980
 */
1981
function api_get_cidreq($addSessionId = true, $addGroupId = true, $origin = '')
1982
{
1983
    $courseCode = api_get_course_id();
1984
    $url = empty($courseCode) ? '' : 'cidReq='.htmlspecialchars($courseCode);
1985
    $origin = empty($origin) ? api_get_origin() : Security::remove_XSS($origin);
1986
1987
    if ($addSessionId) {
1988
        if (!empty($url)) {
1989
            $url .= api_get_session_id() == 0 ? '&id_session=0' : '&id_session='.api_get_session_id();
1990
        }
1991
    }
1992
1993
    if ($addGroupId) {
1994
        if (!empty($url)) {
1995
            $url .= api_get_group_id() == 0 ? '&gidReq=0' : '&gidReq='.api_get_group_id();
1996
        }
1997
    }
1998
1999
    if (!empty($url)) {
2000
        $url .= '&gradebook='.(int) api_is_in_gradebook();
2001
        $url .= '&origin='.$origin;
2002
    }
2003
2004
    return $url;
2005
}
2006
2007
/**
2008
 * Get if we visited a gradebook page.
2009
 *
2010
 * @return bool
2011
 */
2012
function api_is_in_gradebook()
2013
{
2014
    return Session::read('in_gradebook', false);
2015
}
2016
2017
/**
2018
 * Set that we are in a page inside a gradebook.
2019
 *
2020
 * @return bool
2021
 */
2022
function api_set_in_gradebook()
2023
{
2024
    Session::write('in_gradebook', true);
2025
}
2026
2027
/**
2028
 * Remove gradebook session.
2029
 */
2030
function api_remove_in_gradebook()
2031
{
2032
    Session::erase('in_gradebook');
2033
}
2034
2035
/**
2036
 * Returns the current course info array see api_format_course_array()
2037
 * If the course_code is given, the returned array gives info about that
2038
 * particular course, if none given it gets the course info from the session.
2039
 *
2040
 * @param string $course_code
2041
 * @param bool   $strict
2042
 *
2043
 * @return array
2044
 */
2045
function api_get_course_info($course_code = null, $strict = false)
0 ignored issues
show
Unused Code introduced by
The parameter $strict 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

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

3771
    /** @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...
3772
    $message = null,
3773
    $responseCode = 0
3774
) {
3775
    $debug = api_get_setting('server_type') == 'test';
3776
3777
    // Default code is 403 forbidden
3778
    $responseCode = empty($responseCode) ? 403 : $responseCode;
3779
    $message = empty($message) ? get_lang('NotAuthorized') : $message;
3780
3781
    // Create new exception rendered by template:
3782
    // src/ThemeBundle/Resources/views/Exception/error.html.twig
3783
3784
    // if error is 404 then the template is:
3785
    // src/ThemeBundle/Resources/views/Exception/error404.html.twig
3786
    $exception = new Exception($message);
3787
    $request = Container::getRequest();
3788
    $exception = \Symfony\Component\Debug\Exception\FlattenException::create($exception, $responseCode);
3789
    $controller = new \Chamilo\ThemeBundle\Controller\ExceptionController(Container::getTwig(), $debug);
3790
    $response = $controller->showAction($request, $exception);
3791
    $response->send();
3792
    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...
3793
3794
    if (api_get_setting('sso_authentication') === 'true') {
0 ignored issues
show
Unused Code introduced by
IfNode 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...
3795
        global $osso;
3796
        if ($osso) {
3797
            $osso->logout();
3798
        }
3799
    }
3800
3801
    $home_url = api_get_path(WEB_PATH);
3802
    $user_id = api_get_user_id();
3803
    $course = api_get_course_id();
3804
3805
    global $this_section;
3806
3807
    if (CustomPages::enabled() && !isset($user_id)) {
3808
        if (empty($user_id)) {
3809
            // Why the CustomPages::enabled() need to be to set the request_uri
3810
            $_SESSION['request_uri'] = $_SERVER['REQUEST_URI'];
3811
        }
3812
        CustomPages::display(CustomPages::INDEX_UNLOGGED);
3813
    }
3814
3815
    $origin = api_get_origin();
3816
3817
    $msg = null;
3818
    if (isset($message)) {
3819
        $msg = $message;
3820
    } else {
3821
        $msg = Display::return_message(
3822
            get_lang('NotAllowedClickBack').'
3823
            <script>function goBack(){window.history.back();}</script>',
3824
            'error',
3825
            false
3826
        );
3827
        $msg .= '<p class="text-center">
3828
             <a onclick="goBack();" class="btn btn-default" href="'.$home_url.'">'.get_lang('GoBack').'</a>
3829
             </p>';
3830
    }
3831
3832
    $msg = Display::div($msg, ['align' => 'center']);
3833
3834
    $show_headers = 0;
3835
    if ($print_headers && $origin != 'learnpath') {
3836
        $show_headers = 1;
3837
    }
3838
3839
    $tpl = new Template(null, $show_headers, $show_headers, false, true, false, true, $responseCode);
3840
    $tpl->assign('hide_login_link', 1);
3841
    $tpl->assign('content', $msg);
3842
3843
    if (($user_id != 0 && !api_is_anonymous()) &&
3844
        (!isset($course) || $course == -1) &&
3845
        empty($_GET['cidReq'])
3846
    ) {
3847
        // if the access is not authorized and there is some login information
3848
        // but the cidReq is not found, assume we are missing course data and send the user
3849
        // to the user_portal
3850
        $tpl->display_one_col_template();
3851
        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...
3852
    }
3853
3854
    if (!empty($_SERVER['REQUEST_URI']) &&
3855
        (
3856
            !empty($_GET['cidReq']) ||
3857
            $this_section == SECTION_MYPROFILE ||
3858
            $this_section == SECTION_PLATFORM_ADMIN
3859
        )
3860
    ) {
3861
        $courseCode = api_get_course_id();
3862
        // Only display form and return to the previous URL if there was a course ID included
3863
        if ($user_id != 0 && !api_is_anonymous()) {
3864
            //if there is a user ID, then the user is not allowed but the session is still there. Say so and exit
3865
            $tpl->assign('content', $msg);
3866
            $tpl->display_one_col_template();
3867
            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...
3868
        }
3869
3870
        if (!is_null($courseCode)) {
3871
            api_set_firstpage_parameter($courseCode);
3872
        }
3873
3874
        // If the user has no user ID, then his session has expired
3875
        $form = api_get_not_allowed_login_form();
3876
3877
        // see same text in auth/gotocourse.php and main_api.lib.php function api_not_allowed (above)
3878
        $content = Display::return_message(get_lang('NotAllowed'), 'error', false);
3879
3880
        if (!empty($courseCode)) {
3881
            $content .= '<h4>'.get_lang('LoginToGoToThisCourse').'</h4>';
3882
        }
3883
3884
        if (api_is_cas_activated()) {
3885
            $content .= Display::return_message(sprintf(get_lang('YouHaveAnInstitutionalAccount'), api_get_setting("Institution")), '', false);
3886
            $content .= Display::div(
3887
                "<br/><a href='".get_cas_direct_URL(api_get_course_id())."'>".sprintf(get_lang('LoginWithYourAccount'), api_get_setting("Institution"))."</a><br/><br/>",
3888
                ['align' => 'center']
3889
            );
3890
            $content .= Display::return_message(get_lang('YouDontHaveAnInstitutionAccount'));
3891
            $content .= "<p style='text-align:center'><a href='#' onclick='$(this).parent().next().toggle()'>".get_lang('LoginWithExternalAccount')."</a></p>";
3892
            $content .= "<div style='display:none;'>";
3893
        }
3894
        $content .= '<div class="well">';
3895
        $content .= $form->returnForm();
3896
        $content .= '</div>';
3897
        if (api_is_cas_activated()) {
3898
            $content .= "</div>";
3899
        }
3900
3901
        if (!empty($courseCode)) {
3902
            $content .= '<hr/><p style="text-align:center"><a href="'.$home_url.'">'.
3903
                get_lang('ReturnToCourseHomepage').'</a></p>';
3904
        } else {
3905
            $content .= '<hr/><p style="text-align:center"><a href="'.$home_url.'">'.
3906
                get_lang('BackHome').'</a></p>';
3907
        }
3908
3909
        $tpl->setLoginBodyClass();
3910
        $tpl->assign('content', $content);
3911
        $tpl->display_one_col_template();
3912
        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...
3913
    }
3914
3915
    if ($user_id != 0 && !api_is_anonymous()) {
3916
        $tpl->display_one_col_template();
3917
        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...
3918
    }
3919
3920
    $msg = null;
3921
    // The session is over and we were not in a course,
3922
    // or we try to get directly to a private course without being logged
3923
    $courseId = api_get_course_int_id();
3924
    if (!empty($courseId)) {
3925
        api_set_firstpage_parameter(api_get_course_id());
3926
        $tpl->setLoginBodyClass();
3927
3928
        // see same text in auth/gotocourse.php and main_api.lib.php function api_not_allowed (bellow)
3929
        $msg = Display::return_message(get_lang('NotAllowed'), 'error', false);
3930
        $msg .= '<h4>'.get_lang('LoginToGoToThisCourse').'</h4>';
3931
        $casEnabled = api_is_cas_activated();
3932
        if ($casEnabled) {
3933
            $msg .= Display::return_message(
3934
                sprintf(get_lang('YouHaveAnInstitutionalAccount'), api_get_setting("Institution")),
3935
                '',
3936
                false
3937
            );
3938
            $msg .= Display::div("<br/><a href='".get_cas_direct_URL(api_get_course_int_id())."'>".getCASLogoHTML()." ".sprintf(get_lang('LoginWithYourAccount'), api_get_setting("Institution"))."</a><br/><br/>", ['align' => 'center']);
3939
            $msg .= Display::return_message(get_lang('YouDontHaveAnInstitutionAccount'));
3940
            $msg .= "<p style='text-align:center'><a href='#' onclick='$(this).parent().next().toggle()'>".get_lang('LoginWithExternalAccount')."</a></p>";
3941
            $msg .= "<div style='display:none;'>";
3942
        }
3943
        $form = api_get_not_allowed_login_form();
3944
        $msg .= '<div class="well">';
3945
        $msg .= $form->returnForm();
3946
        $msg .= '</div>';
3947
        if ($casEnabled) {
3948
            $msg .= "</div>";
3949
        }
3950
    } else {
3951
        // we were not in a course, return to home page
3952
        $msg = Display::return_message(
3953
            get_lang('NotAllowed'),
3954
            'error',
3955
            false
3956
        );
3957
3958
        $msg .= '<p class="text-center">
3959
                 <a class="btn btn-default" href="'.$home_url.'">'.get_lang('BackHome').'</a>
3960
                 </p>';
3961
3962
        if (!empty($message)) {
3963
            $msg = $message;
3964
        }
3965
3966
        if (api_is_anonymous()) {
3967
            $form = api_get_not_allowed_login_form();
3968
            $msg .= '<div class="well">';
3969
            $msg .= $form->returnForm();
3970
            $msg .= '</div>';
3971
        }
3972
    }
3973
3974
    $tpl->assign('content', $msg);
3975
    $tpl->display_one_col_template();
3976
    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...
3977
}
3978
3979
/**
3980
 * @return FormValidator
3981
 */
3982
function api_get_not_allowed_login_form()
3983
{
3984
    $action = api_get_self().'?'.Security::remove_XSS($_SERVER['QUERY_STRING']);
3985
    $action = str_replace('&amp;', '&', $action);
3986
    Session::write('redirect_after_not_allow_page', $action);
3987
    $action .= '&redirect_after_not_allow_page=1';
3988
3989
    $form = new FormValidator(
3990
        'formLogin',
3991
        'post',
3992
        $action,
3993
        null,
3994
        ['class' => 'form-stacked']
3995
    );
3996
    $params = [
3997
        'placeholder' => get_lang('UserName'),
3998
        'class' => 'col-md-3',
3999
    ];
4000
    if (api_browser_support('autocapitalize')) {
4001
        $params['autocapitalize'] = 'none';
4002
    }
4003
4004
    $form->addElement(
4005
        'text',
4006
        'login',
4007
        null,
4008
        $params
4009
    );
4010
    $form->addElement(
4011
        'password',
4012
        'password',
4013
        null,
4014
        ['placeholder' => get_lang('Password'), 'class' => 'col-md-3']
4015
    ); //new
4016
    $form->addButtonNext(get_lang('LoginEnter'), 'submitAuth');
4017
4018
    return $form;
4019
}
4020
4021
/**
4022
 * Gets a UNIX timestamp from a database (MySQL) datetime format string.
4023
 *
4024
 * @param $last_post_datetime standard output date in a sql query
4025
 *
4026
 * @return int timestamp
4027
 *
4028
 * @author Toon Van Hoecke <[email protected]>
4029
 *
4030
 * @version October 2003
4031
 * @desc convert sql date to unix timestamp
4032
 */
4033
function convert_sql_date($last_post_datetime)
4034
{
4035
    list($last_post_date, $last_post_time) = explode(' ', $last_post_datetime);
4036
    list($year, $month, $day) = explode('-', $last_post_date);
4037
    list($hour, $min, $sec) = explode(':', $last_post_time);
4038
4039
    return mktime((int) $hour, (int) $min, (int) $sec, (int) $month, (int) $day, (int) $year);
4040
}
4041
4042
/**
4043
 * Gets item visibility from the item_property table.
4044
 *
4045
 * Getting the visibility is done by getting the last updated visibility entry,
4046
 * using the largest session ID found if session 0 and another was found (meaning
4047
 * the only one that is actually from the session, in case there are results from
4048
 * session 0 *AND* session n).
4049
 *
4050
 * @param array     Course properties array (result of api_get_course_info())
4051
 * @param string    Tool (learnpath, document, etc)
4052
 * @param int       The item ID in the given tool
4053
 * @param int       The session ID (optional)
4054
 * @param string $tool
4055
 * @param int    $user_id
4056
 * @param string $type
4057
 *
4058
 * @return int -1 on error, 0 if invisible, 1 if visible
4059
 */
4060
function api_get_item_visibility(
4061
    $_course,
4062
    $tool,
4063
    $id,
4064
    $session = 0,
4065
    $user_id = null,
4066
    $type = null,
4067
    $group_id = null
4068
) {
4069
    if (!is_array($_course) || count($_course) == 0 || empty($tool) || empty($id)) {
4070
        return -1;
4071
    }
4072
4073
    $tool = Database::escape_string($tool);
4074
    $id = (int) $id;
4075
    $session = (int) $session;
4076
    $TABLE_ITEMPROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY);
4077
    $course_id = (int) $_course['real_id'];
4078
4079
    $userCondition = '';
4080
    if (!empty($user_id)) {
4081
        $user_id = (int) $user_id;
4082
        $userCondition = " AND to_user_id = $user_id ";
4083
    }
4084
4085
    $typeCondition = '';
4086
    if (!empty($type)) {
4087
        $type = Database::escape_string($type);
4088
        $typeCondition = " AND lastedit_type = '$type' ";
4089
    }
4090
4091
    $groupCondition = '';
4092
    if (!empty($group_id)) {
4093
        $group_id = (int) $group_id;
4094
        $groupCondition = " AND to_group_id = '$group_id' ";
4095
    }
4096
4097
    $sql = "SELECT visibility
4098
            FROM $TABLE_ITEMPROPERTY
4099
            WHERE
4100
                c_id = $course_id AND
4101
                tool = '$tool' AND
4102
                ref = $id AND
4103
                (session_id = $session OR session_id = 0 OR session_id IS NULL)
4104
                $userCondition $typeCondition $groupCondition
4105
            ORDER BY session_id DESC, lastedit_date DESC
4106
            LIMIT 1";
4107
4108
    $res = Database::query($sql);
4109
    if ($res === false || Database::num_rows($res) == 0) {
4110
        return -1;
4111
    }
4112
    $row = Database::fetch_array($res);
4113
4114
    return (int) $row['visibility'];
4115
}
4116
4117
/**
4118
 * Delete a row in the c_item_property table.
4119
 *
4120
 * @param array  $courseInfo
4121
 * @param string $tool
4122
 * @param int    $itemId
4123
 * @param int    $userId
4124
 * @param int    $groupId    group.iid
4125
 * @param int    $sessionId
4126
 *
4127
 * @return false|null
4128
 */
4129
function api_item_property_delete(
4130
    $courseInfo,
4131
    $tool,
4132
    $itemId,
4133
    $userId,
4134
    $groupId = 0,
4135
    $sessionId = 0
4136
) {
4137
    if (empty($courseInfo)) {
4138
        return false;
4139
    }
4140
4141
    $courseId = (int) $courseInfo['real_id'];
4142
4143
    if (empty($courseId) || empty($tool) || empty($itemId)) {
4144
        return false;
4145
    }
4146
4147
    $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4148
    $tool = Database::escape_string($tool);
4149
    $itemId = intval($itemId);
4150
    $userId = intval($userId);
4151
    $groupId = intval($groupId);
4152
    $sessionId = intval($sessionId);
4153
4154
    $groupCondition = " AND to_group_id = $groupId ";
4155
    if (empty($groupId)) {
4156
        $groupCondition = " AND (to_group_id is NULL OR to_group_id = 0) ";
4157
    }
4158
4159
    $userCondition = " AND to_user_id = $userId ";
4160
    if (empty($userId)) {
4161
        $userCondition = " AND (to_user_id is NULL OR to_user_id = 0) ";
4162
    }
4163
    $sessionCondition = api_get_session_condition($sessionId, true, false, 'session_id');
4164
    $sql = "DELETE FROM $table
4165
            WHERE
4166
                c_id = $courseId AND
4167
                tool  = '$tool' AND
4168
                ref = $itemId
4169
                $sessionCondition
4170
                $userCondition
4171
                $groupCondition
4172
            ";
4173
4174
    Database::query($sql);
4175
}
4176
4177
/**
4178
 * Updates or adds item properties to the Item_propetry table
4179
 * Tool and lastedit_type are language independant strings (langvars->get_lang!).
4180
 *
4181
 * @param array  $_course        array with course properties
4182
 * @param string $tool           tool id, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4183
 * @param int    $item_id        id of the item itself, linked to key of every tool ('id', ...)
4184
 * @param string $last_edit_type add or update action
4185
 *                               (1) message to be translated (in trad4all) : e.g. DocumentAdded, DocumentUpdated;
4186
 *                               (2) "delete"
4187
 *                               (3) "visible"
4188
 *                               (4) "invisible"
4189
 * @param int    $user_id        id of the editing/adding user
4190
 * @param array  $groupInfo      must include group.iid/group.od
4191
 * @param int    $to_user_id     id of the intended user (always has priority over $to_group_id !), only relevant for $type (1)
4192
 * @param string $start_visible  0000-00-00 00:00:00 format
4193
 * @param string $end_visible    0000-00-00 00:00:00 format
4194
 * @param int    $session_id     The session ID, if any, otherwise will default to 0
4195
 *
4196
 * @return bool false if update fails
4197
 *
4198
 * @author Toon Van Hoecke <[email protected]>, Ghent University
4199
 *
4200
 * @version January 2005
4201
 * @desc update the item_properties table (if entry not exists, insert) of the course
4202
 */
4203
function api_item_property_update(
4204
    $_course,
4205
    $tool,
4206
    $item_id,
4207
    $last_edit_type,
4208
    $user_id,
4209
    $groupInfo = [],
4210
    $to_user_id = null,
4211
    $start_visible = '',
4212
    $end_visible = '',
4213
    $session_id = 0
4214
) {
4215
    if (empty($_course)) {
4216
        return false;
4217
    }
4218
4219
    $course_id = $_course['real_id'];
4220
4221
    if (empty($course_id)) {
4222
        return false;
4223
    }
4224
4225
    $to_group_id = 0;
4226
    if (!empty($groupInfo) && isset($groupInfo['iid'])) {
4227
        $to_group_id = (int) $groupInfo['iid'];
4228
    }
4229
4230
    $em = Database::getManager();
4231
4232
    // Definition of variables.
4233
    $tool = Database::escape_string($tool);
4234
    $item_id = (int) $item_id;
4235
    $lastEditTypeNoFilter = $last_edit_type;
4236
    $last_edit_type = Database::escape_string($last_edit_type);
4237
    $user_id = (int) $user_id;
4238
4239
    $startVisible = "NULL";
4240
    if (!empty($start_visible)) {
4241
        $start_visible = Database::escape_string($start_visible);
4242
        $startVisible = "'$start_visible'";
4243
    }
4244
4245
    $endVisible = "NULL";
4246
    if (!empty($end_visible)) {
4247
        $end_visible = Database::escape_string($end_visible);
4248
        $endVisible = "'$end_visible'";
4249
    }
4250
4251
    $to_filter = '';
4252
    $time = api_get_utc_datetime();
4253
4254
    if (!empty($session_id)) {
4255
        $session_id = (int) $session_id;
4256
    } else {
4257
        $session_id = api_get_session_id();
4258
    }
4259
4260
    // Definition of tables.
4261
    $tableItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
4262
4263
    if ($to_user_id <= 0) {
4264
        $to_user_id = null; // No to_user_id set
4265
    }
4266
4267
    if (!is_null($to_user_id)) {
4268
        // $to_user_id has more priority than $to_group_id
4269
        $to_user_id = (int) $to_user_id;
4270
        $to_field = 'to_user_id';
4271
        $to_value = $to_user_id;
4272
    } else {
4273
        // $to_user_id is not set.
4274
        $to_field = 'to_group_id';
4275
        $to_value = $to_group_id;
4276
    }
4277
4278
    $toValueCondition = empty($to_value) ? 'NULL' : "'$to_value'";
4279
    // Set filters for $to_user_id and $to_group_id, with priority for $to_user_id
4280
    $condition_session = " AND session_id = $session_id ";
4281
    if (empty($session_id)) {
4282
        $condition_session = ' AND (session_id = 0 OR session_id IS NULL) ';
4283
    }
4284
4285
    $filter = " c_id = $course_id AND tool = '$tool' AND ref = $item_id $condition_session ";
4286
4287
    // Check whether $to_user_id and $to_group_id are passed in the function call.
4288
    // If both are not passed (both are null) then it is a message for everybody and $to_group_id should be 0 !
4289
    if (is_null($to_user_id) && is_null($to_group_id)) {
4290
        $to_group_id = 0;
4291
    }
4292
4293
    if (!is_null($to_user_id)) {
4294
        // Set filter to intended user.
4295
        $to_filter = " AND to_user_id = $to_user_id $condition_session";
4296
    } else {
4297
        // Set filter to intended group.
4298
        if (($to_group_id != 0) && $to_group_id == strval(intval($to_group_id))) {
4299
            $to_filter = " AND to_group_id = $to_group_id $condition_session";
4300
        }
4301
    }
4302
4303
    // Adding filter if set.
4304
    $filter .= $to_filter;
4305
4306
    // Update if possible
4307
    $set_type = '';
4308
4309
    switch ($lastEditTypeNoFilter) {
4310
        case 'delete':
4311
            // delete = make item only visible for the platform admin.
4312
            $visibility = '2';
4313
            if (!empty($session_id)) {
4314
                // Check whether session id already exist into item_properties for updating visibility or add it.
4315
                $sql = "SELECT session_id FROM $tableItemProperty
4316
                        WHERE
4317
                            c_id = $course_id AND
4318
                            tool = '$tool' AND
4319
                            ref = $item_id AND
4320
                            session_id = $session_id";
4321
                $rs = Database::query($sql);
4322
                if (Database::num_rows($rs) > 0) {
4323
                    $sql = "UPDATE $tableItemProperty
4324
                            SET lastedit_type       = '".str_replace('_', '', ucwords($tool))."Deleted',
4325
                                lastedit_date       = '$time',
4326
                                lastedit_user_id    = $user_id,
4327
                                visibility          = $visibility,
4328
                                session_id          = $session_id $set_type
4329
                            WHERE $filter";
4330
                    $result = Database::query($sql);
4331
                } else {
4332
                    $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)
4333
                            VALUES ($course_id, '$tool',$item_id, '$time', $user_id, '$time', '$last_edit_type',$user_id, $toValueCondition, $visibility, $startVisible, $endVisible, $session_id)";
4334
                    $result = Database::query($sql);
4335
                    $id = Database::insert_id();
4336
                    if ($id) {
4337
                        $sql = "UPDATE $tableItemProperty SET id = iid WHERE iid = $id";
4338
                        Database::query($sql);
4339
                    }
4340
                }
4341
            } else {
4342
                $sql = "UPDATE $tableItemProperty
4343
                        SET
4344
                            lastedit_type='".str_replace('_', '', ucwords($tool))."Deleted',
4345
                            lastedit_date='$time',
4346
                            lastedit_user_id = $user_id,
4347
                            visibility = $visibility $set_type
4348
                        WHERE $filter";
4349
                $result = Database::query($sql);
4350
            }
4351
            break;
4352
        case 'visible': // Change item to visible.
4353
            $visibility = '1';
4354
            if (!empty($session_id)) {
4355
                // Check whether session id already exist into item_properties for updating visibility or add it.
4356
                $sql = "SELECT session_id FROM $tableItemProperty
4357
                        WHERE
4358
                            c_id = $course_id AND
4359
                            tool = '$tool' AND
4360
                            ref = $item_id AND
4361
                            session_id = $session_id";
4362
                $rs = Database::query($sql);
4363
                if (Database::num_rows($rs) > 0) {
4364
                    $sql = "UPDATE $tableItemProperty
4365
                            SET
4366
                                lastedit_type='".str_replace('_', '', ucwords($tool))."Visible',
4367
                                lastedit_date='$time',
4368
                                lastedit_user_id = $user_id,
4369
                                visibility = $visibility,
4370
                                session_id = $session_id $set_type
4371
                            WHERE $filter";
4372
                    $result = Database::query($sql);
4373
                } else {
4374
                    $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)
4375
                            VALUES ($course_id, '$tool', $item_id, '$time', $user_id, '$time', '$last_edit_type', $user_id, $toValueCondition, $visibility, $startVisible, $endVisible, $session_id)";
4376
                    $result = Database::query($sql);
4377
                    $id = Database::insert_id();
4378
                    if ($id) {
4379
                        $sql = "UPDATE $tableItemProperty SET id = iid WHERE iid = $id";
4380
                        Database::query($sql);
4381
                    }
4382
                }
4383
            } else {
4384
                $sql = "UPDATE $tableItemProperty
4385
                        SET
4386
                            lastedit_type='".str_replace('_', '', ucwords($tool))."Visible',
4387
                            lastedit_date='$time',
4388
                            lastedit_user_id = $user_id,
4389
                            visibility = $visibility $set_type
4390
                        WHERE $filter";
4391
                $result = Database::query($sql);
4392
            }
4393
            break;
4394
        case 'invisible': // Change item to invisible.
4395
            $visibility = '0';
4396
            if (!empty($session_id)) {
4397
                // Check whether session id already exist into item_properties for updating visibility or add it
4398
                $sql = "SELECT session_id FROM $tableItemProperty
4399
                        WHERE
4400
                            c_id = $course_id AND
4401
                            tool = '$tool' AND
4402
                            ref = $item_id AND
4403
                            session_id = $session_id";
4404
                $rs = Database::query($sql);
4405
                if (Database::num_rows($rs) > 0) {
4406
                    $sql = "UPDATE $tableItemProperty
4407
                            SET
4408
                                lastedit_type = '".str_replace('_', '', ucwords($tool))."Invisible',
4409
                                lastedit_date = '$time',
4410
                                lastedit_user_id = $user_id,
4411
                                visibility = $visibility,
4412
                                session_id = $session_id $set_type
4413
                            WHERE $filter";
4414
                    $result = Database::query($sql);
4415
                } else {
4416
                    $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)
4417
                            VALUES ($course_id, '$tool', $item_id, '$time', $user_id, '$time', '$last_edit_type', $user_id, $toValueCondition, $visibility, $startVisible, $endVisible, $session_id)";
4418
                    $result = Database::query($sql);
4419
                    $id = Database::insert_id();
4420
                    if ($id) {
4421
                        $sql = "UPDATE $tableItemProperty SET id = iid WHERE iid = $id";
4422
                        Database::query($sql);
4423
                    }
4424
                }
4425
            } else {
4426
                $sql = "UPDATE $tableItemProperty
4427
                        SET
4428
                            lastedit_type = '".str_replace('_', '', ucwords($tool))."Invisible',
4429
                            lastedit_date = '$time',
4430
                            lastedit_user_id = $user_id,
4431
                            visibility = $visibility $set_type
4432
                        WHERE $filter";
4433
                $result = Database::query($sql);
4434
            }
4435
            break;
4436
        default: // The item will be added or updated.
4437
            $set_type = ", lastedit_type = '$last_edit_type' ";
4438
            $visibility = '1';
4439
            //$filter .= $to_filter; already added
4440
            $sql = "UPDATE $tableItemProperty
4441
                    SET
4442
                      lastedit_date = '$time',
4443
                      lastedit_user_id = $user_id $set_type
4444
                    WHERE $filter";
4445
            $result = Database::query($sql);
4446
    }
4447
4448
    // Insert if no entries are found (can only happen in case of $last_edit_type switch is 'default').
4449
    if ($result == false || Database::affected_rows($result) == 0) {
4450
        $objCourse = $em->find('ChamiloCoreBundle:Course', intval($course_id));
4451
        $objTime = new DateTime('now', new DateTimeZone('UTC'));
4452
        $objUser = api_get_user_entity($user_id);
4453
        if (empty($objUser)) {
4454
            // Use anonymous
4455
            $user_id = api_get_anonymous_id();
4456
            $objUser = api_get_user_entity($user_id);
4457
        }
4458
4459
        $objGroup = null;
4460
        if (!empty($to_group_id)) {
4461
            $objGroup = $em->find('ChamiloCourseBundle:CGroupInfo', $to_group_id);
4462
        }
4463
4464
        $objToUser = api_get_user_entity($to_user_id);
4465
        $objSession = $em->find('ChamiloCoreBundle:Session', intval($session_id));
4466
4467
        $startVisibleDate = !empty($start_visible) ? new DateTime($start_visible, new DateTimeZone('UTC')) : null;
4468
        $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...
4469
4470
        $cItemProperty = new CItemProperty($objCourse);
4471
        $cItemProperty
4472
            ->setTool($tool)
4473
            ->setRef($item_id)
4474
            ->setInsertDate($objTime)
4475
            ->setInsertUser($objUser)
4476
            ->setLasteditDate($objTime)
4477
            ->setLasteditType($last_edit_type)
4478
            ->setGroup($objGroup)
4479
            ->setToUser($objToUser)
4480
            ->setVisibility($visibility)
4481
            ->setStartVisible($startVisibleDate)
4482
            ->setEndVisible($endVisibleDate)
4483
            ->setSession($objSession);
4484
4485
        $em->persist($cItemProperty);
4486
        $em->flush();
4487
4488
        $id = $cItemProperty->getIid();
4489
4490
        if ($id) {
4491
            $cItemProperty->setId($id);
4492
            $em->merge($cItemProperty);
4493
            $em->flush();
4494
4495
            return false;
4496
        }
4497
    }
4498
4499
    return true;
4500
}
4501
4502
/**
4503
 * Gets item property by tool.
4504
 *
4505
 * @param string    course code
4506
 * @param string    tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4507
 * @param int       id of the item itself, linked to key of every tool ('id', ...), "*" = all items of the tool
4508
 * @param int    $session_id
4509
 * @param string $tool
4510
 * @param string $course_code
4511
 *
4512
 * @return array All fields from c_item_property (all rows found) or empty array
4513
 */
4514
function api_get_item_property_by_tool($tool, $course_code, $session_id = null)
4515
{
4516
    $course_info = api_get_course_info($course_code);
4517
    $tool = Database::escape_string($tool);
4518
4519
    // Definition of tables.
4520
    $item_property_table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4521
    $session_id = (int) $session_id;
4522
    $session_condition = ' AND session_id = '.$session_id;
4523
    if (empty($session_id)) {
4524
        $session_condition = " AND (session_id = 0 OR session_id IS NULL) ";
4525
    }
4526
    $course_id = $course_info['real_id'];
4527
4528
    $sql = "SELECT * FROM $item_property_table
4529
            WHERE
4530
                c_id = $course_id AND
4531
                tool = '$tool'
4532
                $session_condition ";
4533
    $rs = Database::query($sql);
4534
    $list = [];
4535
    if (Database::num_rows($rs) > 0) {
4536
        while ($row = Database::fetch_array($rs, 'ASSOC')) {
4537
            $list[] = $row;
4538
        }
4539
    }
4540
4541
    return $list;
4542
}
4543
4544
/**
4545
 * Gets item property by tool and user.
4546
 *
4547
 * @param int $userId
4548
 * @param int $tool
4549
 * @param int $courseId
4550
 * @param int $session_id
4551
 *
4552
 * @return array
4553
 */
4554
function api_get_item_property_list_by_tool_by_user(
4555
    $userId,
4556
    $tool,
4557
    $courseId,
4558
    $session_id = 0
4559
) {
4560
    $userId = intval($userId);
4561
    $tool = Database::escape_string($tool);
4562
    $session_id = intval($session_id);
4563
    $courseId = intval($courseId);
4564
4565
    // Definition of tables.
4566
    $item_property_table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4567
    $session_condition = ' AND session_id = '.$session_id;
4568
    if (empty($session_id)) {
4569
        $session_condition = " AND (session_id = 0 OR session_id IS NULL) ";
4570
    }
4571
    $sql = "SELECT * FROM $item_property_table
4572
            WHERE
4573
                insert_user_id = $userId AND
4574
                c_id = $courseId AND
4575
                tool = '$tool'
4576
                $session_condition ";
4577
4578
    $rs = Database::query($sql);
4579
    $list = [];
4580
    if (Database::num_rows($rs) > 0) {
4581
        while ($row = Database::fetch_array($rs, 'ASSOC')) {
4582
            $list[] = $row;
4583
        }
4584
    }
4585
4586
    return $list;
4587
}
4588
4589
/**
4590
 * Gets item property id from tool of a course.
4591
 *
4592
 * @param string $course_code course code
4593
 * @param string $tool        tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4594
 * @param int    $ref         id of the item itself, linked to key of every tool ('id', ...), "*" = all items of the tool
4595
 * @param int    $sessionId   Session ID (optional)
4596
 *
4597
 * @return int
4598
 */
4599
function api_get_item_property_id($course_code, $tool, $ref, $sessionId = 0)
4600
{
4601
    $course_info = api_get_course_info($course_code);
4602
    $tool = Database::escape_string($tool);
4603
    $ref = (int) $ref;
4604
4605
    // Definition of tables.
4606
    $tableItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
4607
    $course_id = $course_info['real_id'];
4608
    $sessionId = (int) $sessionId;
4609
    $sessionCondition = " AND session_id = $sessionId ";
4610
    if (empty($sessionId)) {
4611
        $sessionCondition = ' AND (session_id = 0 OR session_id IS NULL) ';
4612
    }
4613
    $sql = "SELECT id FROM $tableItemProperty
4614
            WHERE
4615
                c_id = $course_id AND
4616
                tool = '$tool' AND
4617
                ref = $ref
4618
                $sessionCondition";
4619
    $rs = Database::query($sql);
4620
    $item_property_id = '';
4621
    if (Database::num_rows($rs) > 0) {
4622
        $row = Database::fetch_array($rs);
4623
        $item_property_id = $row['id'];
4624
    }
4625
4626
    return $item_property_id;
4627
}
4628
4629
/**
4630
 * Inserts a record in the track_e_item_property table (No update).
4631
 *
4632
 * @param string $tool
4633
 * @param int    $ref
4634
 * @param string $title
4635
 * @param string $content
4636
 * @param int    $progress
4637
 *
4638
 * @return bool|int
4639
 */
4640
function api_track_item_property_update($tool, $ref, $title, $content, $progress)
4641
{
4642
    $tbl_stats_item_property = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ITEM_PROPERTY);
4643
    $course_id = api_get_course_int_id(); //numeric
4644
    $course_code = api_get_course_id(); //alphanumeric
4645
    $item_property_id = api_get_item_property_id($course_code, $tool, $ref);
4646
    if (!empty($item_property_id)) {
4647
        $sql = "INSERT IGNORE INTO $tbl_stats_item_property SET
4648
                course_id           = '$course_id',
4649
                item_property_id    = '$item_property_id',
4650
                title               = '".Database::escape_string($title)."',
4651
                content             = '".Database::escape_string($content)."',
4652
                progress            = '".intval($progress)."',
4653
                lastedit_date       = '".api_get_utc_datetime()."',
4654
                lastedit_user_id    = '".api_get_user_id()."',
4655
                session_id          = '".api_get_session_id()."'";
4656
        $result = Database::query($sql);
4657
        $affected_rows = Database::affected_rows($result);
4658
4659
        return $affected_rows;
4660
    }
4661
4662
    return false;
4663
}
4664
4665
/**
4666
 * @param string $tool
4667
 * @param int    $ref
4668
 *
4669
 * @return array|resource
4670
 */
4671
function api_get_track_item_property_history($tool, $ref)
4672
{
4673
    $tbl_stats_item_property = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ITEM_PROPERTY);
4674
    $course_id = api_get_course_int_id(); //numeric
4675
    $course_code = api_get_course_id(); //alphanumeric
4676
    $item_property_id = api_get_item_property_id($course_code, $tool, $ref);
4677
    $sql = "SELECT * FROM $tbl_stats_item_property
4678
            WHERE item_property_id = $item_property_id AND course_id = $course_id
4679
            ORDER BY lastedit_date DESC";
4680
    $result = Database::query($sql);
4681
    if ($result === false or $result === null) {
4682
        $result = [];
4683
    } else {
4684
        $result = Database::store_result($result, 'ASSOC');
4685
    }
4686
4687
    return $result;
4688
}
4689
4690
/**
4691
 * Gets item property data from tool of a course id.
4692
 *
4693
 * @param int    $course_id
4694
 * @param string $tool       tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4695
 * @param int    $ref        id of the item itself, linked to key of every tool ('id', ...), "*" = all items of the tool
4696
 * @param int    $session_id
4697
 * @param int    $groupId
4698
 *
4699
 * @return array with all fields from c_item_property, empty array if not found or false if course could not be found
4700
 */
4701
function api_get_item_property_info($course_id, $tool, $ref, $session_id = 0, $groupId = 0)
4702
{
4703
    $courseInfo = api_get_course_info_by_id($course_id);
4704
4705
    if (empty($courseInfo)) {
4706
        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...
4707
    }
4708
4709
    $tool = Database::escape_string($tool);
4710
    $course_id = $courseInfo['real_id'];
4711
    $ref = (int) $ref;
4712
    $session_id = (int) $session_id;
4713
4714
    $sessionCondition = " session_id = $session_id";
4715
    if (empty($session_id)) {
4716
        $sessionCondition = ' (session_id = 0 OR session_id IS NULL) ';
4717
    }
4718
4719
    // Definition of tables.
4720
    $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4721
4722
    $sql = "SELECT * FROM $table
4723
            WHERE
4724
                c_id = $course_id AND
4725
                tool = '$tool' AND
4726
                ref = $ref AND
4727
                $sessionCondition ";
4728
4729
    if (!empty($groupId)) {
4730
        $groupId = (int) $groupId;
4731
        $sql .= " AND to_group_id = $groupId ";
4732
    }
4733
4734
    $rs = Database::query($sql);
4735
    $row = [];
4736
    if (Database::num_rows($rs) > 0) {
4737
        $row = Database::fetch_array($rs, 'ASSOC');
4738
    }
4739
4740
    return $row;
4741
}
4742
4743
/**
4744
 * Displays a combo box so the user can select his/her preferred language.
4745
 *
4746
 * @param string The desired name= value for the select
4747
 * @param bool Whether we use the JQuery Chozen library or not
4748
 * (in some cases, like the indexing language picker, it can alter the presentation)
4749
 *
4750
 * @deprecated
4751
 *
4752
 * @return string
4753
 */
4754
function api_get_languages_combo($name = 'language')
4755
{
4756
    $ret = '';
4757
    $platformLanguage = api_get_setting('platformLanguage');
4758
4759
    // Retrieve a complete list of all the languages.
4760
    $language_list = api_get_languages();
4761
4762
    if (count($language_list) < 2) {
4763
        return $ret;
4764
    }
4765
4766
    // The the current language of the user so that his/her language occurs as selected in the dropdown menu.
4767
    if (isset($_SESSION['user_language_choice'])) {
4768
        $default = $_SESSION['user_language_choice'];
4769
    } else {
4770
        $default = $platformLanguage;
4771
    }
4772
4773
    $ret .= '<select name="'.$name.'" id="language_chosen" class="selectpicker show-tick form-control">';
4774
    foreach ($language_list as $key => $value) {
4775
        if ($key == $default) {
4776
            $selected = ' selected="selected"';
4777
        } else {
4778
            $selected = '';
4779
        }
4780
        $ret .= sprintf('<option value=%s" %s>%s</option>', $key, $selected, $value);
4781
    }
4782
    $ret .= '</select>';
4783
4784
    return $ret;
4785
}
4786
4787
/**
4788
 * @param string $languageIsoCode
4789
 *
4790
 * @return string
4791
 */
4792
function languageToCountryIsoCode($languageIsoCode)
4793
{
4794
    // @todo save in DB
4795
    switch ($languageIsoCode) {
4796
        case 'ko':
4797
            $country = 'kr';
4798
            break;
4799
        case 'ja':
4800
            $country = 'jp';
4801
            break;
4802
        case 'ca':
4803
            $country = 'es';
4804
            break;
4805
        case 'gl':
4806
            $country = 'es';
4807
            break;
4808
        case 'ka':
4809
            $country = 'ge';
4810
            break;
4811
        case 'sl':
4812
            $country = 'si';
4813
            break;
4814
        case 'eu':
4815
            $country = 'es';
4816
            break;
4817
        case 'cs':
4818
            $country = 'cz';
4819
            break;
4820
        case 'el':
4821
            $country = 'ae';
4822
            break;
4823
        case 'ar':
4824
            $country = 'ae';
4825
            break;
4826
        case 'en_US':
4827
        case 'en':
4828
            $country = 'gb';
4829
            break;
4830
        case 'he':
4831
            $country = 'il';
4832
            break;
4833
        case 'uk':
4834
            $country = 'ua'; // Ukraine
4835
            break;
4836
        case 'da':
4837
            $country = 'dk';
4838
            break;
4839
        case 'pt-BR':
4840
            $country = 'br';
4841
            break;
4842
        case 'qu':
4843
            $country = 'pe';
4844
            break;
4845
        case 'sv':
4846
            $country = 'se';
4847
            break;
4848
        case 'zh-TW':
4849
        case 'zh':
4850
            $country = 'cn';
4851
            break;
4852
        default:
4853
            $country = $languageIsoCode;
4854
            break;
4855
    }
4856
    $country = strtolower($country);
4857
4858
    return $country;
4859
}
4860
4861
/**
4862
 * Returns a list of all the languages that are made available by the admin.
4863
 *
4864
 * @return array An array with all languages. Structure of the array is
4865
 *               array['name'] = An array with the name of every language
4866
 *               array['folder'] = An array with the corresponding names of the language-folders in the filesystem
4867
 */
4868
function api_get_languages()
4869
{
4870
    $tbl_language = Database::get_main_table(TABLE_MAIN_LANGUAGE);
4871
    $sql = "SELECT * FROM $tbl_language WHERE available='1' 
4872
            ORDER BY original_name ASC";
4873
    $result = Database::query($sql);
4874
    $languages = [];
4875
    while ($row = Database::fetch_array($result, 'ASSOC')) {
4876
        $languages[$row['isocode']] = $row['original_name'];
4877
    }
4878
4879
    return $languages;
4880
}
4881
4882
/**
4883
 * Returns a list of all the languages that are made available by the admin.
4884
 *
4885
 * @return array
4886
 */
4887
function api_get_languages_to_array()
4888
{
4889
    $tbl_language = Database::get_main_table(TABLE_MAIN_LANGUAGE);
4890
    $sql = "SELECT * FROM $tbl_language WHERE available='1' ORDER BY original_name ASC";
4891
    $result = Database::query($sql);
4892
    $languages = [];
4893
    while ($row = Database::fetch_array($result)) {
4894
        $languages[$row['dokeos_folder']] = $row['original_name'];
4895
    }
4896
4897
    return $languages;
4898
}
4899
4900
/**
4901
 * Returns the id (the database id) of a language.
4902
 *
4903
 * @param   string  language name (the corresponding name of the language-folder in the filesystem)
4904
 *
4905
 * @return int id of the language
4906
 */
4907
function api_get_language_id($language)
4908
{
4909
    $tbl_language = Database::get_main_table(TABLE_MAIN_LANGUAGE);
4910
    if (empty($language)) {
4911
        return null;
4912
    }
4913
    $language = Database::escape_string($language);
4914
    $sql = "SELECT id FROM $tbl_language
4915
            WHERE dokeos_folder = '$language' LIMIT 1";
4916
    $result = Database::query($sql);
4917
    $row = Database::fetch_array($result);
4918
4919
    return $row['id'];
4920
}
4921
4922
/**
4923
 * Get the language information by its id.
4924
 *
4925
 * @param int $languageId
4926
 *
4927
 * @throws Exception
4928
 *
4929
 * @return array
4930
 */
4931
function api_get_language_info($languageId)
4932
{
4933
    $language = Database::getManager()
4934
        ->find('ChamiloCoreBundle:Language', intval($languageId));
4935
4936
    if (!$language) {
4937
        return [];
4938
    }
4939
4940
    return [
4941
        'id' => $language->getId(),
4942
        'original_name' => $language->getOriginalName(),
4943
        'english_name' => $language->getEnglishName(),
4944
        'isocode' => $language->getIsocode(),
4945
        'dokeos_folder' => $language->getDokeosFolder(),
4946
        'available' => $language->getAvailable(),
4947
        'parent_id' => $language->getParent() ? $language->getParent()->getId() : null,
4948
    ];
4949
}
4950
4951
/**
4952
 * @param string $code
4953
 *
4954
 * @return \Chamilo\CoreBundle\Entity\Language
4955
 */
4956
function api_get_language_from_iso($code)
4957
{
4958
    $em = Database::getManager();
4959
    $language = $em->getRepository('ChamiloCoreBundle:Language')->findOneBy(['isocode' => $code]);
4960
4961
    return $language;
4962
}
4963
4964
/**
4965
 * Returns the name of the visual (CSS) theme to be applied on the current page.
4966
 * The returned name depends on the platform, course or user -wide settings.
4967
 *
4968
 * @return string The visual theme's name, it is the name of a folder inside web/css/themes
4969
 */
4970
function api_get_visual_theme()
4971
{
4972
    static $visual_theme;
4973
    if (!isset($visual_theme)) {
4974
        // Get style directly from DB
4975
        $styleFromDatabase = api_get_settings_params_simple(
4976
            [
4977
                'variable = ? AND access_url = ?' => [
4978
                    'stylesheets',
4979
                    api_get_current_access_url_id(),
4980
                ],
4981
            ]
4982
        );
4983
        if ($styleFromDatabase) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $styleFromDatabase of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
4984
            $platform_theme = $styleFromDatabase['selected_value'];
4985
        } else {
4986
            $platform_theme = api_get_setting('stylesheets');
4987
        }
4988
4989
        // Platform's theme.
4990
        $visual_theme = $platform_theme;
4991
        if (api_get_setting('user_selected_theme') == 'true') {
4992
            $user_info = api_get_user_info();
4993
            if (isset($user_info['theme'])) {
4994
                $user_theme = $user_info['theme'];
4995
4996
                if (!empty($user_theme)) {
4997
                    $visual_theme = $user_theme;
4998
                    // User's theme.
4999
                }
5000
            }
5001
        }
5002
5003
        $course_id = api_get_course_id();
5004
        if (!empty($course_id)) {
5005
            if (api_get_setting('allow_course_theme') == 'true') {
5006
                $course_theme = api_get_course_setting('course_theme', $course_id);
5007
5008
                if (!empty($course_theme) && $course_theme != -1) {
5009
                    if (!empty($course_theme)) {
5010
                        // Course's theme.
5011
                        $visual_theme = $course_theme;
5012
                    }
5013
                }
5014
5015
                $allow_lp_theme = api_get_course_setting('allow_learning_path_theme');
5016
                if ($allow_lp_theme == 1) {
5017
                    global $lp_theme_css, $lp_theme_config;
5018
                    // These variables come from the file lp_controller.php.
5019
                    if (!$lp_theme_config) {
5020
                        if (!empty($lp_theme_css)) {
5021
                            // LP's theme.
5022
                            $visual_theme = $lp_theme_css;
5023
                        }
5024
                    }
5025
                }
5026
            }
5027
        }
5028
5029
        if (empty($visual_theme)) {
5030
            $visual_theme = 'chamilo';
5031
        }
5032
5033
        global $lp_theme_log;
5034
        if ($lp_theme_log) {
5035
            $visual_theme = $platform_theme;
5036
        }
5037
    }
5038
5039
    return $visual_theme;
5040
}
5041
5042
/**
5043
 * Returns a list of CSS themes currently available in the CSS folder
5044
 * The folder must have a default.css file.
5045
 *
5046
 * @param bool $getOnlyThemeFromVirtualInstance Used by the vchamilo plugin
5047
 *
5048
 * @return array list of themes directories from the css folder
5049
 *               Note: Directory names (names of themes) in the file system should contain ASCII-characters only
5050
 */
5051
function api_get_themes($getOnlyThemeFromVirtualInstance = false)
5052
{
5053
    // This configuration value is set by the vchamilo plugin
5054
    $virtualTheme = api_get_configuration_value('virtual_css_theme_folder');
5055
5056
    $readCssFolder = function ($dir) use ($virtualTheme) {
5057
        $finder = new Finder();
5058
        $themes = $finder->directories()->in($dir)->depth(0)->sortByName();
5059
        $list = [];
5060
        /** @var Symfony\Component\Finder\SplFileInfo $theme */
5061
        foreach ($themes as $theme) {
5062
            $folder = $theme->getFilename();
5063
            // A theme folder is consider if there's a default.css file
5064
            if (!file_exists($theme->getPathname().'/default.css')) {
5065
                continue;
5066
            }
5067
            $name = ucwords(str_replace('_', ' ', $folder));
5068
            if ($folder == $virtualTheme) {
5069
                continue;
5070
            }
5071
            $list[$folder] = $name;
5072
        }
5073
5074
        return $list;
5075
    };
5076
5077
    $dir = api_get_path(SYS_CSS_PATH).'themes/';
5078
    $list = $readCssFolder($dir);
5079
5080
    if (!empty($virtualTheme)) {
5081
        $newList = $readCssFolder($dir.'/'.$virtualTheme);
5082
        if ($getOnlyThemeFromVirtualInstance) {
5083
            return $newList;
5084
        }
5085
        $list = $list + $newList;
5086
        asort($list);
5087
    }
5088
5089
    return $list;
5090
}
5091
5092
/**
5093
 * Find the largest sort value in a given user_course_category
5094
 * This function is used when we are moving a course to a different category
5095
 * and also when a user subscribes to courses (the new course is added at the end of the main category.
5096
 *
5097
 * @author Patrick Cool <[email protected]>, Ghent University
5098
 *
5099
 * @param int $user_course_category the id of the user_course_category
5100
 * @param int $user_id
5101
 *
5102
 * @return int the value of the highest sort of the user_course_category
5103
 */
5104
function api_max_sort_value($user_course_category, $user_id)
5105
{
5106
    $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
5107
    $sql = "SELECT max(sort) as max_sort FROM $tbl_course_user
5108
            WHERE
5109
                user_id='".intval($user_id)."' AND
5110
                relation_type<>".COURSE_RELATION_TYPE_RRHH." AND
5111
                user_course_cat='".intval($user_course_category)."'";
5112
    $result_max = Database::query($sql);
5113
    if (Database::num_rows($result_max) == 1) {
5114
        $row_max = Database::fetch_array($result_max);
5115
5116
        return $row_max['max_sort'];
5117
    }
5118
5119
    return 0;
5120
}
5121
5122
/**
5123
 * Transforms a number of seconds in hh:mm:ss format.
5124
 *
5125
 * @author Julian Prud'homme
5126
 *
5127
 * @param int the number of seconds
5128
 *
5129
 * @return string the formated time
5130
 */
5131
function api_time_to_hms($seconds)
5132
{
5133
    // $seconds = -1 means that we have wrong data in the db.
5134
    if ($seconds == -1) {
5135
        return
5136
            get_lang('Unknown').
5137
            Display::return_icon(
5138
                'info2.gif',
5139
                get_lang('WrongDatasForTimeSpentOnThePlatform'),
5140
                ['align' => 'absmiddle', 'hspace' => '3px']
5141
            );
5142
    }
5143
5144
    // How many hours ?
5145
    $hours = floor($seconds / 3600);
5146
5147
    // How many minutes ?
5148
    $min = floor(($seconds - ($hours * 3600)) / 60);
5149
5150
    // How many seconds
5151
    $sec = floor($seconds - ($hours * 3600) - ($min * 60));
5152
5153
    if ($sec < 10) {
5154
        $sec = "0$sec";
5155
    }
5156
5157
    if ($min < 10) {
5158
        $min = "0$min";
5159
    }
5160
5161
    return "$hours:$min:$sec";
5162
}
5163
5164
/* FILE SYSTEM RELATED FUNCTIONS */
5165
5166
/**
5167
 * Returns the permissions to be assigned to every newly created directory by the web-server.
5168
 * The return value is based on the platform administrator's setting
5169
 * "Administration > Configuration settings > Security > Permissions for new directories".
5170
 *
5171
 * @return int returns the permissions in the format "Owner-Group-Others, Read-Write-Execute", as an integer value
5172
 */
5173
function api_get_permissions_for_new_directories()
5174
{
5175
    static $permissions;
5176
    if (!isset($permissions)) {
5177
        $permissions = trim(api_get_setting('permissions_for_new_directories'));
5178
        // The default value 0777 is according to that in the platform administration panel after fresh system installation.
5179
        $permissions = octdec(!empty($permissions) ? $permissions : '0777');
5180
    }
5181
5182
    return $permissions;
5183
}
5184
5185
/**
5186
 * Returns the permissions to be assigned to every newly created directory by the web-server.
5187
 * The return value is based on the platform administrator's setting
5188
 * "Administration > Configuration settings > Security > Permissions for new files".
5189
 *
5190
 * @return int returns the permissions in the format
5191
 *             "Owner-Group-Others, Read-Write-Execute", as an integer value
5192
 */
5193
function api_get_permissions_for_new_files()
5194
{
5195
    static $permissions;
5196
    if (!isset($permissions)) {
5197
        $permissions = trim(api_get_setting('permissions_for_new_files'));
5198
        // The default value 0666 is according to that in the platform
5199
        // administration panel after fresh system installation.
5200
        $permissions = octdec(!empty($permissions) ? $permissions : '0666');
5201
    }
5202
5203
    return $permissions;
5204
}
5205
5206
/**
5207
 * Deletes a file, or a folder and its contents.
5208
 *
5209
 * @author      Aidan Lister <[email protected]>
5210
 *
5211
 * @version     1.0.3
5212
 *
5213
 * @param string $dirname Directory to delete
5214
 * @param       bool     Deletes only the content or not
5215
 * @param bool $strict if one folder/file fails stop the loop
5216
 *
5217
 * @return bool Returns TRUE on success, FALSE on failure
5218
 *
5219
 * @see http://aidanlister.com/2004/04/recursively-deleting-a-folder-in-php/
5220
 *
5221
 * @author      Yannick Warnier, adaptation for the Chamilo LMS, April, 2008
5222
 * @author      Ivan Tcholakov, a sanity check about Directory class creation has been added, September, 2009
5223
 */
5224
function rmdirr($dirname, $delete_only_content_in_folder = false, $strict = false)
5225
{
5226
    $res = true;
5227
    // A sanity check.
5228
    if (!file_exists($dirname)) {
5229
        return false;
5230
    }
5231
    $php_errormsg = '';
5232
    // Simple delete for a file.
5233
    if (is_file($dirname) || is_link($dirname)) {
5234
        $res = unlink($dirname);
5235
        if ($res === false) {
5236
            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);
5237
        }
5238
5239
        return $res;
5240
    }
5241
5242
    // Loop through the folder.
5243
    $dir = dir($dirname);
5244
    // A sanity check.
5245
    $is_object_dir = is_object($dir);
5246
    if ($is_object_dir) {
5247
        while (false !== $entry = $dir->read()) {
5248
            // Skip pointers.
5249
            if ($entry == '.' || $entry == '..') {
5250
                continue;
5251
            }
5252
5253
            // Recurse.
5254
            if ($strict) {
5255
                $result = rmdirr("$dirname/$entry");
5256
                if ($result == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

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

Loading history...
5257
                    $res = false;
5258
                    break;
5259
                }
5260
            } else {
5261
                rmdirr("$dirname/$entry");
5262
            }
5263
        }
5264
    }
5265
5266
    // Clean up.
5267
    if ($is_object_dir) {
5268
        $dir->close();
5269
    }
5270
5271
    if ($delete_only_content_in_folder == false) {
5272
        $res = rmdir($dirname);
5273
        if ($res === false) {
5274
            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);
5275
        }
5276
    }
5277
5278
    return $res;
5279
}
5280
5281
// TODO: This function is to be simplified. File access modes to be implemented.
5282
/**
5283
 * function adapted from a php.net comment
5284
 * copy recursively a folder.
5285
 *
5286
 * @param the source folder
5287
 * @param the dest folder
5288
 * @param an array of excluded file_name (without extension)
5289
 * @param copied_files the returned array of copied files
5290
 * @param string $source
5291
 * @param string $dest
5292
 */
5293
function copyr($source, $dest, $exclude = [], $copied_files = [])
5294
{
5295
    if (empty($dest)) {
5296
        return false;
5297
    }
5298
    // Simple copy for a file
5299
    if (is_file($source)) {
5300
        $path_info = pathinfo($source);
5301
        if (!in_array($path_info['filename'], $exclude)) {
5302
            copy($source, $dest);
5303
        }
5304
5305
        return true;
5306
    } elseif (!is_dir($source)) {
5307
        //then source is not a dir nor a file, return
5308
        return false;
5309
    }
5310
5311
    // Make destination directory.
5312
    if (!is_dir($dest)) {
5313
        mkdir($dest, api_get_permissions_for_new_directories());
5314
    }
5315
5316
    // Loop through the folder.
5317
    $dir = dir($source);
5318
    while (false !== $entry = $dir->read()) {
5319
        // Skip pointers
5320
        if ($entry == '.' || $entry == '..') {
5321
            continue;
5322
        }
5323
5324
        // Deep copy directories.
5325
        if ($dest !== "$source/$entry") {
5326
            $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

5326
            $files = copyr("$source/$entry", "$dest/$entry", $exclude, /** @scrutinizer ignore-type */ $copied_files);
Loading history...
5327
        }
5328
    }
5329
    // Clean up.
5330
    $dir->close();
5331
5332
    return true;
5333
}
5334
5335
/**
5336
 * @todo: Using DIRECTORY_SEPARATOR is not recommended, this is an obsolete approach.
5337
 * Documentation header to be added here.
5338
 *
5339
 * @param string $pathname
5340
 * @param string $base_path_document
5341
 * @param int    $session_id
5342
 *
5343
 * @return mixed True if directory already exists, false if a file already exists at
5344
 *               the destination and null if everything goes according to plan
5345
 */
5346
function copy_folder_course_session(
5347
    $pathname,
5348
    $base_path_document,
5349
    $session_id,
5350
    $course_info,
5351
    $document,
5352
    $source_course_id
5353
) {
5354
    $table = Database::get_course_table(TABLE_DOCUMENT);
5355
    $session_id = intval($session_id);
5356
    $source_course_id = intval($source_course_id);
5357
5358
    // Check whether directory already exists.
5359
    if (is_dir($pathname) || empty($pathname)) {
5360
        return true;
5361
    }
5362
5363
    // Ensure that a file with the same name does not already exist.
5364
    if (is_file($pathname)) {
5365
        trigger_error('copy_folder_course_session(): File exists', E_USER_WARNING);
5366
5367
        return false;
5368
    }
5369
5370
    $course_id = $course_info['real_id'];
5371
    $folders = explode(DIRECTORY_SEPARATOR, str_replace($base_path_document.DIRECTORY_SEPARATOR, '', $pathname));
5372
    $new_pathname = $base_path_document;
5373
    $path = '';
5374
5375
    foreach ($folders as $folder) {
5376
        $new_pathname .= DIRECTORY_SEPARATOR.$folder;
5377
        $path .= DIRECTORY_SEPARATOR.$folder;
5378
5379
        if (!file_exists($new_pathname)) {
5380
            $path = Database::escape_string($path);
5381
5382
            $sql = "SELECT * FROM $table
5383
                    WHERE
5384
                        c_id = $source_course_id AND
5385
                        path = '$path' AND
5386
                        filetype = 'folder' AND
5387
                        session_id = '$session_id'";
5388
            $rs1 = Database::query($sql);
5389
            $num_rows = Database::num_rows($rs1);
5390
5391
            if ($num_rows == 0) {
5392
                mkdir($new_pathname, api_get_permissions_for_new_directories());
5393
5394
                // Insert new folder with destination session_id.
5395
                $params = [
5396
                    'c_id' => $course_id,
5397
                    'path' => $path,
5398
                    'comment' => $document->comment,
5399
                    'title' => basename($new_pathname),
5400
                    'filetype' => 'folder',
5401
                    'size' => '0',
5402
                    'session_id' => $session_id,
5403
                ];
5404
                $document_id = Database::insert($table, $params);
5405
                if ($document_id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $document_id of type integer|false 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...
5406
                    $sql = "UPDATE $table SET id = iid WHERE iid = $document_id";
5407
                    Database::query($sql);
5408
5409
                    api_item_property_update(
5410
                        $course_info,
5411
                        TOOL_DOCUMENT,
5412
                        $document_id,
5413
                        'FolderCreated',
5414
                        api_get_user_id(),
5415
                        0,
5416
                        0,
5417
                        null,
5418
                        null,
5419
                        $session_id
5420
                    );
5421
                }
5422
            }
5423
        }
5424
    } // en foreach
5425
}
5426
5427
// TODO: chmodr() is a better name. Some corrections are needed. Documentation header to be added here.
5428
/**
5429
 * @param string $path
5430
 */
5431
function api_chmod_R($path, $filemode)
5432
{
5433
    if (!is_dir($path)) {
5434
        return chmod($path, $filemode);
5435
    }
5436
5437
    $handler = opendir($path);
5438
    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

5438
    while ($file = readdir(/** @scrutinizer ignore-type */ $handler)) {
Loading history...
5439
        if ($file != '.' && $file != '..') {
5440
            $fullpath = "$path/$file";
5441
            if (!is_dir($fullpath)) {
5442
                if (!chmod($fullpath, $filemode)) {
5443
                    return false;
5444
                }
5445
            } else {
5446
                if (!api_chmod_R($fullpath, $filemode)) {
5447
                    return false;
5448
                }
5449
            }
5450
        }
5451
    }
5452
5453
    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

5453
    closedir(/** @scrutinizer ignore-type */ $handler);
Loading history...
5454
5455
    return chmod($path, $filemode);
5456
}
5457
5458
// TODO: Where the following function has been copy/pased from? There is no information about author and license. Style, coding conventions...
5459
/**
5460
 * Parse info file format. (e.g: file.info).
5461
 *
5462
 * Files should use an ini-like format to specify values.
5463
 * White-space generally doesn't matter, except inside values.
5464
 * e.g.
5465
 *
5466
 * @verbatim
5467
 *   key = value
5468
 *   key = "value"
5469
 *   key = 'value'
5470
 *   key = "multi-line
5471
 *
5472
 *   value"
5473
 *   key = 'multi-line
5474
 *
5475
 *   value'
5476
 *   key
5477
 *   =
5478
 *   'value'
5479
 * @endverbatim
5480
 *
5481
 * Arrays are created using a GET-like syntax:
5482
 *
5483
 * @verbatim
5484
 *   key[] = "numeric array"
5485
 *   key[index] = "associative array"
5486
 *   key[index][] = "nested numeric array"
5487
 *   key[index][index] = "nested associative array"
5488
 * @endverbatim
5489
 *
5490
 * PHP constants are substituted in, but only when used as the entire value:
5491
 *
5492
 * Comments should start with a semi-colon at the beginning of a line.
5493
 *
5494
 * This function is NOT for placing arbitrary module-specific settings. Use
5495
 * variable_get() and variable_set() for that.
5496
 *
5497
 * Information stored in the module.info file:
5498
 * - name: The real name of the module for display purposes.
5499
 * - description: A brief description of the module.
5500
 * - dependencies: An array of shortnames of other modules this module depends on.
5501
 * - package: The name of the package of modules this module belongs to.
5502
 *
5503
 * Example of .info file:
5504
 * <code>
5505
 * @verbatim
5506
 *   name = Forum
5507
 *   description = Enables threaded discussions about general topics.
5508
 *   dependencies[] = taxonomy
5509
 *   dependencies[] = comment
5510
 *   package = Core - optional
5511
 *   version = VERSION
5512
 * @endverbatim
5513
 * </code>
5514
 *
5515
 * @param string $filename
5516
 *                         The file we are parsing. Accepts file with relative or absolute path.
5517
 *
5518
 * @return
5519
 *   The info array
5520
 */
5521
function api_parse_info_file($filename)
5522
{
5523
    $info = [];
5524
5525
    if (!file_exists($filename)) {
5526
        return $info;
5527
    }
5528
5529
    $data = file_get_contents($filename);
5530
    if (preg_match_all('
5531
        @^\s*                           # Start at the beginning of a line, ignoring leading whitespace
5532
        ((?:
5533
          [^=;\[\]]|                    # Key names cannot contain equal signs, semi-colons or square brackets,
5534
          \[[^\[\]]*\]                  # unless they are balanced and not nested
5535
        )+?)
5536
        \s*=\s*                         # Key/value pairs are separated by equal signs (ignoring white-space)
5537
        (?:
5538
          ("(?:[^"]|(?<=\\\\)")*")|     # Double-quoted string, which may contain slash-escaped quotes/slashes
5539
          (\'(?:[^\']|(?<=\\\\)\')*\')| # Single-quoted string, which may contain slash-escaped quotes/slashes
5540
          ([^\r\n]*?)                   # Non-quoted string
5541
        )\s*$                           # Stop at the next end of a line, ignoring trailing whitespace
5542
        @msx', $data, $matches, PREG_SET_ORDER)) {
5543
        $key = $value1 = $value2 = $value3 = '';
5544
        foreach ($matches as $match) {
5545
            // Fetch the key and value string.
5546
            $i = 0;
5547
            foreach (['key', 'value1', 'value2', 'value3'] as $var) {
5548
                $$var = isset($match[++$i]) ? $match[$i] : '';
5549
            }
5550
            $value = stripslashes(substr($value1, 1, -1)).stripslashes(substr($value2, 1, -1)).$value3;
5551
5552
            // Parse array syntax.
5553
            $keys = preg_split('/\]?\[/', rtrim($key, ']'));
5554
            $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

5554
            $last = array_pop(/** @scrutinizer ignore-type */ $keys);
Loading history...
5555
            $parent = &$info;
5556
5557
            // Create nested arrays.
5558
            foreach ($keys as $key) {
5559
                if ($key == '') {
5560
                    $key = count($parent);
5561
                }
5562
                if (!isset($parent[$key]) || !is_array($parent[$key])) {
5563
                    $parent[$key] = [];
5564
                }
5565
                $parent = &$parent[$key];
5566
            }
5567
5568
            // Handle PHP constants.
5569
            if (defined($value)) {
5570
                $value = constant($value);
5571
            }
5572
5573
            // Insert actual value.
5574
            if ($last == '') {
5575
                $last = count($parent);
5576
            }
5577
            $parent[$last] = $value;
5578
        }
5579
    }
5580
5581
    return $info;
5582
}
5583
5584
/**
5585
 * Gets Chamilo version from the configuration files.
5586
 *
5587
 * @return string A string of type "1.8.4", or an empty string if the version could not be found
5588
 */
5589
function api_get_version()
5590
{
5591
    return (string) api_get_configuration_value('system_version');
5592
}
5593
5594
/**
5595
 * Gets the software name (the name/brand of the Chamilo-based customized system).
5596
 *
5597
 * @return string
5598
 */
5599
function api_get_software_name()
5600
{
5601
    $name = api_get_configuration_value('software_name');
5602
    if (!empty($name)) {
5603
        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...
5604
    } else {
5605
        return 'Chamilo';
5606
    }
5607
}
5608
5609
/**
5610
 * Checks whether status given in parameter exists in the platform.
5611
 *
5612
 * @param mixed the status (can be either int either string)
5613
 *
5614
 * @return bool if the status exists, else returns false
5615
 */
5616
function api_status_exists($status_asked)
5617
{
5618
    global $_status_list;
5619
5620
    return in_array($status_asked, $_status_list) ? true : isset($_status_list[$status_asked]);
5621
}
5622
5623
/**
5624
 * Checks whether status given in parameter exists in the platform. The function
5625
 * returns the status ID or false if it does not exist, but given the fact there
5626
 * is no "0" status, the return value can be checked against
5627
 * if(api_status_key()) to know if it exists.
5628
 *
5629
 * @param   mixed   The status (can be either int or string)
5630
 *
5631
 * @return mixed Status ID if exists, false otherwise
5632
 */
5633
function api_status_key($status)
5634
{
5635
    global $_status_list;
5636
5637
    return isset($_status_list[$status]) ? $status : array_search($status, $_status_list);
5638
}
5639
5640
/**
5641
 * Gets the status langvars list.
5642
 *
5643
 * @return string[] the list of status with their translations
5644
 */
5645
function api_get_status_langvars()
5646
{
5647
    return [
5648
        COURSEMANAGER => get_lang('Teacher', ''),
5649
        SESSIONADMIN => get_lang('SessionsAdmin', ''),
5650
        DRH => get_lang('Drh', ''),
5651
        STUDENT => get_lang('Student', ''),
5652
        ANONYMOUS => get_lang('Anonymous', ''),
5653
        STUDENT_BOSS => get_lang('RoleStudentBoss', ''),
5654
        INVITEE => get_lang('Invited'),
5655
    ];
5656
}
5657
5658
/**
5659
 * The function that retrieves all the possible settings for a certain config setting.
5660
 *
5661
 * @author Patrick Cool <[email protected]>, Ghent University
5662
 */
5663
function api_get_settings_options($var)
5664
{
5665
    $table_settings_options = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
5666
    $var = Database::escape_string($var);
5667
    $sql = "SELECT * FROM $table_settings_options
5668
            WHERE variable = '$var'
5669
            ORDER BY id";
5670
    $result = Database::query($sql);
5671
    $settings_options_array = [];
5672
    while ($row = Database::fetch_array($result, 'ASSOC')) {
5673
        $settings_options_array[] = $row;
5674
    }
5675
5676
    return $settings_options_array;
5677
}
5678
5679
/**
5680
 * @param array $params
5681
 */
5682
function api_set_setting_option($params)
5683
{
5684
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
5685
    if (empty($params['id'])) {
5686
        Database::insert($table, $params);
5687
    } else {
5688
        Database::update($table, $params, ['id = ? ' => $params['id']]);
5689
    }
5690
}
5691
5692
/**
5693
 * @param array $params
5694
 */
5695
function api_set_setting_simple($params)
5696
{
5697
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5698
    $url_id = api_get_current_access_url_id();
5699
5700
    if (empty($params['id'])) {
5701
        $params['access_url'] = $url_id;
5702
        Database::insert($table, $params);
5703
    } else {
5704
        Database::update($table, $params, ['id = ? ' => [$params['id']]]);
5705
    }
5706
}
5707
5708
/**
5709
 * @param int $id
5710
 */
5711
function api_delete_setting_option($id)
5712
{
5713
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
5714
    if (!empty($id)) {
5715
        Database::delete($table, ['id = ? ' => $id]);
5716
    }
5717
}
5718
5719
/**
5720
 * Sets a platform configuration setting to a given value.
5721
 *
5722
 * @param string    The variable we want to update
5723
 * @param string    The value we want to record
5724
 * @param string    The sub-variable if any (in most cases, this will remain null)
5725
 * @param string    The category if any (in most cases, this will remain null)
5726
 * @param int       The access_url for which this parameter is valid
5727
 * @param string $cat
5728
 *
5729
 * @return bool|null
5730
 */
5731
function api_set_setting($var, $value, $subvar = null, $cat = null, $access_url = 1)
5732
{
5733
    if (empty($var)) {
5734
        return false;
5735
    }
5736
    $t_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5737
    $var = Database::escape_string($var);
5738
    $value = Database::escape_string($value);
5739
    $access_url = (int) $access_url;
5740
    if (empty($access_url)) {
5741
        $access_url = 1;
5742
    }
5743
    $select = "SELECT id FROM $t_settings WHERE variable = '$var' ";
5744
    if (!empty($subvar)) {
5745
        $subvar = Database::escape_string($subvar);
5746
        $select .= " AND subkey = '$subvar'";
5747
    }
5748
    if (!empty($cat)) {
5749
        $cat = Database::escape_string($cat);
5750
        $select .= " AND category = '$cat'";
5751
    }
5752
    if ($access_url > 1) {
5753
        $select .= " AND access_url = $access_url";
5754
    } else {
5755
        $select .= " AND access_url = 1 ";
5756
    }
5757
5758
    $res = Database::query($select);
5759
    if (Database::num_rows($res) > 0) {
5760
        // Found item for this access_url.
5761
        $row = Database::fetch_array($res);
5762
        $sql = "UPDATE $t_settings SET selected_value = '$value'
5763
                WHERE id = ".$row['id'];
5764
        Database::query($sql);
5765
    } else {
5766
        // Item not found for this access_url, we have to check if it exist with access_url = 1
5767
        $select = "SELECT * FROM $t_settings
5768
                   WHERE variable = '$var' AND access_url = 1 ";
5769
        // Just in case
5770
        if ($access_url == 1) {
5771
            if (!empty($subvar)) {
5772
                $select .= " AND subkey = '$subvar'";
5773
            }
5774
            if (!empty($cat)) {
5775
                $select .= " AND category = '$cat'";
5776
            }
5777
            $res = Database::query($select);
5778
            if (Database::num_rows($res) > 0) {
5779
                // We have a setting for access_url 1, but none for the current one, so create one.
5780
                $row = Database::fetch_array($res);
5781
                $insert = "INSERT INTO $t_settings (variable, subkey, type,category, selected_value, title, comment, scope, subkeytext, access_url)
5782
                        VALUES
5783
                        ('".$row['variable']."',".(!empty($row['subkey']) ? "'".$row['subkey']."'" : "NULL").",".
5784
                    "'".$row['type']."','".$row['category']."',".
5785
                    "'$value','".$row['title']."',".
5786
                    "".(!empty($row['comment']) ? "'".$row['comment']."'" : "NULL").",".(!empty($row['scope']) ? "'".$row['scope']."'" : "NULL").",".
5787
                    "".(!empty($row['subkeytext']) ? "'".$row['subkeytext']."'" : "NULL").",$access_url)";
5788
                Database::query($insert);
5789
            } else {
5790
                // Such a setting does not exist.
5791
                //error_log(__FILE__.':'.__LINE__.': Attempting to update setting '.$var.' ('.$subvar.') which does not exist at all', 0);
5792
            }
5793
        } else {
5794
            // Other access url.
5795
            if (!empty($subvar)) {
5796
                $select .= " AND subkey = '$subvar'";
5797
            }
5798
            if (!empty($cat)) {
5799
                $select .= " AND category = '$cat'";
5800
            }
5801
            $res = Database::query($select);
5802
5803
            if (Database::num_rows($res) > 0) {
5804
                // We have a setting for access_url 1, but none for the current one, so create one.
5805
                $row = Database::fetch_array($res);
5806
                if ($row['access_url_changeable'] == 1) {
5807
                    $insert = "INSERT INTO $t_settings (variable,subkey, type,category, selected_value,title, comment,scope, subkeytext,access_url, access_url_changeable) VALUES
5808
                            ('".$row['variable']."',".
5809
                        (!empty($row['subkey']) ? "'".$row['subkey']."'" : "NULL").",".
5810
                        "'".$row['type']."','".$row['category']."',".
5811
                        "'$value','".$row['title']."',".
5812
                        "".(!empty($row['comment']) ? "'".$row['comment']."'" : "NULL").",".
5813
                        (!empty($row['scope']) ? "'".$row['scope']."'" : "NULL").",".
5814
                        "".(!empty($row['subkeytext']) ? "'".$row['subkeytext']."'" : "NULL").",$access_url,".$row['access_url_changeable'].")";
5815
                    Database::query($insert);
5816
                }
5817
            } else { // Such a setting does not exist.
5818
                //error_log(__FILE__.':'.__LINE__.': Attempting to update setting '.$var.' ('.$subvar.') which does not exist at all. The access_url is: '.$access_url.' ',0);
5819
            }
5820
        }
5821
    }
5822
}
5823
5824
/**
5825
 * Sets a whole category of settings to one specific value.
5826
 *
5827
 * @param string    Category
5828
 * @param string    Value
5829
 * @param int       Access URL. Optional. Defaults to 1
5830
 * @param array     Optional array of filters on field type
5831
 * @param string $category
5832
 * @param string $value
5833
 *
5834
 * @return bool
5835
 */
5836
function api_set_settings_category($category, $value = null, $access_url = 1, $fieldtype = [])
5837
{
5838
    if (empty($category)) {
5839
        return false;
5840
    }
5841
    $category = Database::escape_string($category);
5842
    $t_s = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5843
    $access_url = (int) $access_url;
5844
    if (empty($access_url)) {
5845
        $access_url = 1;
5846
    }
5847
    if (isset($value)) {
5848
        $value = Database::escape_string($value);
5849
        $sql = "UPDATE $t_s SET selected_value = '$value'
5850
                WHERE category = '$category' AND access_url = $access_url";
5851
        if (is_array($fieldtype) && count($fieldtype) > 0) {
5852
            $sql .= " AND ( ";
5853
            $i = 0;
5854
            foreach ($fieldtype as $type) {
5855
                if ($i > 0) {
5856
                    $sql .= ' OR ';
5857
                }
5858
                $type = Database::escape_string($type);
5859
                $sql .= " type='".$type."' ";
5860
                $i++;
5861
            }
5862
            $sql .= ")";
5863
        }
5864
        $res = Database::query($sql);
5865
5866
        return $res !== false;
5867
    } else {
5868
        $sql = "UPDATE $t_s SET selected_value = NULL
5869
                WHERE category = '$category' AND access_url = $access_url";
5870
        if (is_array($fieldtype) && count($fieldtype) > 0) {
5871
            $sql .= " AND ( ";
5872
            $i = 0;
5873
            foreach ($fieldtype as $type) {
5874
                if ($i > 0) {
5875
                    $sql .= ' OR ';
5876
                }
5877
                $type = Database::escape_string($type);
5878
                $sql .= " type='".$type."' ";
5879
                $i++;
5880
            }
5881
            $sql .= ")";
5882
        }
5883
        $res = Database::query($sql);
5884
5885
        return $res !== false;
5886
    }
5887
}
5888
5889
/**
5890
 * Gets all available access urls in an array (as in the database).
5891
 *
5892
 * @return array An array of database records
5893
 */
5894
function api_get_access_urls($from = 0, $to = 1000000, $order = 'url', $direction = 'ASC')
5895
{
5896
    $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5897
    $from = (int) $from;
5898
    $to = (int) $to;
5899
    $order = Database::escape_string($order, null, false);
5900
    $direction = Database::escape_string($direction, null, false);
5901
    $sql = "SELECT id, url, description, active, created_by, tms
5902
            FROM $table
5903
            ORDER BY $order $direction
5904
            LIMIT $to OFFSET $from";
5905
    $res = Database::query($sql);
5906
5907
    return Database::store_result($res);
5908
}
5909
5910
/**
5911
 * Gets the access url info in an array.
5912
 *
5913
 * @param int  $id            Id of the access url
5914
 * @param bool $returnDefault Set to false if you want the real URL if URL 1 is still 'http://localhost/'
5915
 *
5916
 * @return array All the info (url, description, active, created_by, tms)
5917
 *               from the access_url table
5918
 *
5919
 * @author Julio Montoya
5920
 */
5921
function api_get_access_url($id, $returnDefault = true)
5922
{
5923
    static $staticResult;
5924
    $id = (int) $id;
5925
5926
    if (isset($staticResult[$id])) {
5927
        $result = $staticResult[$id];
5928
    } else {
5929
        // Calling the Database:: library dont work this is handmade.
5930
        $table_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5931
        $sql = "SELECT url, description, active, created_by, tms
5932
                FROM $table_access_url WHERE id = '$id' ";
5933
        $res = Database::query($sql);
5934
        $result = @Database::fetch_array($res);
5935
        $staticResult[$id] = $result;
5936
    }
5937
5938
    // If the result url is 'http://localhost/' (the default) and the root_web
5939
    // (=current url) is different, and the $id is = 1 (which might mean
5940
    // api_get_current_access_url_id() returned 1 by default), then return the
5941
    // root_web setting instead of the current URL
5942
    // This is provided as an option to avoid breaking the storage of URL-specific
5943
    // homepages in home/localhost/
5944
    if ($id === 1 && $returnDefault === false) {
5945
        $currentUrl = api_get_current_access_url_id();
5946
        // only do this if we are on the main URL (=1), otherwise we could get
5947
        // information on another URL instead of the one asked as parameter
5948
        if ($currentUrl === 1) {
5949
            $rootWeb = api_get_path(WEB_PATH);
5950
            $default = 'http://localhost/';
5951
            if ($result['url'] === $default && $rootWeb != $default) {
5952
                $result['url'] = $rootWeb;
5953
            }
5954
        }
5955
    }
5956
5957
    return $result;
5958
}
5959
5960
/**
5961
 * Gets all the current settings for a specific access url.
5962
 *
5963
 * @param string    The category, if any, that we want to get
5964
 * @param string    Whether we want a simple list (display a category) or
5965
 * a grouped list (group by variable as in settings.php default). Values: 'list' or 'group'
5966
 * @param int       Access URL's ID. Optional. Uses 1 by default, which is the unique URL
5967
 *
5968
 * @return array Array of database results for the current settings of the current access URL
5969
 */
5970
function &api_get_settings($cat = null, $ordering = 'list', $access_url = 1, $url_changeable = 0)
5971
{
5972
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5973
    $access_url = (int) $access_url;
5974
    $where_condition = '';
5975
    if ($url_changeable == 1) {
5976
        $where_condition = " AND access_url_changeable= '1' ";
5977
    }
5978
    if (empty($access_url) || $access_url == -1) {
5979
        $access_url = 1;
5980
    }
5981
    $sql = "SELECT * FROM $table
5982
            WHERE access_url = $access_url  $where_condition ";
5983
5984
    if (!empty($cat)) {
5985
        $cat = Database::escape_string($cat);
5986
        $sql .= " AND category='$cat' ";
5987
    }
5988
    if ($ordering == 'group') {
5989
        $sql .= " ORDER BY id ASC";
5990
    } else {
5991
        $sql .= " ORDER BY 1,2 ASC";
5992
    }
5993
    $result = Database::query($sql);
5994
    if ($result === null) {
5995
        return [];
5996
    }
5997
    $result = Database::store_result($result, 'ASSOC');
5998
5999
    return $result;
6000
}
6001
6002
/**
6003
 * @param string $value       The value we want to record
6004
 * @param string $variable    The variable name we want to insert
6005
 * @param string $subKey      The subkey for the variable we want to insert
6006
 * @param string $type        The type for the variable we want to insert
6007
 * @param string $category    The category for the variable we want to insert
6008
 * @param string $title       The title
6009
 * @param string $comment     The comment
6010
 * @param string $scope       The scope
6011
 * @param string $subKeyText  The subkey text
6012
 * @param int    $accessUrlId The access_url for which this parameter is valid
6013
 * @param int    $visibility  The changeability of this setting for non-master urls
6014
 *
6015
 * @return int The setting ID
6016
 */
6017
function api_add_setting(
6018
    $value,
6019
    $variable,
6020
    $subKey = '',
6021
    $type = 'textfield',
6022
    $category = '',
6023
    $title = '',
6024
    $comment = '',
6025
    $scope = '',
6026
    $subKeyText = '',
6027
    $accessUrlId = 1,
6028
    $visibility = 0
6029
) {
6030
    $em = Database::getManager();
6031
    $settingRepo = $em->getRepository('ChamiloCoreBundle:SettingsCurrent');
6032
    $accessUrlId = (int) $accessUrlId ?: 1;
6033
6034
    if (is_array($value)) {
6035
        $value = serialize($value);
6036
    } else {
6037
        $value = trim($value);
6038
    }
6039
6040
    $criteria = ['variable' => $variable, 'url' => $accessUrlId];
6041
6042
    if (!empty($subKey)) {
6043
        $criteria['subkey'] = $subKey;
6044
    }
6045
6046
    // Check if this variable doesn't exist already
6047
    /** @var SettingsCurrent $setting */
6048
    $setting = $settingRepo->findOneBy($criteria);
6049
6050
    if ($setting) {
0 ignored issues
show
introduced by
$setting is of type Chamilo\CoreBundle\Entity\SettingsCurrent, thus it always evaluated to true. If $setting can have other possible types, add them to main/inc/lib/api.lib.php:6047
Loading history...
6051
        $setting->setSelectedValue($value);
6052
6053
        $em->persist($setting);
6054
        $em->flush();
6055
6056
        return $setting->getId();
6057
    }
6058
6059
    // Item not found for this access_url, we have to check if the whole thing is missing
6060
    // (in which case we ignore the insert) or if there *is* a record but just for access_url = 1
6061
    $setting = new SettingsCurrent();
6062
    $url = api_get_url_entity();
6063
6064
    $setting
6065
        ->setVariable($variable)
6066
        ->setSelectedValue($value)
6067
        ->setType($type)
6068
        ->setCategory($category)
6069
        ->setSubkey($subKey)
6070
        ->setTitle($title)
6071
        ->setComment($comment)
6072
        ->setScope($scope)
6073
        ->setSubkeytext($subKeyText)
6074
        ->setUrl(api_get_url_entity())
6075
        ->setAccessUrlChangeable($visibility);
6076
6077
    $em->persist($setting);
6078
    $em->flush();
6079
6080
    return $setting->getId();
6081
}
6082
6083
/**
6084
 * Checks wether a user can or can't view the contents of a course.
6085
 *
6086
 * @deprecated use CourseManager::is_user_subscribed_in_course
6087
 *
6088
 * @param int $userid User id or NULL to get it from $_SESSION
6089
 * @param int $cid    course id to check whether the user is allowed
6090
 *
6091
 * @return bool
6092
 */
6093
function api_is_course_visible_for_user($userid = null, $cid = null)
6094
{
6095
    if ($userid === null) {
6096
        $userid = api_get_user_id();
6097
    }
6098
    if (empty($userid) || strval(intval($userid)) != $userid) {
6099
        if (api_is_anonymous()) {
6100
            $userid = api_get_anonymous_id();
6101
        } else {
6102
            return false;
6103
        }
6104
    }
6105
    $cid = Database::escape_string($cid);
6106
6107
    $courseInfo = api_get_course_info($cid);
6108
    $courseId = $courseInfo['real_id'];
6109
    $is_platformAdmin = api_is_platform_admin();
6110
6111
    $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
6112
    $course_cat_table = Database::get_main_table(TABLE_MAIN_CATEGORY);
6113
6114
    $sql = "SELECT
6115
                $course_table.category_code,
6116
                $course_table.visibility,
6117
                $course_table.code,
6118
                $course_cat_table.code
6119
            FROM $course_table
6120
            LEFT JOIN $course_cat_table
6121
                ON $course_table.category_code = $course_cat_table.code
6122
            WHERE
6123
                $course_table.code = '$cid'
6124
            LIMIT 1";
6125
6126
    $result = Database::query($sql);
6127
6128
    if (Database::num_rows($result) > 0) {
6129
        $visibility = Database::fetch_array($result);
6130
        $visibility = $visibility['visibility'];
6131
    } else {
6132
        $visibility = 0;
6133
    }
6134
    // Shortcut permissions in case the visibility is "open to the world".
6135
    if ($visibility === COURSE_VISIBILITY_OPEN_WORLD) {
6136
        return true;
6137
    }
6138
6139
    $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
6140
6141
    $sql = "SELECT
6142
                is_tutor, status
6143
            FROM $tbl_course_user
6144
            WHERE
6145
                user_id  = '$userid' AND
6146
                relation_type <> '".COURSE_RELATION_TYPE_RRHH."' AND
6147
                c_id = $courseId
6148
            LIMIT 1";
6149
6150
    $result = Database::query($sql);
6151
6152
    if (Database::num_rows($result) > 0) {
6153
        // This user has got a recorded state for this course.
6154
        $cuData = Database::fetch_array($result);
6155
        $is_courseMember = true;
6156
        $is_courseAdmin = ($cuData['status'] == 1);
6157
    }
6158
6159
    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...
6160
        // This user has no status related to this course.
6161
        // Is it the session coach or the session admin?
6162
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
6163
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
6164
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
6165
6166
        $sql = "SELECT
6167
                    session.id_coach, session_admin_id, session.id
6168
                FROM
6169
                    $tbl_session as session
6170
                INNER JOIN $tbl_session_course
6171
                    ON session_rel_course.session_id = session.id
6172
                    AND session_rel_course.c_id = '$courseId'
6173
                LIMIT 1";
6174
6175
        $result = Database::query($sql);
6176
        $row = Database::store_result($result);
6177
6178
        if ($row[0]['id_coach'] == $userid) {
6179
            $is_courseMember = true;
6180
            $is_courseAdmin = false;
6181
        } elseif ($row[0]['session_admin_id'] == $userid) {
6182
            $is_courseMember = false;
6183
            $is_courseAdmin = false;
6184
        } else {
6185
            // Check if the current user is the course coach.
6186
            $sql = "SELECT 1
6187
                    FROM $tbl_session_course
6188
                    WHERE session_rel_course.c_id = '$courseId'
6189
                    AND session_rel_course.id_coach = '$userid'
6190
                    LIMIT 1";
6191
6192
            $result = Database::query($sql);
6193
6194
            //if ($row = Database::fetch_array($result)) {
6195
            if (Database::num_rows($result) > 0) {
6196
                $is_courseMember = true;
6197
                $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
6198
6199
                $sql = "SELECT status FROM $tbl_user
6200
                        WHERE user_id = $userid
6201
                        LIMIT 1";
6202
6203
                $result = Database::query($sql);
6204
6205
                if (Database::result($result, 0, 0) == 1) {
6206
                    $is_courseAdmin = true;
6207
                } else {
6208
                    $is_courseAdmin = false;
6209
                }
6210
            } else {
6211
                // Check if the user is a student is this session.
6212
                $sql = "SELECT  id
6213
                        FROM $tbl_session_course_user
6214
                        WHERE
6215
                            user_id  = '$userid' AND
6216
                            c_id = '$courseId'
6217
                        LIMIT 1";
6218
6219
                if (Database::num_rows($result) > 0) {
6220
                    // This user haa got a recorded state for this course.
6221
                    while ($row = Database::fetch_array($result)) {
6222
                        $is_courseMember = true;
6223
                        $is_courseAdmin = false;
6224
                    }
6225
                }
6226
            }
6227
        }
6228
    }
6229
6230
    switch ($visibility) {
6231
        case COURSE_VISIBILITY_OPEN_WORLD:
6232
            return true;
6233
        case COURSE_VISIBILITY_OPEN_PLATFORM:
6234
            return isset($userid);
6235
        case COURSE_VISIBILITY_REGISTERED:
6236
        case COURSE_VISIBILITY_CLOSED:
6237
            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...
6238
        case COURSE_VISIBILITY_HIDDEN:
6239
            return $is_platformAdmin;
6240
    }
6241
6242
    return false;
6243
}
6244
6245
/**
6246
 * Returns whether an element (forum, message, survey ...) belongs to a session or not.
6247
 *
6248
 * @param string the tool of the element
6249
 * @param int the element id in database
6250
 * @param int the session_id to compare with element session id
6251
 * @param string $tool
6252
 *
6253
 * @return bool true if the element is in the session, false else
6254
 */
6255
function api_is_element_in_the_session($tool, $element_id, $session_id = null)
6256
{
6257
    if (is_null($session_id)) {
6258
        $session_id = api_get_session_id();
6259
    }
6260
6261
    // Get information to build query depending of the tool.
6262
    switch ($tool) {
6263
        case TOOL_SURVEY:
6264
            $table_tool = Database::get_course_table(TABLE_SURVEY);
6265
            $key_field = 'survey_id';
6266
            break;
6267
        case TOOL_ANNOUNCEMENT:
6268
            $table_tool = Database::get_course_table(TABLE_ANNOUNCEMENT);
6269
            $key_field = 'id';
6270
            break;
6271
        case TOOL_AGENDA:
6272
            $table_tool = Database::get_course_table(TABLE_AGENDA);
6273
            $key_field = 'id';
6274
            break;
6275
        case TOOL_GROUP:
6276
            $table_tool = Database::get_course_table(TABLE_GROUP);
6277
            $key_field = 'id';
6278
            break;
6279
        default:
6280
            return false;
6281
    }
6282
    $course_id = api_get_course_int_id();
6283
6284
    $sql = "SELECT session_id FROM $table_tool 
6285
            WHERE c_id = $course_id AND $key_field =  ".intval($element_id);
6286
    $rs = Database::query($sql);
6287
    if ($element_session_id = Database::result($rs, 0, 0)) {
6288
        if ($element_session_id == intval($session_id)) {
6289
            // The element belongs to the session.
6290
            return true;
6291
        }
6292
    }
6293
6294
    return false;
6295
}
6296
6297
/**
6298
 * Replaces "forbidden" characters in a filename string.
6299
 *
6300
 * @param string $filename
6301
 * @param bool   $treat_spaces_as_hyphens
6302
 *
6303
 * @return string
6304
 */
6305
function api_replace_dangerous_char($filename, $treat_spaces_as_hyphens = true)
6306
{
6307
    // Some non-properly encoded file names can cause the whole file to be
6308
    // skipped when uploaded. Avoid this by detecting the encoding and
6309
    // converting to UTF-8, setting the source as ASCII (a reasonably
6310
    // limited characters set) if nothing could be found (BT#
6311
    $encoding = api_detect_encoding($filename);
6312
    if (empty($encoding)) {
6313
        $encoding = 'ASCII';
6314
    }
6315
    $filename = api_to_system_encoding($filename, $encoding);
6316
    $url = URLify::filter(
6317
        $filename,
6318
        250,
6319
        '',
6320
        true,
6321
        true,
6322
        false,
6323
        false,
6324
        $treat_spaces_as_hyphens
6325
    );
6326
6327
    return $url;
6328
}
6329
6330
/**
6331
 * Fixes the $_SERVER['REQUEST_URI'] that is empty in IIS6.
6332
 *
6333
 * @author Ivan Tcholakov, 28-JUN-2006.
6334
 */
6335
function api_request_uri()
6336
{
6337
    if (!empty($_SERVER['REQUEST_URI'])) {
6338
        return $_SERVER['REQUEST_URI'];
6339
    }
6340
    $uri = $_SERVER['SCRIPT_NAME'];
6341
    if (!empty($_SERVER['QUERY_STRING'])) {
6342
        $uri .= '?'.$_SERVER['QUERY_STRING'];
6343
    }
6344
    $_SERVER['REQUEST_URI'] = $uri;
6345
6346
    return $uri;
6347
}
6348
6349
/** Gets the current access_url id of the Chamilo Platform
6350
 * @author Julio Montoya <[email protected]>
6351
 *
6352
 * @return int access_url_id of the current Chamilo Installation
6353
 */
6354
function api_get_current_access_url_id()
6355
{
6356
    $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
6357
    $path = Database::escape_string(api_get_path(WEB_PATH));
6358
    $sql = "SELECT id FROM $table WHERE url = '".$path."'";
6359
    $result = Database::query($sql);
6360
    if (Database::num_rows($result) > 0) {
6361
        $access_url_id = Database::result($result, 0, 0);
6362
        if ($access_url_id === false) {
6363
            return -1;
6364
        }
6365
6366
        return $access_url_id;
6367
    }
6368
6369
    //if the url in WEB_PATH was not found, it can only mean that there is
6370
    // either a configuration problem or the first URL has not been defined yet
6371
    // (by default it is http://localhost/). Thus the more sensible thing we can
6372
    // do is return 1 (the main URL) as the user cannot hack this value anyway
6373
    return 1;
6374
}
6375
6376
/**
6377
 * Gets the registered urls from a given user id.
6378
 *
6379
 * @author Julio Montoya <[email protected]>
6380
 *
6381
 * @return int user id
6382
 */
6383
function api_get_access_url_from_user($user_id)
6384
{
6385
    $user_id = (int) $user_id;
6386
    $table_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
6387
    $table_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
6388
    $sql = "SELECT access_url_id
6389
            FROM $table_url_rel_user url_rel_user
6390
            INNER JOIN $table_url u
6391
            ON (url_rel_user.access_url_id = u.id)
6392
            WHERE user_id = ".intval($user_id);
6393
    $result = Database::query($sql);
6394
    $list = [];
6395
    while ($row = Database::fetch_array($result, 'ASSOC')) {
6396
        $list[] = $row['access_url_id'];
6397
    }
6398
6399
    return $list;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $list returns the type array which is incompatible with the documented return type integer.
Loading history...
6400
}
6401
6402
/**
6403
 * Gets the status of a user in a course.
6404
 *
6405
 * @param int $user_id
6406
 * @param int $courseId
6407
 *
6408
 * @return int user status
6409
 */
6410
function api_get_status_of_user_in_course($user_id, $courseId)
6411
{
6412
    $tbl_rel_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
6413
    if (!empty($user_id) && !empty($courseId)) {
6414
        $user_id = intval($user_id);
6415
        $courseId = intval($courseId);
6416
        $sql = 'SELECT status
6417
                FROM '.$tbl_rel_course_user.'
6418
                WHERE user_id='.$user_id.' AND c_id = '.$courseId;
6419
        $result = Database::query($sql);
6420
        $row_status = Database::fetch_array($result, 'ASSOC');
6421
6422
        return $row_status['status'];
6423
    } else {
6424
        return 0;
6425
    }
6426
}
6427
6428
/**
6429
 * Checks whether the curent user is in a group or not.
6430
 *
6431
 * @param string        The group id - optional (takes it from session if not given)
6432
 * @param string        The course code - optional (no additional check by course if course code is not given)
6433
 *
6434
 * @return bool
6435
 *
6436
 * @author Ivan Tcholakov
6437
 */
6438
function api_is_in_group($groupIdParam = null, $courseCodeParam = null)
6439
{
6440
    if (!empty($courseCodeParam)) {
6441
        $courseCode = api_get_course_id();
6442
        if (!empty($courseCode)) {
6443
            if ($courseCodeParam != $courseCode) {
6444
                return false;
6445
            }
6446
        } else {
6447
            return false;
6448
        }
6449
    }
6450
6451
    $groupId = api_get_group_id();
6452
6453
    if (isset($groupId) && $groupId != '') {
6454
        if (!empty($groupIdParam)) {
6455
            return $groupIdParam == $groupId;
6456
        } else {
6457
            return true;
6458
        }
6459
    }
6460
6461
    return false;
6462
}
6463
6464
/**
6465
 * Checks whether a secret key is valid.
6466
 *
6467
 * @param string $original_key_secret - secret key from (webservice) client
6468
 * @param string $security_key        - security key from Chamilo
6469
 *
6470
 * @return bool - true if secret key is valid, false otherwise
6471
 */
6472
function api_is_valid_secret_key($original_key_secret, $security_key)
6473
{
6474
    return $original_key_secret == sha1($security_key);
6475
}
6476
6477
/**
6478
 * Checks whether a user is into course.
6479
 *
6480
 * @param int $course_id - the course id
6481
 * @param int $user_id   - the user id
6482
 *
6483
 * @return bool
6484
 */
6485
function api_is_user_of_course($course_id, $user_id)
6486
{
6487
    $tbl_course_rel_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
6488
    $sql = 'SELECT user_id FROM '.$tbl_course_rel_user.'
6489
            WHERE
6490
                c_id ="'.intval($course_id).'" AND
6491
                user_id = "'.intval($user_id).'" AND
6492
                relation_type <> '.COURSE_RELATION_TYPE_RRHH.' ';
6493
    $result = Database::query($sql);
6494
6495
    return Database::num_rows($result) == 1;
6496
}
6497
6498
/**
6499
 * Checks whether the server's operating system is Windows (TM).
6500
 *
6501
 * @return bool - true if the operating system is Windows, false otherwise
6502
 */
6503
function api_is_windows_os()
6504
{
6505
    if (function_exists('php_uname')) {
6506
        // php_uname() exists as of PHP 4.0.2, according to the documentation.
6507
        // We expect that this function will always work for Chamilo 1.8.x.
6508
        $os = php_uname();
6509
    }
6510
    // The following methods are not needed, but let them stay, just in case.
6511
    elseif (isset($_ENV['OS'])) {
6512
        // Sometimes $_ENV['OS'] may not be present (bugs?)
6513
        $os = $_ENV['OS'];
6514
    } elseif (defined('PHP_OS')) {
6515
        // PHP_OS means on which OS PHP was compiled, this is why
6516
        // using PHP_OS is the last choice for detection.
6517
        $os = PHP_OS;
6518
    } else {
6519
        return false;
6520
    }
6521
6522
    return strtolower(substr((string) $os, 0, 3)) == 'win';
6523
}
6524
6525
/**
6526
 * This function informs whether the sent request is XMLHttpRequest.
6527
 */
6528
function api_is_xml_http_request()
6529
{
6530
    return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest';
6531
}
6532
6533
/**
6534
 * This wrapper function has been implemented for avoiding some known problems about the function getimagesize().
6535
 *
6536
 * @see http://php.net/manual/en/function.getimagesize.php
6537
 * @see http://www.dokeos.com/forum/viewtopic.php?t=12345
6538
 * @see http://www.dokeos.com/forum/viewtopic.php?t=16355
6539
 *
6540
 * @return int
6541
 */
6542
function api_getimagesize($path)
6543
{
6544
    $image = new Image($path);
6545
6546
    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<string,integer>|array which is incompatible with the documented return type integer.
Loading history...
6547
}
6548
6549
/**
6550
 * This function resizes an image, with preserving its proportions (or aspect ratio).
6551
 *
6552
 * @author Ivan Tcholakov, MAY-2009.
6553
 *
6554
 * @param int $image         System path or URL of the image
6555
 * @param int $target_width  Targeted width
6556
 * @param int $target_height Targeted height
6557
 *
6558
 * @return array Calculated new width and height
6559
 */
6560
function api_resize_image($image, $target_width, $target_height)
6561
{
6562
    $image_properties = api_getimagesize($image);
6563
6564
    return api_calculate_image_size(
6565
        $image_properties['width'],
6566
        $image_properties['height'],
6567
        $target_width,
6568
        $target_height
6569
    );
6570
}
6571
6572
/**
6573
 * This function calculates new image size, with preserving image's proportions (or aspect ratio).
6574
 *
6575
 * @author Ivan Tcholakov, MAY-2009.
6576
 * @author The initial idea has been taken from code by Patrick Cool, MAY-2004.
6577
 *
6578
 * @param int $image_width   Initial width
6579
 * @param int $image_height  Initial height
6580
 * @param int $target_width  Targeted width
6581
 * @param int $target_height Targeted height
6582
 *
6583
 * @return array Calculated new width and height
6584
 */
6585
function api_calculate_image_size(
6586
    $image_width,
6587
    $image_height,
6588
    $target_width,
6589
    $target_height
6590
) {
6591
    // Only maths is here.
6592
    $result = ['width' => $image_width, 'height' => $image_height];
6593
    if ($image_width <= 0 || $image_height <= 0) {
6594
        return $result;
6595
    }
6596
    $resize_factor_width = $target_width / $image_width;
6597
    $resize_factor_height = $target_height / $image_height;
6598
    $delta_width = $target_width - $image_width * $resize_factor_height;
6599
    $delta_height = $target_height - $image_height * $resize_factor_width;
6600
    if ($delta_width > $delta_height) {
6601
        $result['width'] = ceil($image_width * $resize_factor_height);
6602
        $result['height'] = ceil($image_height * $resize_factor_height);
6603
    } elseif ($delta_width < $delta_height) {
6604
        $result['width'] = ceil($image_width * $resize_factor_width);
6605
        $result['height'] = ceil($image_height * $resize_factor_width);
6606
    } else {
6607
        $result['width'] = ceil($target_width);
6608
        $result['height'] = ceil($target_height);
6609
    }
6610
6611
    return $result;
6612
}
6613
6614
/**
6615
 * Returns a list of Chamilo's tools or
6616
 * checks whether a given identificator is a valid Chamilo's tool.
6617
 *
6618
 * @author Isaac flores paz
6619
 *
6620
 * @param string The tool name to filter
6621
 *
6622
 * @return mixed Filtered string or array
6623
 */
6624
function api_get_tools_lists($my_tool = null)
6625
{
6626
    $tools_list = [
6627
        TOOL_DOCUMENT,
6628
        TOOL_THUMBNAIL,
6629
        TOOL_HOTPOTATOES,
6630
        TOOL_CALENDAR_EVENT,
6631
        TOOL_LINK,
6632
        TOOL_COURSE_DESCRIPTION,
6633
        TOOL_SEARCH,
6634
        TOOL_LEARNPATH,
6635
        TOOL_ANNOUNCEMENT,
6636
        TOOL_FORUM,
6637
        TOOL_THREAD,
6638
        TOOL_POST,
6639
        TOOL_DROPBOX,
6640
        TOOL_QUIZ,
6641
        TOOL_USER,
6642
        TOOL_GROUP,
6643
        TOOL_BLOGS,
6644
        TOOL_CHAT,
6645
        TOOL_STUDENTPUBLICATION,
6646
        TOOL_TRACKING,
6647
        TOOL_HOMEPAGE_LINK,
6648
        TOOL_COURSE_SETTING,
6649
        TOOL_BACKUP,
6650
        TOOL_COPY_COURSE_CONTENT,
6651
        TOOL_RECYCLE_COURSE,
6652
        TOOL_COURSE_HOMEPAGE,
6653
        TOOL_COURSE_RIGHTS_OVERVIEW,
6654
        TOOL_UPLOAD,
6655
        TOOL_COURSE_MAINTENANCE,
6656
        TOOL_SURVEY,
6657
        TOOL_WIKI,
6658
        TOOL_GLOSSARY,
6659
        TOOL_GRADEBOOK,
6660
        TOOL_NOTEBOOK,
6661
        TOOL_ATTENDANCE,
6662
        TOOL_COURSE_PROGRESS,
6663
    ];
6664
    if (empty($my_tool)) {
6665
        return $tools_list;
6666
    }
6667
6668
    return in_array($my_tool, $tools_list) ? $my_tool : '';
6669
}
6670
6671
/**
6672
 * Checks whether we already approved the last version term and condition.
6673
 *
6674
 * @param int user id
6675
 *
6676
 * @return bool true if we pass false otherwise
6677
 */
6678
function api_check_term_condition($userId)
6679
{
6680
    if (api_get_setting('allow_terms_conditions') === 'true') {
6681
        // Check if exists terms and conditions
6682
        if (LegalManager::count() == 0) {
6683
            return true;
6684
        }
6685
6686
        $extraFieldValue = new ExtraFieldValue('user');
6687
        $data = $extraFieldValue->get_values_by_handler_and_field_variable(
6688
            $userId,
6689
            'legal_accept'
6690
        );
6691
6692
        if (!empty($data) && isset($data['value']) && !empty($data['value'])) {
6693
            $result = $data['value'];
6694
            $user_conditions = explode(':', $result);
6695
            $version = $user_conditions[0];
6696
            $langId = $user_conditions[1];
6697
            $realVersion = LegalManager::get_last_version($langId);
6698
6699
            return $version >= $realVersion;
6700
        }
6701
6702
        return false;
6703
    }
6704
6705
    return false;
6706
}
6707
6708
/**
6709
 * Gets all information of a tool into course.
6710
 *
6711
 * @param int The tool id
6712
 *
6713
 * @return array
6714
 */
6715
function api_get_tool_information_by_name($name)
6716
{
6717
    $t_tool = Database::get_course_table(TABLE_TOOL_LIST);
6718
    $course_id = api_get_course_int_id();
6719
    $sql = "SELECT * FROM $t_tool
6720
            WHERE c_id = $course_id  AND name = '".Database::escape_string($name)."' ";
6721
    $rs = Database::query($sql);
6722
6723
    return Database::fetch_array($rs, 'ASSOC');
6724
}
6725
6726
/**
6727
 * Function used to protect a "global" admin script.
6728
 * The function blocks access when the user has no global platform admin rights.
6729
 * Global admins are the admins that are registered in the main.admin table
6730
 * AND the users who have access to the "principal" portal.
6731
 * That means that there is a record in the main.access_url_rel_user table
6732
 * with his user id and the access_url_id=1.
6733
 *
6734
 * @author Julio Montoya
6735
 *
6736
 * @param int $user_id
6737
 *
6738
 * @return bool
6739
 */
6740
function api_is_global_platform_admin($user_id = null)
6741
{
6742
    $user_id = (int) $user_id;
6743
    if (empty($user_id)) {
6744
        $user_id = api_get_user_id();
6745
    }
6746
    if (api_is_platform_admin_by_id($user_id)) {
6747
        $urlList = api_get_access_url_from_user($user_id);
6748
        // The admin is registered in the first "main" site with access_url_id = 1
6749
        if (in_array(1, $urlList)) {
6750
            return true;
6751
        } else {
6752
            return false;
6753
        }
6754
    }
6755
6756
    return false;
6757
}
6758
6759
/**
6760
 * @param int  $admin_id_to_check
6761
 * @param int  $my_user_id
6762
 * @param bool $allow_session_admin
6763
 *
6764
 * @return bool
6765
 */
6766
function api_global_admin_can_edit_admin(
6767
    $admin_id_to_check,
6768
    $my_user_id = null,
6769
    $allow_session_admin = false
6770
) {
6771
    if (empty($my_user_id)) {
6772
        $my_user_id = api_get_user_id();
6773
    }
6774
6775
    $iam_a_global_admin = api_is_global_platform_admin($my_user_id);
6776
    $user_is_global_admin = api_is_global_platform_admin($admin_id_to_check);
6777
6778
    if ($iam_a_global_admin) {
6779
        // Global admin can edit everything
6780
        return true;
6781
    } else {
6782
        // If i'm a simple admin
6783
        $is_platform_admin = api_is_platform_admin_by_id($my_user_id);
6784
6785
        if ($allow_session_admin) {
6786
            $is_platform_admin = api_is_platform_admin_by_id($my_user_id) || (api_get_user_status($my_user_id) == SESSIONADMIN);
6787
        }
6788
6789
        if ($is_platform_admin) {
6790
            if ($user_is_global_admin) {
6791
                return false;
6792
            } else {
6793
                return true;
6794
            }
6795
        } else {
6796
            return false;
6797
        }
6798
    }
6799
}
6800
6801
/**
6802
 * @param int  $admin_id_to_check
6803
 * @param int  $my_user_id
6804
 * @param bool $allow_session_admin
6805
 *
6806
 * @return bool|null
6807
 */
6808
function api_protect_super_admin($admin_id_to_check, $my_user_id = null, $allow_session_admin = false)
6809
{
6810
    if (api_global_admin_can_edit_admin($admin_id_to_check, $my_user_id, $allow_session_admin)) {
6811
        return true;
6812
    } else {
6813
        api_not_allowed();
6814
    }
6815
}
6816
6817
/**
6818
 * Function used to protect a global admin script.
6819
 * The function blocks access when the user has no global platform admin rights.
6820
 * See also the api_is_global_platform_admin() function wich defines who's a "global" admin.
6821
 *
6822
 * @author Julio Montoya
6823
 */
6824
function api_protect_global_admin_script()
6825
{
6826
    if (!api_is_global_platform_admin()) {
6827
        api_not_allowed();
6828
6829
        return false;
6830
    }
6831
6832
    return true;
6833
}
6834
6835
/**
6836
 * Get active template.
6837
 *
6838
 * @param string    theme type (optional: default)
6839
 * @param string    path absolute(abs) or relative(rel) (optional:rel)
6840
 *
6841
 * @return string actived template path
6842
 */
6843
function api_get_template($path_type = 'rel')
6844
{
6845
    $path_types = ['rel', 'abs'];
6846
    $template_path = '';
6847
    if (in_array($path_type, $path_types)) {
6848
        if ($path_type == 'rel') {
6849
            $template_path = api_get_path(SYS_TEMPLATE_PATH);
6850
        } else {
6851
            $template_path = api_get_path(WEB_TEMPLATE_PATH);
6852
        }
6853
    }
6854
    $actived_theme = 'default';
6855
    if (api_get_setting('active_template')) {
6856
        $actived_theme = api_get_setting('active_template');
6857
    }
6858
    $actived_theme_path = $template_path.$actived_theme.DIRECTORY_SEPARATOR;
6859
6860
    return $actived_theme_path;
6861
}
6862
6863
/**
6864
 * Check browser support for specific file types or features
6865
 * This function checks if the user's browser supports a file format or given
6866
 * feature, or returns the current browser and major version when
6867
 * $format=check_browser. Only a limited number of formats and features are
6868
 * checked by this method. Make sure you check its definition first.
6869
 *
6870
 * @param string $format Can be a file format (extension like svg, webm, ...) or a feature (like autocapitalize, ...)
6871
 *
6872
 * @return bool or return text array if $format=check_browser
6873
 *
6874
 * @author Juan Carlos Raña Trabado
6875
 */
6876
function api_browser_support($format = '')
6877
{
6878
    $browser = new Browser();
6879
    $current_browser = $browser->getBrowser();
6880
    $a_versiontemp = explode('.', $browser->getVersion());
6881
    $current_majorver = $a_versiontemp[0];
6882
6883
    static $result;
6884
6885
    if (isset($result[$format])) {
6886
        return $result[$format];
6887
    }
6888
6889
    // Native svg support
6890
    if ($format == 'svg') {
6891
        if (($current_browser == 'Internet Explorer' && $current_majorver >= 9) ||
6892
            ($current_browser == 'Firefox' && $current_majorver > 1) ||
6893
            ($current_browser == 'Safari' && $current_majorver >= 4) ||
6894
            ($current_browser == 'Chrome' && $current_majorver >= 1) ||
6895
            ($current_browser == 'Opera' && $current_majorver >= 9)
6896
        ) {
6897
            $result[$format] = true;
6898
6899
            return true;
6900
        } else {
6901
            $result[$format] = false;
6902
6903
            return false;
6904
        }
6905
    } elseif ($format == 'pdf') {
6906
        // native pdf support
6907
        if ($current_browser == 'Chrome' && $current_majorver >= 6) {
6908
            $result[$format] = true;
6909
6910
            return true;
6911
        } else {
6912
            $result[$format] = false;
6913
6914
            return false;
6915
        }
6916
    } elseif ($format == 'tif' || $format == 'tiff') {
6917
        //native tif support
6918
        if ($current_browser == 'Safari' && $current_majorver >= 5) {
6919
            $result[$format] = true;
6920
6921
            return true;
6922
        } else {
6923
            $result[$format] = false;
6924
6925
            return false;
6926
        }
6927
    } elseif ($format == 'ogg' || $format == 'ogx' || $format == 'ogv' || $format == 'oga') {
6928
        //native ogg, ogv,oga support
6929
        if (($current_browser == 'Firefox' && $current_majorver >= 3) ||
6930
            ($current_browser == 'Chrome' && $current_majorver >= 3) ||
6931
            ($current_browser == 'Opera' && $current_majorver >= 9)) {
6932
            $result[$format] = true;
6933
6934
            return true;
6935
        } else {
6936
            $result[$format] = false;
6937
6938
            return false;
6939
        }
6940
    } elseif ($format == 'mpg' || $format == 'mpeg') {
6941
        //native mpg support
6942
        if (($current_browser == 'Safari' && $current_majorver >= 5)) {
6943
            $result[$format] = true;
6944
6945
            return true;
6946
        } else {
6947
            $result[$format] = false;
6948
6949
            return false;
6950
        }
6951
    } elseif ($format == 'mp4') {
6952
        //native mp4 support (TODO: Android, iPhone)
6953
        if ($current_browser == 'Android' || $current_browser == 'iPhone') {
6954
            $result[$format] = true;
6955
6956
            return true;
6957
        } else {
6958
            $result[$format] = false;
6959
6960
            return false;
6961
        }
6962
    } elseif ($format == 'mov') {
6963
        //native mov support( TODO:check iPhone)
6964
        if ($current_browser == 'Safari' && $current_majorver >= 5 || $current_browser == 'iPhone') {
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: ($current_browser == 'Sa...ent_browser == 'iPhone', Probably Intended Meaning: $current_browser == 'Saf...nt_browser == 'iPhone')
Loading history...
6965
            $result[$format] = true;
6966
6967
            return true;
6968
        } else {
6969
            $result[$format] = false;
6970
6971
            return false;
6972
        }
6973
    } elseif ($format == 'avi') {
6974
        //native avi support
6975
        if ($current_browser == 'Safari' && $current_majorver >= 5) {
6976
            $result[$format] = true;
6977
6978
            return true;
6979
        } else {
6980
            $result[$format] = false;
6981
6982
            return false;
6983
        }
6984
    } elseif ($format == 'wmv') {
6985
        //native wmv support
6986
        if ($current_browser == 'Firefox' && $current_majorver >= 4) {
6987
            $result[$format] = true;
6988
6989
            return true;
6990
        } else {
6991
            $result[$format] = false;
6992
6993
            return false;
6994
        }
6995
    } elseif ($format == 'webm') {
6996
        //native webm support (TODO:check IE9, Chrome9, Android)
6997
        if (($current_browser == 'Firefox' && $current_majorver >= 4) ||
6998
            ($current_browser == 'Opera' && $current_majorver >= 9) ||
6999
            ($current_browser == 'Internet Explorer' && $current_majorver >= 9) ||
7000
            ($current_browser == 'Chrome' && $current_majorver >= 9) ||
7001
            $current_browser == 'Android'
7002
        ) {
7003
            $result[$format] = true;
7004
7005
            return true;
7006
        } else {
7007
            $result[$format] = false;
7008
7009
            return false;
7010
        }
7011
    } elseif ($format == 'wav') {
7012
        //native wav support (only some codecs !)
7013
        if (($current_browser == 'Firefox' && $current_majorver >= 4) ||
7014
            ($current_browser == 'Safari' && $current_majorver >= 5) ||
7015
            ($current_browser == 'Opera' && $current_majorver >= 9) ||
7016
            ($current_browser == 'Internet Explorer' && $current_majorver >= 9) ||
7017
            ($current_browser == 'Chrome' && $current_majorver > 9) ||
7018
            $current_browser == 'Android' ||
7019
            $current_browser == 'iPhone'
7020
        ) {
7021
            $result[$format] = true;
7022
7023
            return true;
7024
        } else {
7025
            $result[$format] = false;
7026
7027
            return false;
7028
        }
7029
    } elseif ($format == 'mid' || $format == 'kar') {
7030
        //native midi support (TODO:check Android)
7031
        if ($current_browser == 'Opera' && $current_majorver >= 9 || $current_browser == 'Android') {
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: ($current_browser == 'Op...nt_browser == 'Android', Probably Intended Meaning: $current_browser == 'Ope...t_browser == 'Android')
Loading history...
7032
            $result[$format] = true;
7033
7034
            return true;
7035
        } else {
7036
            $result[$format] = false;
7037
7038
            return false;
7039
        }
7040
    } elseif ($format == 'wma') {
7041
        //native wma support
7042
        if ($current_browser == 'Firefox' && $current_majorver >= 4) {
7043
            $result[$format] = true;
7044
7045
            return true;
7046
        } else {
7047
            $result[$format] = false;
7048
7049
            return false;
7050
        }
7051
    } elseif ($format == 'au') {
7052
        //native au support
7053
        if ($current_browser == 'Safari' && $current_majorver >= 5) {
7054
            $result[$format] = true;
7055
7056
            return true;
7057
        } else {
7058
            $result[$format] = false;
7059
7060
            return false;
7061
        }
7062
    } elseif ($format == 'mp3') {
7063
        //native mp3 support (TODO:check Android, iPhone)
7064
        if (($current_browser == 'Safari' && $current_majorver >= 5) ||
7065
            ($current_browser == 'Chrome' && $current_majorver >= 6) ||
7066
            ($current_browser == 'Internet Explorer' && $current_majorver >= 9) ||
7067
            $current_browser == 'Android' ||
7068
            $current_browser == 'iPhone' ||
7069
            $current_browser == 'Firefox'
7070
        ) {
7071
            $result[$format] = true;
7072
7073
            return true;
7074
        } else {
7075
            $result[$format] = false;
7076
7077
            return false;
7078
        }
7079
    } elseif ($format == 'autocapitalize') {
7080
        // Help avoiding showing the autocapitalize option if the browser doesn't
7081
        // support it: this attribute is against the HTML5 standard
7082
        if ($current_browser == 'Safari' || $current_browser == 'iPhone') {
7083
            return true;
7084
        } else {
7085
            return false;
7086
        }
7087
    } elseif ($format == "check_browser") {
7088
        $array_check_browser = [$current_browser, $current_majorver];
7089
7090
        return $array_check_browser;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $array_check_browser returns the type array<integer,mixed|string> which is incompatible with the documented return type boolean.
Loading history...
7091
    } else {
7092
        $result[$format] = false;
7093
7094
        return false;
7095
    }
7096
}
7097
7098
/**
7099
 * This function checks if exist path and file browscap.ini
7100
 * In order for this to work, your browscap configuration setting in php.ini
7101
 * must point to the correct location of the browscap.ini file on your system
7102
 * http://php.net/manual/en/function.get-browser.php.
7103
 *
7104
 * @return bool
7105
 *
7106
 * @author Juan Carlos Raña Trabado
7107
 */
7108
function api_check_browscap()
7109
{
7110
    $setting = ini_get('browscap');
7111
    if ($setting) {
7112
        $browser = get_browser($_SERVER['HTTP_USER_AGENT'], true);
7113
        if (strpos($setting, 'browscap.ini') && !empty($browser)) {
7114
            return true;
7115
        }
7116
    }
7117
7118
    return false;
7119
}
7120
7121
/**
7122
 * Returns the <script> HTML tag.
7123
 */
7124
function api_get_js($file)
7125
{
7126
    return '<script type="text/javascript" src="'.api_get_path(WEB_LIBRARY_PATH).'javascript/'.$file.'"></script>'."\n";
7127
}
7128
7129
/**
7130
 * Returns the <script> HTML tag.
7131
 *
7132
 * @return string
7133
 */
7134
function api_get_asset($file)
7135
{
7136
    return '<script type="text/javascript" src="'.api_get_path(WEB_PUBLIC_PATH).'libs/'.$file.'"></script>'."\n";
7137
}
7138
7139
/**
7140
 * Returns the <script> HTML tag.
7141
 *
7142
 * @param string $file
7143
 * @param string $media
7144
 *
7145
 * @return string
7146
 */
7147
function api_get_css_asset($file, $media = 'screen')
7148
{
7149
    return '<link href="'.api_get_path(WEB_PUBLIC_PATH).'libs/'.$file.'" rel="stylesheet" media="'.$media.'" type="text/css" />'."\n";
7150
}
7151
7152
/**
7153
 * Returns the <link> HTML tag.
7154
 *
7155
 * @param string $file
7156
 * @param string $media
7157
 */
7158
function api_get_css($file, $media = 'screen')
7159
{
7160
    return '<link href="'.$file.'" rel="stylesheet" media="'.$media.'" type="text/css" />'."\n";
7161
}
7162
7163
function api_get_bootstrap_and_font_awesome($returnOnlyPath = false)
7164
{
7165
    $url = api_get_path(WEB_PUBLIC_PATH).'build/css/bootstrap.css';
7166
    if ($returnOnlyPath) {
7167
        return $url;
7168
    }
7169
7170
    return '<link href="'.$url.'" rel="stylesheet" type="text/css" />'."\n";
7171
}
7172
7173
/**
7174
 * Returns the js header to include the jquery library.
7175
 */
7176
function api_get_jquery_js()
7177
{
7178
    return api_get_asset('jquery/dist/jquery.min.js');
7179
}
7180
7181
/**
7182
 * Returns the jquery path.
7183
 *
7184
 * @return string
7185
 */
7186
function api_get_jquery_web_path()
7187
{
7188
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery/dist/jquery.min.js';
7189
}
7190
7191
/**
7192
 * @return string
7193
 */
7194
function api_get_jquery_ui_js_web_path()
7195
{
7196
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery-ui/jquery-ui.min.js';
7197
}
7198
7199
/**
7200
 * @return string
7201
 */
7202
function api_get_jquery_ui_css_web_path()
7203
{
7204
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery-ui/themes/smoothness/jquery-ui.min.css';
7205
}
7206
7207
/**
7208
 * Returns the jquery-ui library js headers.
7209
 *
7210
 * @param   bool    add the jqgrid library
7211
 *
7212
 * @return string html tags
7213
 */
7214
function api_get_jquery_ui_js($include_jqgrid = false)
7215
{
7216
    $libraries = [];
7217
    if ($include_jqgrid) {
7218
        $libraries[] = 'jqgrid';
7219
    }
7220
7221
    return api_get_jquery_libraries_js($libraries);
7222
}
7223
7224
function api_get_jqgrid_js()
7225
{
7226
    return api_get_jquery_libraries_js(['jqgrid']);
7227
}
7228
7229
/**
7230
 * Returns the jquery library js and css headers.
7231
 *
7232
 * @param   array   list of jquery libraries supported jquery-ui, jqgrid
7233
 * @param   bool    add the jquery library
7234
 *
7235
 * @return string html tags
7236
 */
7237
function api_get_jquery_libraries_js($libraries)
7238
{
7239
    $js = '';
7240
    $js_path = api_get_path(WEB_LIBRARY_PATH).'javascript/';
7241
7242
    //jqgrid js and css
7243
    if (in_array('jqgrid', $libraries)) {
7244
        $languaje = 'en';
7245
        $platform_isocode = strtolower(api_get_language_isocode());
7246
7247
        //languages supported by jqgrid see files in main/inc/lib/javascript/jqgrid/js/i18n
7248
        $jqgrid_langs = [
7249
            'bg', 'bg1251', 'cat', 'cn', 'cs', 'da', 'de', 'el', 'en', 'es', 'fa', 'fi', 'fr', 'gl', 'he', 'hu', 'is', 'it', 'ja', 'nl', 'no', 'pl', 'pt-br', 'pt', 'ro', 'ru', 'sk', 'sr', 'sv', 'tr', 'ua',
7250
        ];
7251
7252
        if (in_array($platform_isocode, $jqgrid_langs)) {
7253
            $languaje = $platform_isocode;
7254
        }
7255
        //$js .= '<link rel="stylesheet" href="'.$js_path.'jqgrid/css/ui.jqgrid.css" type="text/css">';
7256
        $js .= api_get_css($js_path.'jqgrid/css/ui.jqgrid.css');
7257
        $js .= api_get_js('jqgrid/js/i18n/grid.locale-'.$languaje.'.js');
7258
        $js .= api_get_js('jqgrid/js/jquery.jqGrid.min.js');
7259
    }
7260
7261
    //Document multiple upload funcionality
7262
    if (in_array('jquery-uploadzs', $libraries)) {
7263
        $js .= api_get_asset('blueimp-load-image/js/load-image.all.min.js');
7264
        $js .= api_get_asset('blueimp-canvas-to-blob/js/canvas-to-blob.min.js');
7265
        $js .= api_get_asset('jquery-file-upload/js/jquery.iframe-transport.js');
7266
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload.js');
7267
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-process.js');
7268
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-image.js');
7269
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-audio.js');
7270
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-video.js');
7271
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-validate.js');
7272
7273
        $js .= api_get_css(api_get_path(WEB_PUBLIC_PATH).'assets/jquery-file-upload/css/jquery.fileupload.css');
7274
        $js .= api_get_css(api_get_path(WEB_PUBLIC_PATH).'assets/jquery-file-upload/css/jquery.fileupload-ui.css');
7275
    }
7276
7277
    // jquery datepicker
7278
    if (in_array('datepicker', $libraries)) {
7279
        $languaje = 'en-GB';
7280
        $platform_isocode = strtolower(api_get_language_isocode());
7281
7282
        // languages supported by jqgrid see files in main/inc/lib/javascript/jqgrid/js/i18n
7283
        $datapicker_langs = [
7284
            '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',
7285
        ];
7286
        if (in_array($platform_isocode, $datapicker_langs)) {
7287
            $languaje = $platform_isocode;
7288
        }
7289
7290
        $js .= api_get_js('jquery-ui/jquery-ui-i18n.min.js');
7291
        $script = '<script>
7292
        $(function(){
7293
            $.datepicker.setDefaults($.datepicker.regional["'.$languaje.'"]);
7294
            $.datepicker.regional["local"] = $.datepicker.regional["'.$languaje.'"];
7295
        });
7296
        </script>
7297
        ';
7298
        $js .= $script;
7299
    }
7300
7301
    return $js;
7302
}
7303
7304
/**
7305
 * Returns the URL to the course or session, removing the complexity of the URL
7306
 * building piece by piece.
7307
 *
7308
 * This function relies on api_get_course_info()
7309
 *
7310
 * @param string $courseCode The course code - optional (takes it from context if not given)
7311
 * @param int    $sessionId  The session ID  - optional (takes it from context if not given)
7312
 * @param int    $groupId    The group ID - optional (takes it from context if not given)
7313
 *
7314
 * @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
7315
 *
7316
 * @author  Julio Montoya <[email protected]>
7317
 */
7318
function api_get_course_url($courseCode = null, $sessionId = null, $groupId = null)
7319
{
7320
    $courseDirectory = '';
7321
    $url = '';
7322
    // If courseCode not set, get context or []
7323
    if (empty($courseCode)) {
7324
        $courseInfo = api_get_course_info();
7325
    } else {
7326
        $courseInfo = api_get_course_info($courseCode);
7327
    }
7328
7329
    // If course defined, get directory, otherwise keep empty string
7330
    if (!empty($courseInfo['directory'])) {
7331
        $courseDirectory = $courseInfo['directory'];
7332
    }
7333
7334
    // If sessionId not set, get context or 0
7335
    if (empty($sessionId)) {
7336
        $sessionId = api_get_session_id();
7337
    }
7338
7339
    // If groupId not set, get context or 0
7340
    if (empty($groupId)) {
7341
        $groupId = api_get_group_id();
7342
    }
7343
7344
    // Build the URL
7345
    if (!empty($courseDirectory)) {
7346
        // directory not empty, so we do have a course
7347
        $url = api_get_path(WEB_COURSE_PATH).$courseDirectory.'/index.php?id_session='.$sessionId.'&gidReq='.$groupId;
7348
    } elseif (!empty($sessionId) &&
7349
        api_get_setting('session.remove_session_url') !== 'true'
7350
    ) {
7351
        // if the course was unset and the session was set, send directly to the session
7352
        $url = api_get_path(WEB_CODE_PATH).'session/index.php?session_id='.$sessionId;
7353
    }
7354
7355
    // if not valid combination was found, return an empty string
7356
    return $url;
7357
}
7358
7359
/**
7360
 * Check if the current portal has the $_configuration['multiple_access_urls'] parameter on.
7361
 *
7362
 * @return bool true if multi site is enabled
7363
 */
7364
function api_get_multiple_access_url()
7365
{
7366
    global $_configuration;
7367
    if (isset($_configuration['multiple_access_urls']) && $_configuration['multiple_access_urls']) {
7368
        return true;
7369
    }
7370
7371
    return false;
7372
}
7373
7374
/**
7375
 * @return bool
7376
 */
7377
function api_is_multiple_url_enabled()
7378
{
7379
    return api_get_multiple_access_url();
7380
}
7381
7382
/**
7383
 * Returns a md5 unique id.
7384
 *
7385
 * @todo add more parameters
7386
 */
7387
function api_get_unique_id()
7388
{
7389
    $id = md5(time().uniqid().api_get_user_id().api_get_course_id().api_get_session_id());
7390
7391
    return $id;
7392
}
7393
7394
/**
7395
 * Get home path.
7396
 *
7397
 * @return string
7398
 */
7399
function api_get_home_path()
7400
{
7401
    // FIX : Start the routing determination from central path definition
7402
    $home = api_get_path(SYS_HOME_PATH);
7403
    if (api_get_multiple_access_url()) {
7404
        $access_url_id = api_get_current_access_url_id();
7405
        $url_info = api_get_access_url($access_url_id);
7406
        $url = api_remove_trailing_slash(preg_replace('/https?:\/\//i', '', $url_info['url']));
7407
        $clean_url = api_replace_dangerous_char($url);
7408
        $clean_url = str_replace('/', '-', $clean_url);
7409
        $clean_url .= '/';
7410
        if ($clean_url != 'localhost/') {
7411
            // means that the multiple URL was not well configured we don't rename the $home variable
7412
            return "{$home}{$clean_url}";
7413
        }
7414
    }
7415
7416
    return $home;
7417
}
7418
7419
/**
7420
 * @param int Course id
7421
 * @param int tool id: TOOL_QUIZ, TOOL_FORUM, TOOL_STUDENTPUBLICATION, TOOL_LEARNPATH
7422
 * @param int the item id (tool id, exercise id, lp id)
7423
 *
7424
 * @return bool
7425
 */
7426
function api_resource_is_locked_by_gradebook($item_id, $link_type, $course_code = null)
7427
{
7428
    if (api_is_platform_admin()) {
7429
        return false;
7430
    }
7431
    if (api_get_setting('gradebook_locking_enabled') == 'true') {
7432
        if (empty($course_code)) {
7433
            $course_code = api_get_course_id();
7434
        }
7435
        $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_LINK);
7436
        $item_id = intval($item_id);
7437
        $link_type = intval($link_type);
7438
        $course_code = Database::escape_string($course_code);
7439
        $sql = "SELECT locked FROM $table
7440
                WHERE locked = 1 AND ref_id = $item_id AND type = $link_type AND course_code = '$course_code' ";
7441
        $result = Database::query($sql);
7442
        if (Database::num_rows($result)) {
7443
            return true;
7444
        }
7445
    }
7446
7447
    return false;
7448
}
7449
7450
/**
7451
 * Blocks a page if the item was added in a gradebook.
7452
 *
7453
 * @param int       exercise id, work id, thread id,
7454
 * @param int       LINK_EXERCISE, LINK_STUDENTPUBLICATION, LINK_LEARNPATH LINK_FORUM_THREAD, LINK_ATTENDANCE
7455
 * see gradebook/lib/be/linkfactory
7456
 * @param string    course code
7457
 *
7458
 * @return false|null
7459
 */
7460
function api_block_course_item_locked_by_gradebook($item_id, $link_type, $course_code = null)
7461
{
7462
    if (api_is_platform_admin()) {
7463
        return false;
7464
    }
7465
7466
    if (api_resource_is_locked_by_gradebook($item_id, $link_type, $course_code)) {
7467
        $message = Display::return_message(get_lang('ResourceLockedByGradebook'), 'warning');
7468
        api_not_allowed(true, $message);
7469
    }
7470
}
7471
7472
/**
7473
 * Checks the PHP version installed is enough to run Chamilo.
7474
 *
7475
 * @param string Include path (used to load the error page)
7476
 */
7477
function api_check_php_version($my_inc_path = null)
7478
{
7479
    if (!function_exists('version_compare') || version_compare(phpversion(), REQUIRED_PHP_VERSION, '<')) {
7480
        $global_error_code = 1;
7481
        // Incorrect PHP version
7482
        $global_page = $my_inc_path.'global_error_message.inc.php';
7483
        if (file_exists($global_page)) {
7484
            require $global_page;
7485
        }
7486
        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...
7487
    }
7488
}
7489
7490
/**
7491
 * Checks whether the Archive directory is present and writeable. If not,
7492
 * prints a warning message.
7493
 */
7494
function api_check_archive_dir()
7495
{
7496
    if (is_dir(api_get_path(SYS_ARCHIVE_PATH)) && !is_writable(api_get_path(SYS_ARCHIVE_PATH))) {
7497
        $message = Display::return_message(get_lang('ArchivesDirectoryNotWriteableContactAdmin'), 'warning');
7498
        api_not_allowed(true, $message);
7499
    }
7500
}
7501
7502
/**
7503
 * Returns an array of global configuration settings which should be ignored
7504
 * when printing the configuration settings screens.
7505
 *
7506
 * @return array Array of strings, each identifying one of the excluded settings
7507
 */
7508
function api_get_locked_settings()
7509
{
7510
    return [
7511
        'permanently_remove_deleted_files',
7512
        'account_valid_duration',
7513
        'service_ppt2lp',
7514
        'wcag_anysurfer_public_pages',
7515
        'upload_extensions_list_type',
7516
        'upload_extensions_blacklist',
7517
        'upload_extensions_whitelist',
7518
        'upload_extensions_skip',
7519
        'upload_extensions_replace_by',
7520
        'hide_dltt_markup',
7521
        'split_users_upload_directory',
7522
        'permissions_for_new_directories',
7523
        'permissions_for_new_files',
7524
        'platform_charset',
7525
        'ldap_description',
7526
        'cas_activate',
7527
        'cas_server',
7528
        'cas_server_uri',
7529
        'cas_port',
7530
        'cas_protocol',
7531
        'cas_add_user_activate',
7532
        'update_user_info_cas_with_ldap',
7533
        'languagePriority1',
7534
        'languagePriority2',
7535
        'languagePriority3',
7536
        'languagePriority4',
7537
        'login_is_email',
7538
        'chamilo_database_version',
7539
    ];
7540
}
7541
7542
/**
7543
 * Checks if the user is corrently logged in. Returns the user ID if he is, or
7544
 * false if he isn't. If the user ID is given and is an integer, then the same
7545
 * ID is simply returned.
7546
 *
7547
 * @param  int User ID
7548
 *
7549
 * @return bool Integer User ID is logged in, or false otherwise
7550
 */
7551
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

7551
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...
7552
{
7553
    return Container::getAuthorizationChecker()->isGranted('IS_AUTHENTICATED_FULLY');
7554
}
7555
7556
/**
7557
 * Guess the real ip for register in the database, even in reverse proxy cases.
7558
 * To be recognized, the IP has to be found in either $_SERVER['REMOTE_ADDR'] or
7559
 * in $_SERVER['HTTP_X_FORWARDED_FOR'], which is in common use with rproxies.
7560
 * Note: the result of this function is not SQL-safe. Please escape it before
7561
 * inserting in a database.
7562
 *
7563
 * @return string the user's real ip (unsafe - escape it before inserting to db)
7564
 *
7565
 * @author Jorge Frisancho Jibaja <[email protected]>, USIL - Some changes to allow the use of real IP using reverse proxy
7566
 *
7567
 * @version CEV CHANGE 24APR2012
7568
 */
7569
function api_get_real_ip()
7570
{
7571
    // Guess the IP if behind a reverse proxy
7572
    global $debug;
7573
    $ip = trim($_SERVER['REMOTE_ADDR']);
7574
    if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
7575
        if (preg_match('/,/', $_SERVER['HTTP_X_FORWARDED_FOR'])) {
7576
            @list($ip1, $ip2) = @explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
7577
        } else {
7578
            $ip1 = $_SERVER['HTTP_X_FORWARDED_FOR'];
7579
        }
7580
        $ip = trim($ip1);
7581
    }
7582
    if (!empty($debug)) {
7583
        error_log('Real IP: '.$ip);
7584
    }
7585
7586
    return $ip;
7587
}
7588
7589
/**
7590
 * Checks whether an IP is included inside an IP range.
7591
 *
7592
 * @param string IP address
7593
 * @param string IP range
7594
 * @param string $ip
7595
 *
7596
 * @return bool True if IP is in the range, false otherwise
7597
 *
7598
 * @author claudiu at cnixs dot com  on http://www.php.net/manual/fr/ref.network.php#55230
7599
 * @author Yannick Warnier for improvements and managment of multiple ranges
7600
 *
7601
 * @todo check for IPv6 support
7602
 */
7603
function api_check_ip_in_range($ip, $range)
7604
{
7605
    if (empty($ip) or empty($range)) {
7606
        return false;
7607
    }
7608
    $ip_ip = ip2long($ip);
7609
    // divide range param into array of elements
7610
    if (strpos($range, ',') !== false) {
7611
        $ranges = explode(',', $range);
7612
    } else {
7613
        $ranges = [$range];
7614
    }
7615
    foreach ($ranges as $range) {
0 ignored issues
show
introduced by
$range is overwriting one of the parameters of this function.
Loading history...
7616
        $range = trim($range);
7617
        if (empty($range)) {
7618
            continue;
7619
        }
7620
        if (strpos($range, '/') === false) {
7621
            if (strcmp($ip, $range) === 0) {
7622
                return true; // there is a direct IP match, return OK
7623
            }
7624
            continue; //otherwise, get to the next range
7625
        }
7626
        // the range contains a "/", so analyse completely
7627
        list($net, $mask) = explode("/", $range);
7628
7629
        $ip_net = ip2long($net);
7630
        // mask binary magic
7631
        $ip_mask = ~((1 << (32 - $mask)) - 1);
7632
7633
        $ip_ip_net = $ip_ip & $ip_mask;
7634
        if ($ip_ip_net == $ip_net) {
7635
            return true;
7636
        }
7637
    }
7638
7639
    return false;
7640
}
7641
7642
function api_check_user_access_to_legal($course_visibility)
7643
{
7644
    $course_visibility_list = [COURSE_VISIBILITY_OPEN_WORLD, COURSE_VISIBILITY_OPEN_PLATFORM];
7645
7646
    return in_array($course_visibility, $course_visibility_list) || api_is_drh();
7647
}
7648
7649
/**
7650
 * Checks if the global chat is enabled or not.
7651
 *
7652
 * @return bool
7653
 */
7654
function api_is_global_chat_enabled()
7655
{
7656
    return
7657
        !api_is_anonymous() &&
7658
        api_get_setting('allow_global_chat') === 'true' &&
7659
        api_get_setting('allow_social_tool') === 'true';
7660
}
7661
7662
/**
7663
 * @todo Fix tool_visible_by_default_at_creation labels
7664
 * @todo Add sessionId parameter to avoid using context
7665
 *
7666
 * @param int   $item_id
7667
 * @param int   $tool_id
7668
 * @param int   $group_id   id
7669
 * @param array $courseInfo
7670
 * @param int   $sessionId
7671
 * @param int   $userId
7672
 */
7673
function api_set_default_visibility(
7674
    $item_id,
7675
    $tool_id,
7676
    $group_id = 0,
7677
    $courseInfo = [],
7678
    $sessionId = 0,
7679
    $userId = 0
7680
) {
7681
    $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
7682
    $courseId = $courseInfo['real_id'];
7683
    $courseCode = $courseInfo['code'];
7684
    $sessionId = empty($sessionId) ? api_get_session_id() : $sessionId;
7685
    $userId = empty($userId) ? api_get_user_id() : $userId;
7686
7687
    // if group is null force group_id = 0, this force is needed to create a LP folder with group = 0
7688
    if (is_null($group_id)) {
7689
        $group_id = 0;
7690
    } else {
7691
        $group_id = empty($group_id) ? api_get_group_id() : $group_id;
7692
    }
7693
7694
    $groupInfo = [];
7695
    if (!empty($group_id)) {
7696
        $groupInfo = GroupManager::get_group_properties($group_id);
7697
    }
7698
    $original_tool_id = $tool_id;
7699
7700
    switch ($tool_id) {
7701
        case TOOL_LINK:
7702
        case TOOL_LINK_CATEGORY:
7703
            $tool_id = 'links';
7704
            break;
7705
        case TOOL_DOCUMENT:
7706
            $tool_id = 'documents';
7707
            break;
7708
        case TOOL_LEARNPATH:
7709
            $tool_id = 'learning';
7710
            break;
7711
        case TOOL_ANNOUNCEMENT:
7712
            $tool_id = 'announcements';
7713
            break;
7714
        case TOOL_FORUM:
7715
        case TOOL_FORUM_CATEGORY:
7716
        case TOOL_FORUM_THREAD:
7717
            $tool_id = 'forums';
7718
            break;
7719
        case TOOL_QUIZ:
7720
            $tool_id = 'quiz';
7721
            break;
7722
    }
7723
    $setting = api_get_setting('tool_visible_by_default_at_creation');
7724
7725
    if (isset($setting[$tool_id])) {
7726
        $visibility = 'invisible';
7727
        if ($setting[$tool_id] == 'true') {
7728
            $visibility = 'visible';
7729
        }
7730
7731
        // Read the portal and course default visibility
7732
        if ($tool_id == 'documents') {
7733
            $visibility = DocumentManager::getDocumentDefaultVisibility($courseCode);
7734
        }
7735
7736
        api_item_property_update(
7737
            $courseInfo,
7738
            $original_tool_id,
7739
            $item_id,
7740
            $visibility,
7741
            $userId,
7742
            $groupInfo,
7743
            null,
7744
            null,
7745
            null,
7746
            $sessionId
7747
        );
7748
7749
        // Fixes default visibility for tests
7750
        switch ($original_tool_id) {
7751
            case TOOL_QUIZ:
7752
                if (empty($sessionId)) {
7753
                    $objExerciseTmp = new Exercise($courseId);
7754
                    $objExerciseTmp->read($item_id);
7755
                    if ($visibility == 'visible') {
7756
                        $objExerciseTmp->enable();
7757
                        $objExerciseTmp->save();
7758
                    } else {
7759
                        $objExerciseTmp->disable();
7760
                        $objExerciseTmp->save();
7761
                    }
7762
                }
7763
                break;
7764
        }
7765
    }
7766
}
7767
7768
/**
7769
 * @return string
7770
 */
7771
function api_get_security_key()
7772
{
7773
    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...
7774
}
7775
7776
/**
7777
 * @param int $user_id
7778
 * @param int $courseId
7779
 * @param int $session_id
7780
 *
7781
 * @return array
7782
 */
7783
function api_detect_user_roles($user_id, $courseId, $session_id = 0)
7784
{
7785
    $user_roles = [];
7786
    $courseInfo = api_get_course_info_by_id($courseId);
7787
    $course_code = $courseInfo['code'];
7788
7789
    $url_id = api_get_current_access_url_id();
7790
    if (api_is_platform_admin_by_id($user_id, $url_id)) {
7791
        $user_roles[] = PLATFORM_ADMIN;
7792
    }
7793
7794
    /*if (api_is_drh()) {
7795
        $user_roles[] = DRH;
7796
    }*/
7797
7798
    if (!empty($session_id)) {
7799
        if (SessionManager::user_is_general_coach($user_id, $session_id)) {
7800
            $user_roles[] = SESSION_GENERAL_COACH;
7801
        }
7802
    }
7803
7804
    if (!empty($course_code)) {
7805
        if (empty($session_id)) {
7806
            if (CourseManager::is_course_teacher($user_id, $course_code)) {
7807
                $user_roles[] = COURSEMANAGER;
7808
            }
7809
            if (CourseManager::get_tutor_in_course_status($user_id, $courseInfo['real_id'])) {
7810
                $user_roles[] = COURSE_TUTOR;
7811
            }
7812
7813
            if (CourseManager::is_user_subscribed_in_course($user_id, $course_code)) {
7814
                $user_roles[] = COURSE_STUDENT;
7815
            }
7816
        } else {
7817
            $user_status_in_session = SessionManager::get_user_status_in_course_session(
7818
                $user_id,
7819
                $courseId,
7820
                $session_id
7821
            );
7822
7823
            if (!empty($user_status_in_session)) {
7824
                if ($user_status_in_session == 0) {
7825
                    $user_roles[] = SESSION_STUDENT;
7826
                }
7827
                if ($user_status_in_session == 2) {
7828
                    $user_roles[] = SESSION_COURSE_COACH;
7829
                }
7830
            }
7831
7832
            /*if (api_is_course_session_coach($user_id, $course_code, $session_id)) {
7833
               $user_roles[] = SESSION_COURSE_COACH;
7834
            }*/
7835
        }
7836
    }
7837
7838
    return $user_roles;
7839
}
7840
7841
/**
7842
 * @param int $courseId
7843
 * @param int $session_id
7844
 *
7845
 * @return bool
7846
 */
7847
function api_coach_can_edit_view_results($courseId = null, $session_id = null)
7848
{
7849
    if (api_is_platform_admin()) {
7850
        return true;
7851
    }
7852
7853
    $user_id = api_get_user_id();
7854
7855
    if (empty($courseId)) {
7856
        $courseId = api_get_course_int_id();
7857
    }
7858
7859
    if (empty($session_id)) {
7860
        $session_id = api_get_session_id();
7861
    }
7862
7863
    $roles = api_detect_user_roles($user_id, $courseId, $session_id);
7864
7865
    if (in_array(SESSION_COURSE_COACH, $roles)) {
7866
        //return api_get_setting('session_tutor_reports_visibility') == 'true';
7867
        return true;
7868
    } else {
7869
        if (in_array(COURSEMANAGER, $roles)) {
7870
            return true;
7871
        }
7872
7873
        return false;
7874
    }
7875
}
7876
7877
/**
7878
 * @param string $file
7879
 *
7880
 * @return string
7881
 */
7882
function api_get_js_simple($file)
7883
{
7884
    return '<script type="text/javascript" src="'.$file.'"></script>'."\n";
7885
}
7886
7887
function api_set_settings_and_plugins()
7888
{
7889
    global $_configuration;
7890
    $_setting = [];
7891
    $_plugins = [];
7892
7893
    // access_url == 1 is the default chamilo location
7894
    $settings_by_access_list = [];
7895
    $access_url_id = api_get_current_access_url_id();
7896
    if ($access_url_id != 1) {
7897
        $url_info = api_get_access_url($_configuration['access_url']);
7898
        if ($url_info['active'] == 1) {
7899
            $settings_by_access = &api_get_settings(null, 'list', $_configuration['access_url'], 1);
7900
            foreach ($settings_by_access as &$row) {
7901
                if (empty($row['variable'])) {
7902
                    $row['variable'] = 0;
7903
                }
7904
                if (empty($row['subkey'])) {
7905
                    $row['subkey'] = 0;
7906
                }
7907
                if (empty($row['category'])) {
7908
                    $row['category'] = 0;
7909
                }
7910
                $settings_by_access_list[$row['variable']][$row['subkey']][$row['category']] = $row;
7911
            }
7912
        }
7913
    }
7914
7915
    $result = api_get_settings(null, 'list', 1);
7916
7917
    foreach ($result as &$row) {
7918
        if ($access_url_id != 1) {
7919
            if ($url_info['active'] == 1) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $url_info does not seem to be defined for all execution paths leading up to this point.
Loading history...
7920
                $var = empty($row['variable']) ? 0 : $row['variable'];
7921
                $subkey = empty($row['subkey']) ? 0 : $row['subkey'];
7922
                $category = empty($row['category']) ? 0 : $row['category'];
7923
            }
7924
7925
            if ($row['access_url_changeable'] == 1 && $url_info['active'] == 1) {
7926
                if (isset($settings_by_access_list[$var]) &&
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $var does not seem to be defined for all execution paths leading up to this point.
Loading history...
7927
                    $settings_by_access_list[$var][$subkey][$category]['selected_value'] != '') {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $subkey does not seem to be defined for all execution paths leading up to this point.
Loading history...
Comprehensibility Best Practice introduced by
The variable $category does not seem to be defined for all execution paths leading up to this point.
Loading history...
7928
                    if ($row['subkey'] == null) {
7929
                        $_setting[$row['variable']] = $settings_by_access_list[$var][$subkey][$category]['selected_value'];
7930
                    } else {
7931
                        $_setting[$row['variable']][$row['subkey']] = $settings_by_access_list[$var][$subkey][$category]['selected_value'];
7932
                    }
7933
                } else {
7934
                    if ($row['subkey'] == null) {
7935
                        $_setting[$row['variable']] = $row['selected_value'];
7936
                    } else {
7937
                        $_setting[$row['variable']][$row['subkey']] = $row['selected_value'];
7938
                    }
7939
                }
7940
            } else {
7941
                if ($row['subkey'] == null) {
7942
                    $_setting[$row['variable']] = $row['selected_value'];
7943
                } else {
7944
                    $_setting[$row['variable']][$row['subkey']] = $row['selected_value'];
7945
                }
7946
            }
7947
        } else {
7948
            if ($row['subkey'] == null) {
7949
                $_setting[$row['variable']] = $row['selected_value'];
7950
            } else {
7951
                $_setting[$row['variable']][$row['subkey']] = $row['selected_value'];
7952
            }
7953
        }
7954
    }
7955
7956
    $result = api_get_settings('Plugins', 'list', $access_url_id);
7957
    $_plugins = [];
7958
    foreach ($result as &$row) {
7959
        $key = &$row['variable'];
7960
        if (is_string($_setting[$key])) {
7961
            $_setting[$key] = [];
7962
        }
7963
        $_setting[$key][] = $row['selected_value'];
7964
        $_plugins[$key][] = $row['selected_value'];
7965
    }
7966
7967
    $_SESSION['_setting'] = $_setting;
7968
    $_SESSION['_plugins'] = $_plugins;
7969
}
7970
7971
/**
7972
 * Modify default memory_limit and max_execution_time limits
7973
 * Needed when processing long tasks.
7974
 */
7975
function api_set_more_memory_and_time_limits()
7976
{
7977
    if (function_exists('ini_set')) {
7978
        api_set_memory_limit('256M');
7979
        ini_set('max_execution_time', 1800);
7980
    }
7981
}
7982
7983
/**
7984
 * Tries to set memory limit, if authorized and new limit is higher than current.
7985
 *
7986
 * @param string $mem New memory limit
7987
 *
7988
 * @return bool True on success, false on failure or current is higher than suggested
7989
 * @assert (null) === false
7990
 * @assert (-1) === false
7991
 * @assert (0) === true
7992
 * @assert ('1G') === true
7993
 */
7994
function api_set_memory_limit($mem)
7995
{
7996
    //if ini_set() not available, this function is useless
7997
    if (!function_exists('ini_set') || is_null($mem) || $mem == -1) {
7998
        return false;
7999
    }
8000
8001
    $memory_limit = ini_get('memory_limit');
8002
    if (api_get_bytes_memory_limit($mem) > api_get_bytes_memory_limit($memory_limit)) {
8003
        ini_set('memory_limit', $mem);
8004
8005
        return true;
8006
    }
8007
8008
    return false;
8009
}
8010
8011
/**
8012
 * Gets memory limit in bytes.
8013
 *
8014
 * @param string The memory size (128M, 1G, 1000K, etc)
8015
 *
8016
 * @return int
8017
 * @assert (null) === false
8018
 * @assert ('1t')  === 1099511627776
8019
 * @assert ('1g')  === 1073741824
8020
 * @assert ('1m')  === 1048576
8021
 * @assert ('100k') === 102400
8022
 */
8023
function api_get_bytes_memory_limit($mem)
8024
{
8025
    $size = strtolower(substr($mem, -1));
8026
8027
    switch ($size) {
8028
        case 't':
8029
            $mem = intval(substr($mem, -1)) * 1024 * 1024 * 1024 * 1024;
8030
            break;
8031
        case 'g':
8032
            $mem = intval(substr($mem, 0, -1)) * 1024 * 1024 * 1024;
8033
            break;
8034
        case 'm':
8035
            $mem = intval(substr($mem, 0, -1)) * 1024 * 1024;
8036
            break;
8037
        case 'k':
8038
            $mem = intval(substr($mem, 0, -1)) * 1024;
8039
            break;
8040
        default:
8041
            // we assume it's integer only
8042
            $mem = intval($mem);
8043
            break;
8044
    }
8045
8046
    return $mem;
8047
}
8048
8049
/**
8050
 * Finds all the information about a user from username instead of user id.
8051
 *
8052
 * @param string $officialCode
8053
 *
8054
 * @return array $user_info user_id, lastname, firstname, username, email, ...
8055
 *
8056
 * @author Yannick Warnier <[email protected]>
8057
 */
8058
function api_get_user_info_from_official_code($officialCode)
8059
{
8060
    if (empty($officialCode)) {
8061
        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...
8062
    }
8063
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
8064
            WHERE official_code ='".Database::escape_string($officialCode)."'";
8065
    $result = Database::query($sql);
8066
    if (Database::num_rows($result) > 0) {
8067
        $result_array = Database::fetch_array($result);
8068
8069
        return _api_format_user($result_array);
8070
    }
8071
8072
    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...
8073
}
8074
8075
/**
8076
 * @param string $usernameInputId
8077
 * @param string $passwordInputId
8078
 *
8079
 * @return null|string
8080
 */
8081
function api_get_password_checker_js($usernameInputId, $passwordInputId)
8082
{
8083
    $checkPass = api_get_setting('allow_strength_pass_checker');
8084
    $useStrengthPassChecker = $checkPass === 'true';
8085
8086
    if ($useStrengthPassChecker === false) {
8087
        return null;
8088
    }
8089
8090
    $translations = [
8091
        'wordLength' => get_lang('PasswordIsTooShort'),
8092
        'wordNotEmail' => get_lang('YourPasswordCannotBeTheSameAsYourEmail'),
8093
        'wordSimilarToUsername' => get_lang('YourPasswordCannotContainYourUsername'),
8094
        'wordTwoCharacterClasses' => get_lang('WordTwoCharacterClasses'),
8095
        'wordRepetitions' => get_lang('TooManyRepetitions'),
8096
        'wordSequences' => get_lang('YourPasswordContainsSequences'),
8097
        'errorList' => get_lang('ErrorsFound'),
8098
        'veryWeak' => get_lang('PasswordVeryWeak'),
8099
        'weak' => get_lang('PasswordWeak'),
8100
        'normal' => get_lang('PasswordNormal'),
8101
        'medium' => get_lang('PasswordMedium'),
8102
        'strong' => get_lang('PasswordStrong'),
8103
        'veryStrong' => get_lang('PasswordVeryStrong'),
8104
    ];
8105
8106
    $js = api_get_asset('pwstrength-bootstrap/dist/pwstrength-bootstrap.min.js');
8107
    $js .= "<script>    
8108
    var errorMessages = {
8109
        password_to_short : \"".get_lang('PasswordIsTooShort')."\",
8110
        same_as_username : \"".get_lang('YourPasswordCannotBeTheSameAsYourUsername')."\"
8111
    };
8112
8113
    $(document).ready(function() {
8114
        var lang = ".json_encode($translations).";     
8115
        var options = {        
8116
            onLoad : function () {
8117
                //$('#messages').text('Start typing password');
8118
            },
8119
            onKeyUp: function (evt) {
8120
                $(evt.target).pwstrength('outputErrorList');
8121
            },
8122
            errorMessages : errorMessages,
8123
            viewports: {
8124
                progress: '#password_progress',
8125
                verdict: '#password-verdict',
8126
                errors: '#password-errors'
8127
            },
8128
            usernameField: '$usernameInputId'
8129
        };
8130
        options.i18n = {
8131
            t: function (key) {
8132
                var result = lang[key];
8133
                return result === key ? '' : result; // This assumes you return the                
8134
            }
8135
        };
8136
        $('".$passwordInputId."').pwstrength(options);
8137
    });
8138
    </script>";
8139
8140
    return $js;
8141
}
8142
8143
/**
8144
 * create an user extra field called 'captcha_blocked_until_date'.
8145
 *
8146
 * @param string $username
8147
 *
8148
 * @return bool
8149
 */
8150
function api_block_account_captcha($username)
8151
{
8152
    $userInfo = api_get_user_info_from_username($username);
8153
    if (empty($userInfo)) {
8154
        return false;
8155
    }
8156
    $minutesToBlock = api_get_setting('captcha_time_to_block');
8157
    $time = time() + $minutesToBlock * 60;
8158
    UserManager::update_extra_field_value(
8159
        $userInfo['user_id'],
8160
        'captcha_blocked_until_date',
8161
        api_get_utc_datetime($time)
8162
    );
8163
8164
    return true;
8165
}
8166
8167
/**
8168
 * @param string $username
8169
 *
8170
 * @return bool
8171
 */
8172
function api_clean_account_captcha($username)
8173
{
8174
    $userInfo = api_get_user_info_from_username($username);
8175
    if (empty($userInfo)) {
8176
        return false;
8177
    }
8178
    Session::erase('loginFailedCount');
8179
    UserManager::update_extra_field_value(
8180
        $userInfo['user_id'],
8181
        'captcha_blocked_until_date',
8182
        null
8183
    );
8184
8185
    return true;
8186
}
8187
8188
/**
8189
 * @param string $username
8190
 *
8191
 * @return bool
8192
 */
8193
function api_get_user_blocked_by_captcha($username)
8194
{
8195
    $userInfo = api_get_user_info_from_username($username);
8196
    if (empty($userInfo)) {
8197
        return false;
8198
    }
8199
    $data = UserManager::get_extra_user_data_by_field(
8200
        $userInfo['user_id'],
8201
        'captcha_blocked_until_date'
8202
    );
8203
    if (isset($data) && isset($data['captcha_blocked_until_date'])) {
8204
        return $data['captcha_blocked_until_date'];
8205
    }
8206
8207
    return false;
8208
}
8209
8210
/**
8211
 * Remove tags from HTML anf return the $in_number_char first non-HTML char
8212
 * Postfix the text with "..." if it has been truncated.
8213
 *
8214
 * @param string $text
8215
 * @param int    $number
8216
 *
8217
 * @return string
8218
 *
8219
 * @author hubert borderiou
8220
 */
8221
function api_get_short_text_from_html($text, $number)
8222
{
8223
    // Delete script and style tags
8224
    $text = preg_replace('/(<(script|style)\b[^>]*>).*?(<\/\2>)/is', "$1$3", $text);
8225
    $text = api_html_entity_decode($text);
8226
    $out_res = api_remove_tags_with_space($text, false);
8227
    $postfix = "...";
8228
    if (strlen($out_res) > $number) {
8229
        $out_res = substr($out_res, 0, $number).$postfix;
8230
    }
8231
8232
    return $out_res;
8233
}
8234
8235
/**
8236
 * Replace tags with a space in a text.
8237
 * If $in_double_quote_replace, replace " with '' (for HTML attribute purpose, for exemple).
8238
 *
8239
 * @return string
8240
 *
8241
 * @author hubert borderiou
8242
 */
8243
function api_remove_tags_with_space($in_html, $in_double_quote_replace = true)
8244
{
8245
    $out_res = $in_html;
8246
    if ($in_double_quote_replace) {
8247
        $out_res = str_replace('"', "''", $out_res);
8248
    }
8249
    // avoid text stuck together when tags are removed, adding a space after >
8250
    $out_res = str_replace(">", "> ", $out_res);
8251
    $out_res = strip_tags($out_res);
8252
8253
    return $out_res;
8254
}
8255
8256
/**
8257
 * If true, the drh can access all content (courses, users) inside a session.
8258
 *
8259
 * @return bool
8260
 */
8261
function api_drh_can_access_all_session_content()
8262
{
8263
    $value = api_get_setting('drh_can_access_all_session_content');
8264
8265
    return $value === 'true';
8266
}
8267
8268
/**
8269
 * @param string $tool
8270
 * @param string $setting
8271
 * @param int    $defaultValue
8272
 *
8273
 * @return string
8274
 */
8275
function api_get_default_tool_setting($tool, $setting, $defaultValue)
8276
{
8277
    global $_configuration;
8278
    if (isset($_configuration[$tool]) &&
8279
        isset($_configuration[$tool]['default_settings']) &&
8280
        isset($_configuration[$tool]['default_settings'][$setting])
8281
    ) {
8282
        return $_configuration[$tool]['default_settings'][$setting];
8283
    }
8284
8285
    return $defaultValue;
8286
}
8287
8288
/**
8289
 * Checks if user can login as another user.
8290
 *
8291
 * @param int $loginAsUserId the user id to log in
8292
 * @param int $userId        my user id
8293
 *
8294
 * @return bool
8295
 */
8296
function api_can_login_as($loginAsUserId, $userId = null)
8297
{
8298
    if (empty($userId)) {
8299
        $userId = api_get_user_id();
8300
    }
8301
    if ($loginAsUserId == $userId) {
8302
        return false;
8303
    }
8304
8305
    if (empty($loginAsUserId)) {
8306
        return false;
8307
    }
8308
8309
    if ($loginAsUserId != strval(intval($loginAsUserId))) {
8310
        return false;
8311
    }
8312
8313
    // Check if the user to login is an admin
8314
    if (api_is_platform_admin_by_id($loginAsUserId)) {
8315
        // Only super admins can login to admin accounts
8316
        if (!api_global_admin_can_edit_admin($loginAsUserId)) {
8317
            return false;
8318
        }
8319
    }
8320
8321
    $userInfo = api_get_user_info($userId);
8322
    $isDrh = function () use ($loginAsUserId) {
8323
        if (api_is_drh()) {
8324
            if (api_drh_can_access_all_session_content()) {
8325
                $users = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus(
8326
                    'drh_all',
8327
                    api_get_user_id()
8328
                );
8329
                $userList = [];
8330
                if (is_array($users)) {
8331
                    foreach ($users as $user) {
8332
                        $userList[] = $user['user_id'];
8333
                    }
8334
                }
8335
                if (in_array($loginAsUserId, $userList)) {
8336
                    return true;
8337
                }
8338
            } else {
8339
                if (api_is_drh() &&
8340
                    UserManager::is_user_followed_by_drh($loginAsUserId, api_get_user_id())
8341
                ) {
8342
                    return true;
8343
                }
8344
            }
8345
        }
8346
8347
        return false;
8348
    };
8349
8350
    return api_is_platform_admin() || (api_is_session_admin() && $userInfo['status'] == 5) || $isDrh();
8351
}
8352
8353
/**
8354
 * @return bool
8355
 */
8356
function api_is_allowed_in_course()
8357
{
8358
    if (api_is_platform_admin()) {
8359
        return true;
8360
    }
8361
8362
    $user = api_get_current_user();
8363
    if ($user) {
8364
        if ($user->hasRole('ROLE_CURRENT_SESSION_COURSE_STUDENT') ||
8365
            $user->hasRole('ROLE_CURRENT_SESSION_COURSE_TEACHER') ||
8366
            $user->hasRole('ROLE_CURRENT_COURSE_STUDENT') ||
8367
            $user->hasRole('ROLE_CURRENT_COURSE_TEACHER')
8368
        ) {
8369
            return true;
8370
        }
8371
    }
8372
8373
    return false;
8374
8375
8376
    return Session::read('is_allowed_in_course');
0 ignored issues
show
Unused Code introduced by
return ChamiloSession::r...'is_allowed_in_course') 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...
8377
}
8378
8379
/**
8380
 * Set the cookie to go directly to the course code $in_firstpage
8381
 * after login.
8382
 *
8383
 * @param string $in_firstpage is the course code of the course to go
8384
 */
8385
function api_set_firstpage_parameter($in_firstpage)
0 ignored issues
show
Unused Code introduced by
The parameter $in_firstpage 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

8385
function api_set_firstpage_parameter(/** @scrutinizer ignore-unused */ $in_firstpage)

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...
8386
{
8387
    //setcookie('GotoCourse', $in_firstpage);
8388
}
8389
8390
/**
8391
 * Delete the cookie to go directly to the course code $in_firstpage
8392
 * after login.
8393
 */
8394
function api_delete_firstpage_parameter()
8395
{
8396
    setcookie('GotoCourse', '', time() - 3600);
8397
}
8398
8399
/**
8400
 * @return bool if course_code for direct course access after login is set
8401
 */
8402
function exist_firstpage_parameter()
8403
{
8404
    return isset($_COOKIE['GotoCourse']) && $_COOKIE['GotoCourse'] != '';
8405
}
8406
8407
/**
8408
 * @return return the course_code of the course where user login
8409
 */
8410
function api_get_firstpage_parameter()
8411
{
8412
    return $_COOKIE['GotoCourse'];
8413
}
8414
8415
/**
8416
 * Return true on https install.
8417
 *
8418
 * @return bool
8419
 */
8420
function api_is_https()
8421
{
8422
    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...
8423
        $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https' || !empty($_configuration['force_https_forwarded_proto'])
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $_configuration seems to never exist and therefore empty should always be true.
Loading history...
8424
    ) {
8425
        $isSecured = true;
8426
    } else {
8427
        if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') {
8428
            $isSecured = true;
8429
        } else {
8430
            $isSecured = false;
8431
            // last chance
8432
            if (!empty($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443) {
8433
                $isSecured = true;
8434
            }
8435
        }
8436
    }
8437
8438
    return $isSecured;
8439
}
8440
8441
/**
8442
 * Return protocol (http or https).
8443
 *
8444
 * @return string
8445
 */
8446
function api_get_protocol()
8447
{
8448
    return api_is_https() ? 'https' : 'http';
8449
}
8450
8451
/**
8452
 * Return a string where " are replaced with 2 '
8453
 * It is useful when you pass a PHP variable in a Javascript browser dialog
8454
 * e.g. : alert("<?php get_lang('Message') ?>");
8455
 * and message contains character ".
8456
 *
8457
 * @param string $in_text
8458
 *
8459
 * @return string
8460
 */
8461
function convert_double_quote_to_single($in_text)
8462
{
8463
    return api_preg_replace('/"/', "''", $in_text);
8464
}
8465
8466
/**
8467
 * Get origin.
8468
 *
8469
 * @param string
8470
 *
8471
 * @return string
8472
 */
8473
function api_get_origin()
8474
{
8475
    $origin = isset($_REQUEST['origin']) ? Security::remove_XSS($_REQUEST['origin']) : '';
8476
8477
    return $origin;
8478
}
8479
8480
/**
8481
 * Warns an user that the portal reach certain limit.
8482
 *
8483
 * @param string $limitName
8484
 */
8485
function api_warn_hosting_contact($limitName)
8486
{
8487
    $hostingParams = api_get_configuration_value(1);
8488
    $email = null;
8489
8490
    if (!empty($hostingParams)) {
8491
        if (isset($hostingParams['hosting_contact_mail'])) {
8492
            $email = $hostingParams['hosting_contact_mail'];
8493
        }
8494
    }
8495
8496
    if (!empty($email)) {
8497
        $subject = get_lang('HostingWarningReached');
8498
        $body = get_lang('PortalName').': '.api_get_path(WEB_PATH)." \n ";
8499
        $body .= get_lang('PortalLimitType').': '.$limitName." \n ";
8500
        if (isset($hostingParams[$limitName])) {
8501
            $body .= get_lang('Value').': '.$hostingParams[$limitName];
8502
        }
8503
        api_mail_html(null, $email, $subject, $body);
8504
    }
8505
}
8506
8507
/**
8508
 * Gets value of a variable from app/config/configuration.php
8509
 * Variables that are not set in the configuration.php file but set elsewhere:
8510
 * - virtual_css_theme_folder (vchamilo plugin)
8511
 * - access_url (global.inc.php)
8512
 * - apc/apc_prefix (global.inc.php).
8513
 *
8514
 * @param string $variable
8515
 *
8516
 * @return bool|mixed
8517
 */
8518
function api_get_configuration_value($variable)
8519
{
8520
    global $_configuration;
8521
    // Check the current url id, id = 1 by default
8522
    $urlId = isset($_configuration['access_url']) ? (int) $_configuration['access_url'] : 1;
8523
8524
    $variable = trim($variable);
8525
8526
    // Check if variable exists
8527
    if (isset($_configuration[$variable])) {
8528
        if (is_array($_configuration[$variable])) {
8529
            // Check if it exists for the sub portal
8530
            if (array_key_exists($urlId, $_configuration[$variable])) {
8531
                return $_configuration[$variable][$urlId];
8532
            } else {
8533
                // Try to found element with id = 1 (master portal)
8534
                if (array_key_exists(1, $_configuration[$variable])) {
8535
                    return $_configuration[$variable][1];
8536
                }
8537
            }
8538
        }
8539
8540
        return $_configuration[$variable];
8541
    }
8542
8543
    return false;
8544
}
8545
8546
/**
8547
 * Returns supported image extensions in the portal.
8548
 *
8549
 * @param bool $supportVectors Whether vector images should also be accepted or not
8550
 *
8551
 * @return array Supported image extensions in the portal
8552
 */
8553
function api_get_supported_image_extensions($supportVectors = true)
8554
{
8555
    // jpg can also be called jpeg, jpe, jfif and jif. See https://en.wikipedia.org/wiki/JPEG#JPEG_filename_extensions
8556
    $supportedImageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'jpe', 'jfif', 'jif'];
8557
    if ($supportVectors) {
8558
        array_push($supportedImageExtensions, 'svg');
8559
    }
8560
    if (version_compare(PHP_VERSION, '5.5.0', '>=')) {
8561
        array_push($supportedImageExtensions, 'webp');
8562
    }
8563
8564
    return $supportedImageExtensions;
8565
}
8566
8567
/**
8568
 * This setting changes the registration status for the campus.
8569
 *
8570
 * @author Patrick Cool <[email protected]>, Ghent University
8571
 *
8572
 * @version August 2006
8573
 *
8574
 * @param bool $listCampus Whether we authorize
8575
 *
8576
 * @todo the $_settings should be reloaded here. => write api function for this and use this in global.inc.php also.
8577
 */
8578
function api_register_campus($listCampus = true)
8579
{
8580
    $tbl_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
8581
8582
    $sql = "UPDATE $tbl_settings SET selected_value='true' WHERE variable='registered'";
8583
    Database::query($sql);
8584
8585
    if (!$listCampus) {
8586
        $sql = "UPDATE $tbl_settings SET selected_value='true' WHERE variable='donotlistcampus'";
8587
        Database::query($sql);
8588
    }
8589
}
8590
8591
/**
8592
 * Checks whether current user is a student boss.
8593
 *
8594
 * @global array $_user
8595
 *
8596
 * @return bool
8597
 */
8598
function api_is_student_boss()
8599
{
8600
    $_user = api_get_user_info();
8601
8602
    return isset($_user['status']) && $_user['status'] == STUDENT_BOSS;
8603
}
8604
8605
/**
8606
 * Check whether the user type should be exclude.
8607
 * Such as invited or anonymous users.
8608
 *
8609
 * @param bool $checkDB Optional. Whether check the user status
8610
 * @param int  $userId  Options. The user id
8611
 *
8612
 * @return bool
8613
 */
8614
function api_is_excluded_user_type($checkDB = false, $userId = 0)
8615
{
8616
    if ($checkDB) {
8617
        $userId = empty($userId) ? api_get_user_id() : (int) $userId;
8618
8619
        if ($userId == 0) {
8620
            return true;
8621
        }
8622
8623
        $userInfo = api_get_user_info($userId);
8624
8625
        switch ($userInfo['status']) {
8626
            case INVITEE:
8627
            case ANONYMOUS:
8628
                return true;
8629
            default:
8630
                return false;
8631
        }
8632
    }
8633
8634
    $isInvited = api_is_invitee();
8635
    $isAnonymous = api_is_anonymous();
8636
8637
    if ($isInvited || $isAnonymous) {
8638
        return true;
8639
    }
8640
8641
    return false;
8642
}
8643
8644
/**
8645
 * Get the user status to ignore in reports.
8646
 *
8647
 * @param string $format Optional. The result type (array or string)
8648
 *
8649
 * @return array|string
8650
 */
8651
function api_get_users_status_ignored_in_reports($format = 'array')
8652
{
8653
    $excludedTypes = [
8654
        INVITEE,
8655
        ANONYMOUS,
8656
    ];
8657
8658
    if ($format == 'string') {
8659
        return implode(', ', $excludedTypes);
8660
    }
8661
8662
    return $excludedTypes;
8663
}
8664
8665
/**
8666
 * Set the Site Use Cookie Warning for 1 year.
8667
 */
8668
function api_set_site_use_cookie_warning_cookie()
8669
{
8670
    setcookie('ChamiloUsesCookies', 'ok', time() + 31556926);
8671
}
8672
8673
/**
8674
 * Return true if the Site Use Cookie Warning Cookie warning exists.
8675
 *
8676
 * @return bool
8677
 */
8678
function api_site_use_cookie_warning_cookie_exist()
8679
{
8680
    return isset($_COOKIE['ChamiloUsesCookies']);
8681
}
8682
8683
/**
8684
 * Given a number of seconds, format the time to show hours, minutes and seconds.
8685
 *
8686
 * @param int    $time         The time in seconds
8687
 * @param string $originFormat Optional. PHP o JS
8688
 *
8689
 * @return string (00h00'00")
8690
 */
8691
function api_format_time($time, $originFormat = 'php')
8692
{
8693
    $h = get_lang('h');
8694
    $hours = $time / 3600;
8695
    $mins = ($time % 3600) / 60;
8696
    $secs = ($time % 60);
8697
8698
    if ($time < 0) {
8699
        $hours = 0;
8700
        $mins = 0;
8701
        $secs = 0;
8702
    }
8703
8704
    if ($originFormat == 'js') {
8705
        $formattedTime = trim(sprintf("%02d : %02d : %02d", $hours, $mins, $secs));
8706
    } else {
8707
        $formattedTime = trim(sprintf("%02d$h%02d'%02d\"", $hours, $mins, $secs));
8708
    }
8709
8710
    return $formattedTime;
8711
}
8712
8713
/**
8714
 * Create a new empty directory with index.html file.
8715
 *
8716
 * @param string $name            The new directory name
8717
 * @param string $parentDirectory Directory parent directory name
8718
 *
8719
 * @return bool Return true if the directory was create. Otherwise return false
8720
 */
8721
function api_create_protected_dir($name, $parentDirectory)
8722
{
8723
    $isCreated = false;
8724
8725
    if (!is_writable($parentDirectory)) {
8726
        return false;
8727
    }
8728
8729
    $fullPath = $parentDirectory.api_replace_dangerous_char($name);
8730
8731
    if (mkdir($fullPath, api_get_permissions_for_new_directories(), true)) {
8732
        $fp = fopen($fullPath.'/index.html', 'w');
8733
8734
        if ($fp) {
0 ignored issues
show
introduced by
$fp is of type resource|false, thus it always evaluated to false.
Loading history...
8735
            if (fwrite($fp, '<html><head></head><body></body></html>')) {
8736
                $isCreated = true;
8737
            }
8738
        }
8739
8740
        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

8740
        fclose(/** @scrutinizer ignore-type */ $fp);
Loading history...
8741
    }
8742
8743
    return $isCreated;
8744
}
8745
8746
/**
8747
 * Sends an email
8748
 * Sender name and email can be specified, if not specified
8749
 * name and email of the platform admin are used.
8750
 *
8751
 * @param string    name of recipient
8752
 * @param string    email of recipient
8753
 * @param string    email subject
8754
 * @param string    email body
8755
 * @param string    sender name
8756
 * @param string    sender e-mail
8757
 * @param array     extra headers in form $headers = array($name => $value) to allow parsing
8758
 * @param array     data file (path and filename)
8759
 * @param bool      True for attaching a embedded file inside content html (optional)
8760
 * @param array     Additional parameters
8761
 *
8762
 * @return bool true if mail was sent
8763
 */
8764
function api_mail_html(
8765
    $recipientName,
8766
    $recipientEmail,
8767
    $subject,
8768
    $body,
8769
    $senderName = '',
8770
    $senderEmail = '',
8771
    $extra_headers = [],
8772
    $data_file = [],
8773
    $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

8773
    /** @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...
8774
    $additionalParameters = []
8775
) {
8776
    if (!api_valid_email($recipientEmail)) {
8777
        return false;
8778
    }
8779
8780
    // Default values
8781
    $notification = new Notification();
8782
    $defaultEmail = $notification->getDefaultPlatformSenderEmail();
8783
    $defaultName = $notification->getDefaultPlatformSenderName();
8784
8785
    // If the parameter is set don't use the admin.
8786
    $senderName = !empty($senderName) ? $senderName : $defaultName;
8787
    $senderEmail = !empty($senderEmail) ? $senderEmail : $defaultEmail;
8788
8789
    // Reply to first
8790
    $replyToName = '';
8791
    $replyToEmail = '';
8792
    if (isset($extra_headers['reply_to'])) {
8793
        $replyToEmail = $extra_headers['reply_to']['mail'];
8794
        $replyToName = $extra_headers['reply_to']['name'];
8795
    }
8796
8797
    //If the SMTP configuration only accept one sender
8798
    /*if (isset($platform_email['SMTP_UNIQUE_SENDER']) && $platform_email['SMTP_UNIQUE_SENDER']) {
8799
        $senderName = $platform_email['SMTP_FROM_NAME'];
8800
        $senderEmail = $platform_email['SMTP_FROM_EMAIL'];
8801
        $valid = PHPMailer::validateAddress($senderEmail);
8802
        if ($valid) {
8803
            //force-set Sender to $senderEmail, otherwise SetFrom only does it if it is currently empty
8804
            $mail->Sender = $senderEmail;
8805
        }
8806
    }*/
8807
8808
    /*$mail->SetFrom($senderEmail, $senderName);
8809
    $mail->Subject = $subject;
8810
    $mail->AltBody = strip_tags(
8811
        str_replace('<br />', "\n", api_html_entity_decode($message))
8812
    );*/
8813
8814
    /*if (is_array($extra_headers) && count($extra_headers) > 0) {
8815
        foreach ($extra_headers as $key => $value) {
8816
            switch (strtolower($key)) {
8817
                case 'encoding':
8818
                case 'content-transfer-encoding':
8819
                    $mail->Encoding = $value;
8820
                    break;
8821
                case 'charset':
8822
                    $mail->Charset = $value;
8823
                    break;
8824
                case 'contenttype':
8825
                case 'content-type':
8826
                    $mail->ContentType = $value;
8827
                    break;
8828
                default:
8829
                    $mail->AddCustomHeader($key.':'.$value);
8830
                    break;
8831
            }
8832
        }
8833
    } else {
8834
        if (!empty($extra_headers)) {
8835
            $mail->AddCustomHeader($extra_headers);
8836
        }
8837
    }*/
8838
8839
    // WordWrap the html body (phpMailer only fixes AltBody) FS#2988
8840
    //$mail->Body = $mail->WrapText($mail->Body, $mail->WordWrap);
8841
    try {
8842
        $message = new \Swift_Message($subject);
8843
8844
        $list = api_get_configuration_value('send_all_emails_to');
8845
        if (!empty($list) && isset($list['emails'])) {
8846
            foreach ($list['emails'] as $email) {
8847
                $message->addCc($email);
8848
            }
8849
        }
8850
8851
        // Attachment
8852
        if (!empty($data_file)) {
8853
            foreach ($data_file as $file_attach) {
8854
                if (!empty($file_attach['path']) && !empty($file_attach['filename'])) {
8855
                    //$message->attach(Swift_Attachment::fromPath($file_attach['path'], $file_attach['filename']);
8856
                    $message->attach(
8857
                        Swift_Attachment::fromPath($file_attach['path'])->setFilename($file_attach['filename'])
8858
                    );
8859
                }
8860
            }
8861
        }
8862
8863
        $noReply = api_get_setting('noreply_email_address');
8864
        $automaticEmailText = '';
8865
        if (!empty($noReply)) {
8866
            $automaticEmailText = '<br />'.get_lang('ThisIsAutomaticEmailNoReply');
8867
        }
8868
8869
        $params = [
8870
            'content' => '',
8871
            'mail_header_style' => api_get_configuration_value('mail_header_style'),
8872
            'mail_content_style' => api_get_configuration_value('mail_content_style'),
8873
            'link' => $additionalParameters['link'] ?? '',
8874
            'automatic_email_text' => $automaticEmailText,
8875
        ];
8876
8877
        $paramsHtml = $paramsText = $params;
8878
8879
        $paramsHtml['content'] = $body;
8880
        $paramsText['content'] = str_replace('<br />', "\n", api_html_entity_decode($body));
8881
8882
        if (!empty($senderEmail)) {
8883
            $message->setFrom([$senderEmail => $senderName]);
8884
        }
8885
8886
        if (!empty($recipientEmail)) {
8887
            $message->setTo([$recipientEmail => $recipientName]);
8888
        }
8889
8890
        if (!empty($replyToEmail)) {
8891
            $message->setReplyTo([$replyToEmail => $replyToName]);
8892
        }
8893
8894
        $message
8895
            ->setBody(
8896
                Container::getTwig()->render(
8897
                    'ChamiloCoreBundle:Mailer:Default/default.html.twig',
8898
                    $paramsHtml
8899
                ),
8900
                'text/html'
8901
            )
8902
            ->addPart(
8903
                Container::getTwig()->render(
8904
                    'ChamiloCoreBundle:Mailer:Default/default.text.twig',
8905
                    $paramsText
8906
                ),
8907
                'text/plain'
8908
            )
8909
            //->setEncoder(\Swift_Encoding::get8BitEncoding())
8910
        ;
8911
8912
        $type = $message->getHeaders()->get('Content-Type');
8913
        $type->setCharset('utf-8');
8914
        Container::getMailer()->send($message);
8915
8916
        return true;
8917
    } catch (Exception $e) {
8918
        error_log($e->getMessage());
8919
    }
8920
8921
    if (!empty($additionalParameters)) {
8922
        $plugin = new AppPlugin();
8923
        $smsPlugin = $plugin->getSMSPluginLibrary();
8924
        if ($smsPlugin) {
0 ignored issues
show
introduced by
$smsPlugin is of type SmsPluginLibraryInterface, thus it always evaluated to true.
Loading history...
8925
            $smsPlugin->send($additionalParameters);
8926
        }
8927
    }
8928
8929
    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...
8930
}
8931
8932
/**
8933
 * @param string $tool       Possible values: GroupManager::GROUP_TOOL_*
8934
 * @param bool   $showHeader
8935
 */
8936
function api_protect_course_group($tool, $showHeader = true)
8937
{
8938
    $userId = api_get_user_id();
8939
    $groupId = api_get_group_id();
8940
    $groupInfo = GroupManager::get_group_properties($groupId);
8941
8942
    if (!empty($groupInfo)) {
8943
        $allow = GroupManager::user_has_access(
8944
            $userId,
8945
            $groupInfo['iid'],
8946
            $tool
8947
        );
8948
8949
        if (!$allow) {
8950
            api_not_allowed($showHeader);
8951
        }
8952
    }
8953
}
8954
8955
/**
8956
 * Check if a date is in a date range.
8957
 *
8958
 * @param datetime $startDate
8959
 * @param datetime $endDate
8960
 * @param datetime $currentDate
8961
 *
8962
 * @return bool true if date is in rage, false otherwise
8963
 */
8964
function api_is_date_in_date_range($startDate, $endDate, $currentDate = null)
8965
{
8966
    $startDate = strtotime(api_get_local_time($startDate));
8967
    $endDate = strtotime(api_get_local_time($endDate));
8968
    $currentDate = strtotime(api_get_local_time($currentDate));
8969
8970
    if ($currentDate >= $startDate && $currentDate <= $endDate) {
8971
        return true;
8972
    }
8973
8974
    return false;
8975
}
8976
8977
/**
8978
 * Eliminate the duplicates of a multidimensional array by sending the key.
8979
 *
8980
 * @param array $array multidimensional array
8981
 * @param int   $key   key to find to compare
8982
 *
8983
 * @return array
8984
 */
8985
function api_unique_multidim_array($array, $key)
8986
{
8987
    $temp_array = [];
8988
    $i = 0;
8989
    $key_array = [];
8990
8991
    foreach ($array as $val) {
8992
        if (!in_array($val[$key], $key_array)) {
8993
            $key_array[$i] = $val[$key];
8994
            $temp_array[$i] = $val;
8995
        }
8996
        $i++;
8997
    }
8998
8999
    return $temp_array;
9000
}
9001
9002
/**
9003
 * Limit the access to Session Admins when the limit_session_admin_role
9004
 * configuration variable is set to true.
9005
 */
9006
function api_protect_limit_for_session_admin()
9007
{
9008
    $limitAdmin = api_get_setting('limit_session_admin_role');
9009
    if (api_is_session_admin() && $limitAdmin === 'true') {
9010
        api_not_allowed(true);
9011
    }
9012
}
9013
9014
/**
9015
 * @return bool
9016
 */
9017
function api_is_student_view_active()
9018
{
9019
    $studentView = Session::read('studentview');
9020
9021
    return $studentView === 'studentview';
9022
}
9023
9024
/**
9025
 * Adds a file inside the upload/$type/id.
9026
 *
9027
 * @param string $type
9028
 * @param array  $file
9029
 * @param int    $itemId
9030
 * @param string $cropParameters
9031
 *
9032
 * @return array|bool
9033
 */
9034
function api_upload_file($type, $file, $itemId, $cropParameters = '')
9035
{
9036
    $upload = process_uploaded_file($file);
9037
    if ($upload) {
9038
        $name = api_replace_dangerous_char($file['name']);
9039
9040
        // No "dangerous" files
9041
        $name = disable_dangerous_file($name);
9042
9043
        $pathId = '/'.substr((string) $itemId, 0, 1).'/'.$itemId.'/';
9044
        $path = api_get_path(SYS_UPLOAD_PATH).$type.$pathId;
9045
9046
        if (!is_dir($path)) {
9047
            mkdir($path, api_get_permissions_for_new_directories(), true);
9048
        }
9049
9050
        $pathToSave = $path.$name;
9051
        $result = moveUploadedFile($file, $pathToSave);
9052
9053
        if ($result) {
9054
            if (!empty($cropParameters)) {
9055
                $image = new Image($pathToSave);
9056
                $image->crop($cropParameters);
9057
            }
9058
9059
            return ['path_to_save' => $pathId.$name];
9060
        }
9061
9062
        return false;
9063
    }
9064
}
9065
9066
/**
9067
 * @param string $type
9068
 * @param int    $itemId
9069
 * @param string $file
9070
 *
9071
 * @return bool
9072
 */
9073
function api_get_uploaded_web_url($type, $itemId, $file)
9074
{
9075
    return api_get_uploaded_file($type, $itemId, $file, true);
9076
}
9077
9078
/**
9079
 * @param string $type
9080
 * @param int    $itemId
9081
 * @param string $file
9082
 * @param bool   $getUrl
9083
 *
9084
 * @return bool
9085
 */
9086
function api_get_uploaded_file($type, $itemId, $file, $getUrl = false)
9087
{
9088
    $itemId = (int) $itemId;
9089
    $pathId = '/'.substr((string) $itemId, 0, 1).'/'.$itemId.'/';
9090
    $path = api_get_path(SYS_UPLOAD_PATH).$type.$pathId;
9091
    $file = basename($file);
9092
    $file = $path.'/'.$file;
9093
    if (Security::check_abs_path($file, $path) && is_file($file) && file_exists($file)) {
9094
        if ($getUrl) {
9095
            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...
9096
        }
9097
9098
        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...
9099
    }
9100
9101
    return false;
9102
}
9103
9104
/**
9105
 * @param string $type
9106
 * @param int    $itemId
9107
 * @param string $file
9108
 * @param string $title
9109
 */
9110
function api_download_uploaded_file($type, $itemId, $file, $title = '')
9111
{
9112
    $file = api_get_uploaded_file($type, $itemId, $file);
9113
    if ($file) {
9114
        if (Security::check_abs_path($file, api_get_path(SYS_UPLOAD_PATH).$type)) {
9115
            DocumentManager::file_send_for_download($file, true, $title);
9116
            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...
9117
        }
9118
    }
9119
    api_not_allowed(true);
9120
}
9121
9122
/**
9123
 * @param string $type
9124
 * @param string $file
9125
 */
9126
function api_remove_uploaded_file($type, $file)
9127
{
9128
    $typePath = api_get_path(SYS_UPLOAD_PATH).$type;
9129
    $path = $typePath.'/'.$file;
9130
    if (Security::check_abs_path($path, $typePath) && file_exists($path) && is_file($path)) {
9131
        unlink($path);
9132
    }
9133
}
9134
9135
/**
9136
 * @param string $type
9137
 * @param int    $itemId
9138
 * @param string $file
9139
 *
9140
 * @return bool
9141
 */
9142
function api_remove_uploaded_file_by_id($type, $itemId, $file)
9143
{
9144
    $file = api_get_uploaded_file($type, $itemId, $file, false);
9145
    $typePath = api_get_path(SYS_UPLOAD_PATH).$type;
9146
    if (Security::check_abs_path($file, $typePath) && file_exists($file) && is_file($file)) {
9147
        unlink($file);
9148
9149
        return true;
9150
    }
9151
9152
    return false;
9153
}
9154
9155
/**
9156
 * Converts string value to float value.
9157
 *
9158
 * 3.141516 => 3.141516
9159
 * 3,141516 => 3.141516
9160
 *
9161
 * @todo WIP
9162
 *
9163
 * @param string $number
9164
 *
9165
 * @return float
9166
 */
9167
function api_float_val($number)
9168
{
9169
    $number = (float) str_replace(',', '.', trim($number));
9170
9171
    return $number;
9172
}
9173
9174
/**
9175
 * Converts float values
9176
 * Example if $decimals = 2.
9177
 *
9178
 * 3.141516 => 3.14
9179
 * 3,141516 => 3,14
9180
 *
9181
 * @param string $number            number in iso code
9182
 * @param int    $decimals
9183
 * @param string $decimalSeparator
9184
 * @param string $thousandSeparator
9185
 *
9186
 * @return bool|string
9187
 */
9188
function api_number_format($number, $decimals = 0, $decimalSeparator = '.', $thousandSeparator = ',')
9189
{
9190
    $number = api_float_val($number);
9191
9192
    return number_format($number, $decimals, $decimalSeparator, $thousandSeparator);
9193
}
9194
9195
/**
9196
 * Set location url with a exit break by default.
9197
 *
9198
 * @param $url
9199
 * @param bool $exit
9200
 */
9201
function location($url, $exit = true)
9202
{
9203
    header('Location: '.$url);
9204
9205
    if ($exit) {
9206
        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...
9207
    }
9208
}
9209
9210
/**
9211
 * @return string
9212
 */
9213
function api_get_web_url()
9214
{
9215
    if (api_get_setting('server_type') === 'test') {
9216
        return api_get_path(WEB_PATH).'web/app_dev.php/';
9217
    } else {
9218
        return api_get_path(WEB_PATH).'web/';
9219
    }
9220
}
9221
9222
/**
9223
 * @param string $from
9224
 * @param string $to
9225
 *
9226
 * @return string
9227
 */
9228
function api_get_relative_path($from, $to)
9229
{
9230
    // some compatibility fixes for Windows paths
9231
    $from = is_dir($from) ? rtrim($from, '\/').'/' : $from;
9232
    $to = is_dir($to) ? rtrim($to, '\/').'/' : $to;
9233
    $from = str_replace('\\', '/', $from);
9234
    $to = str_replace('\\', '/', $to);
9235
9236
    $from = explode('/', $from);
9237
    $to = explode('/', $to);
9238
    $relPath = $to;
9239
9240
    foreach ($from as $depth => $dir) {
9241
        // find first non-matching dir
9242
        if ($dir === $to[$depth]) {
9243
            // ignore this directory
9244
            array_shift($relPath);
9245
        } else {
9246
            // get number of remaining dirs to $from
9247
            $remaining = count($from) - $depth;
9248
            if ($remaining > 1) {
9249
                // add traversals up to first matching dir
9250
                $padLength = (count($relPath) + $remaining - 1) * -1;
9251
                $relPath = array_pad($relPath, $padLength, '..');
9252
                break;
9253
            } else {
9254
                $relPath[0] = './'.$relPath[0];
9255
            }
9256
        }
9257
    }
9258
9259
    return implode('/', $relPath);
9260
}
9261