Passed
Push — master ( 145827...6e0f6e )
by Julito
23:20 queued 12:22
created

api_is_platform_admin()   B

Complexity

Conditions 7
Paths 8

Size

Total Lines 19
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

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

1152
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...
1153
{
1154
    $course_info = api_get_course_info();
1155
    if (empty($course_info)) {
1156
        api_not_allowed($print_headers);
1157
1158
        return false;
1159
    }
1160
1161
    $is_allowed_in_course = api_is_allowed_in_course();
1162
    $is_visible = false;
1163
1164
    if (api_is_drh()) {
1165
        return true;
1166
    }
1167
1168
    // Session admin has access to course
1169
    $sessionAccess = api_get_configuration_value('session_admins_access_all_content');
1170
    if ($sessionAccess) {
1171
        $allow_session_admins = true;
1172
    }
1173
1174
    if (api_is_platform_admin($allow_session_admins)) {
1175
        return true;
1176
    }
1177
1178
    if (isset($course_info) && isset($course_info['visibility'])) {
1179
        switch ($course_info['visibility']) {
1180
            default:
1181
            case COURSE_VISIBILITY_CLOSED:
1182
                // Completely closed: the course is only accessible to the teachers. - 0
1183
                if (api_get_user_id() && !api_is_anonymous() && $is_allowed_in_course) {
1184
                    $is_visible = true;
1185
                }
1186
                break;
1187
            case COURSE_VISIBILITY_REGISTERED:
1188
                // Private - access authorized to course members only - 1
1189
                if (api_get_user_id() && !api_is_anonymous() && $is_allowed_in_course) {
1190
                    $is_visible = true;
1191
                }
1192
                break;
1193
            case COURSE_VISIBILITY_OPEN_PLATFORM:
1194
                // Open - access allowed for users registered on the platform - 2
1195
                if (api_get_user_id() && !api_is_anonymous() && $is_allowed_in_course) {
1196
                    $is_visible = true;
1197
                }
1198
                break;
1199
            case COURSE_VISIBILITY_OPEN_WORLD:
1200
                //Open - access allowed for the whole world - 3
1201
                $is_visible = true;
1202
                break;
1203
            case COURSE_VISIBILITY_HIDDEN:
1204
                //Completely closed: the course is only accessible to the teachers. - 0
1205
                if (api_is_platform_admin()) {
1206
                    $is_visible = true;
1207
                }
1208
                break;
1209
        }
1210
1211
        //If password is set and user is not registered to the course then the course is not visible
1212
        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...
1213
            isset($course_info['registration_code']) &&
1214
            !empty($course_info['registration_code'])
1215
        ) {
1216
            $is_visible = false;
1217
        }
1218
    }
1219
1220
    // Check session visibility
1221
    $session_id = api_get_session_id();
1222
1223
    if (!empty($session_id)) {
1224
        //$is_allowed_in_course was set in local.inc.php
1225
        if (!$is_allowed_in_course) {
1226
            $is_visible = false;
1227
        }
1228
    }
1229
1230
    if (!$is_visible) {
1231
        api_not_allowed($print_headers);
1232
1233
        return false;
1234
    }
1235
1236
    return true;
1237
}
1238
1239
/**
1240
 * Function used to protect an admin script.
1241
 *
1242
 * The function blocks access when the user has no platform admin rights
1243
 * with an error message printed on default output
1244
 *
1245
 * @param bool Whether to allow session admins as well
1246
 * @param bool Whether to allow HR directors as well
1247
 * @param string An optional message (already passed through get_lang)
1248
 *
1249
 * @return bool True if user is allowed, false otherwise.
1250
 *              The function also outputs an error message in case not allowed
1251
 *
1252
 * @author Roan Embrechts (original author)
1253
 */
1254
function api_protect_admin_script($allow_sessions_admins = false, $allow_drh = false, $message = null)
1255
{
1256
    if (!api_is_platform_admin($allow_sessions_admins, $allow_drh)) {
1257
        api_not_allowed(true, $message);
1258
1259
        return false;
1260
    }
1261
1262
    return true;
1263
}
1264
1265
/**
1266
 * Function used to protect a teacher script.
1267
 * The function blocks access when the user has no teacher rights.
1268
 *
1269
 * @return bool True if the current user can access the script, false otherwise
1270
 *
1271
 * @author Yoselyn Castillo
1272
 */
1273
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

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

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

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

3786
    /** @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...
3787
    $message = null,
3788
    $responseCode = 0
3789
) {
3790
    $debug = api_get_setting('server_type') == 'test';
3791
3792
    // Default code is 403 forbidden
3793
    $responseCode = empty($responseCode) ? 403 : $responseCode;
3794
    $message = empty($message) ? get_lang('NotAuthorized') : $message;
3795
3796
    // Create new exception rendered by template:
3797
    // src/ThemeBundle/Resources/views/Exception/error.html.twig
3798
3799
    // if error is 404 then the template is:
3800
    // src/ThemeBundle/Resources/views/Exception/error404.html.twig
3801
    $exception = new Exception($message);
3802
    $request = Container::getRequest();
3803
    $exception = \Symfony\Component\Debug\Exception\FlattenException::create($exception, $responseCode);
3804
    $controller = new \Chamilo\ThemeBundle\Controller\ExceptionController(Container::getTwig(), $debug);
3805
    $response = $controller->showAction($request, $exception);
3806
    $response->send();
3807
    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...
3808
3809
    $home_url = api_get_path(WEB_PATH);
0 ignored issues
show
Unused Code introduced by
$home_url = api_get_path(WEB_PATH) 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...
3810
    $user_id = api_get_user_id();
3811
    $course = api_get_course_id();
3812
3813
    global $this_section;
3814
3815
    if (CustomPages::enabled() && !isset($user_id)) {
3816
        if (empty($user_id)) {
3817
            // Why the CustomPages::enabled() need to be to set the request_uri
3818
            $_SESSION['request_uri'] = $_SERVER['REQUEST_URI'];
3819
        }
3820
        CustomPages::display(CustomPages::INDEX_UNLOGGED);
3821
    }
3822
3823
    $origin = api_get_origin();
3824
3825
    $msg = null;
3826
    if (isset($message)) {
3827
        $msg = $message;
3828
    } else {
3829
        $msg = Display::return_message(
3830
            get_lang('NotAllowedClickBack').'
3831
            <script>function goBack(){window.history.back();}</script>',
3832
            'error',
3833
            false
3834
        );
3835
        $msg .= '<p class="text-center">
3836
             <a onclick="goBack();" class="btn btn-default" href="'.$home_url.'">'.get_lang('GoBack').'</a>
3837
             </p>';
3838
    }
3839
3840
    $msg = Display::div($msg, ['align' => 'center']);
3841
3842
    $show_headers = 0;
3843
    if ($print_headers && $origin != 'learnpath') {
3844
        $show_headers = 1;
3845
    }
3846
3847
    $tpl = new Template(null, $show_headers, $show_headers, false, true, false, true, $responseCode);
3848
    $tpl->assign('hide_login_link', 1);
3849
    $tpl->assign('content', $msg);
3850
3851
    if (($user_id != 0 && !api_is_anonymous()) &&
3852
        (!isset($course) || $course == -1) &&
3853
        empty($_GET['cidReq'])
3854
    ) {
3855
        // if the access is not authorized and there is some login information
3856
        // but the cidReq is not found, assume we are missing course data and send the user
3857
        // to the user_portal
3858
        $tpl->display_one_col_template();
3859
        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...
3860
    }
3861
3862
    if (!empty($_SERVER['REQUEST_URI']) &&
3863
        (
3864
            !empty($_GET['cidReq']) ||
3865
            $this_section == SECTION_MYPROFILE ||
3866
            $this_section == SECTION_PLATFORM_ADMIN
3867
        )
3868
    ) {
3869
        $courseCode = api_get_course_id();
3870
        // Only display form and return to the previous URL if there was a course ID included
3871
        if ($user_id != 0 && !api_is_anonymous()) {
3872
            //if there is a user ID, then the user is not allowed but the session is still there. Say so and exit
3873
            $tpl->assign('content', $msg);
3874
            $tpl->display_one_col_template();
3875
            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...
3876
        }
3877
3878
        if (!is_null($courseCode)) {
3879
            api_set_firstpage_parameter($courseCode);
3880
        }
3881
3882
        // If the user has no user ID, then his session has expired
3883
        $form = api_get_not_allowed_login_form();
3884
3885
        // see same text in auth/gotocourse.php and main_api.lib.php function api_not_allowed (above)
3886
        $content = Display::return_message(get_lang('NotAllowed'), 'error', false);
3887
3888
        if (!empty($courseCode)) {
3889
            $content .= '<h4>'.get_lang('LoginToGoToThisCourse').'</h4>';
3890
        }
3891
3892
        $content .= '<div class="well">';
3893
        $content .= $form->returnForm();
3894
        $content .= '</div>';
3895
        if (!empty($courseCode)) {
3896
            $content .= '<hr/><p style="text-align:center"><a href="'.$home_url.'">'.
3897
                get_lang('ReturnToCourseHomepage').'</a></p>';
3898
        } else {
3899
            $content .= '<hr/><p style="text-align:center"><a href="'.$home_url.'">'.
3900
                get_lang('BackHome').'</a></p>';
3901
        }
3902
3903
        $tpl->setLoginBodyClass();
3904
        $tpl->assign('content', $content);
3905
        $tpl->display_one_col_template();
3906
        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...
3907
    }
3908
3909
    if ($user_id != 0 && !api_is_anonymous()) {
3910
        $tpl->display_one_col_template();
3911
        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...
3912
    }
3913
3914
    $msg = null;
3915
    // The session is over and we were not in a course,
3916
    // or we try to get directly to a private course without being logged
3917
    $courseId = api_get_course_int_id();
3918
    if (!empty($courseId)) {
3919
        api_set_firstpage_parameter(api_get_course_id());
3920
        $tpl->setLoginBodyClass();
3921
3922
        // see same text in auth/gotocourse.php and main_api.lib.php function api_not_allowed (bellow)
3923
        $msg = Display::return_message(get_lang('NotAllowed'), 'error', false);
3924
        $msg .= '<h4>'.get_lang('LoginToGoToThisCourse').'</h4>';
3925
        $form = api_get_not_allowed_login_form();
3926
        $msg .= '<div class="well">';
3927
        $msg .= $form->returnForm();
3928
        $msg .= '</div>';
3929
        if ($casEnabled) {
3930
            $msg .= "</div>";
3931
        }
3932
    } else {
3933
        // we were not in a course, return to home page
3934
        $msg = Display::return_message(
3935
            get_lang('NotAllowed'),
3936
            'error',
3937
            false
3938
        );
3939
3940
        $msg .= '<p class="text-center">
3941
                 <a class="btn btn-default" href="'.$home_url.'">'.get_lang('BackHome').'</a>
3942
                 </p>';
3943
3944
        if (!empty($message)) {
3945
            $msg = $message;
3946
        }
3947
3948
        if (api_is_anonymous()) {
3949
            $form = api_get_not_allowed_login_form();
3950
            $msg .= '<div class="well">';
3951
            $msg .= $form->returnForm();
3952
            $msg .= '</div>';
3953
        }
3954
    }
3955
3956
    $tpl->assign('content', $msg);
3957
    $tpl->display_one_col_template();
3958
    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...
3959
}
3960
3961
/**
3962
 * @return FormValidator
3963
 */
3964
function api_get_not_allowed_login_form()
3965
{
3966
    $action = api_get_self().'?'.Security::remove_XSS($_SERVER['QUERY_STRING']);
3967
    $action = str_replace('&amp;', '&', $action);
3968
    Session::write('redirect_after_not_allow_page', $action);
3969
    $action .= '&redirect_after_not_allow_page=1';
3970
3971
    $form = new FormValidator(
3972
        'formLogin',
3973
        'post',
3974
        $action,
3975
        null,
3976
        ['class' => 'form-stacked']
3977
    );
3978
    $params = [
3979
        'placeholder' => get_lang('UserName'),
3980
        'class' => 'col-md-3',
3981
    ];
3982
    if (api_browser_support('autocapitalize')) {
3983
        $params['autocapitalize'] = 'none';
3984
    }
3985
3986
    $form->addElement(
3987
        'text',
3988
        'login',
3989
        null,
3990
        $params
3991
    );
3992
    $form->addElement(
3993
        'password',
3994
        'password',
3995
        null,
3996
        ['placeholder' => get_lang('Password'), 'class' => 'col-md-3']
3997
    ); //new
3998
    $form->addButtonNext(get_lang('LoginEnter'), 'submitAuth');
3999
4000
    return $form;
4001
}
4002
4003
/**
4004
 * Gets a UNIX timestamp from a database (MySQL) datetime format string.
4005
 *
4006
 * @param $last_post_datetime standard output date in a sql query
4007
 *
4008
 * @return int timestamp
4009
 *
4010
 * @author Toon Van Hoecke <[email protected]>
4011
 *
4012
 * @version October 2003
4013
 * @desc convert sql date to unix timestamp
4014
 */
4015
function convert_sql_date($last_post_datetime)
4016
{
4017
    list($last_post_date, $last_post_time) = explode(' ', $last_post_datetime);
4018
    list($year, $month, $day) = explode('-', $last_post_date);
4019
    list($hour, $min, $sec) = explode(':', $last_post_time);
4020
4021
    return mktime((int) $hour, (int) $min, (int) $sec, (int) $month, (int) $day, (int) $year);
4022
}
4023
4024
/**
4025
 * Gets item visibility from the item_property table.
4026
 *
4027
 * Getting the visibility is done by getting the last updated visibility entry,
4028
 * using the largest session ID found if session 0 and another was found (meaning
4029
 * the only one that is actually from the session, in case there are results from
4030
 * session 0 *AND* session n).
4031
 *
4032
 * @param array  $_course  Course properties array (result of api_get_course_info())
4033
 * @param string $tool     Tool (learnpath, document, etc)
4034
 * @param int    $id       The item ID in the given tool
4035
 * @param int    $session  The session ID (optional)
4036
 * @param int    $user_id
4037
 * @param string $type
4038
 * @param string $group_id
4039
 *
4040
 * @return int -1 on error, 0 if invisible, 1 if visible
4041
 */
4042
function api_get_item_visibility(
4043
    $_course,
4044
    $tool,
4045
    $id,
4046
    $session = 0,
4047
    $user_id = null,
4048
    $type = null,
4049
    $group_id = null
4050
) {
4051
    if (!is_array($_course) || count($_course) == 0 || empty($tool) || empty($id)) {
4052
        return -1;
4053
    }
4054
4055
    $tool = Database::escape_string($tool);
4056
    $id = (int) $id;
4057
    $session = (int) $session;
4058
    $TABLE_ITEMPROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY);
4059
    $course_id = (int) $_course['real_id'];
4060
4061
    $userCondition = '';
4062
    if (!empty($user_id)) {
4063
        $user_id = (int) $user_id;
4064
        $userCondition = " AND to_user_id = $user_id ";
4065
    }
4066
4067
    $typeCondition = '';
4068
    if (!empty($type)) {
4069
        $type = Database::escape_string($type);
4070
        $typeCondition = " AND lastedit_type = '$type' ";
4071
    }
4072
4073
    $groupCondition = '';
4074
    if (!empty($group_id)) {
4075
        $group_id = (int) $group_id;
4076
        $groupCondition = " AND to_group_id = '$group_id' ";
4077
    }
4078
4079
    $sql = "SELECT visibility
4080
            FROM $TABLE_ITEMPROPERTY
4081
            WHERE
4082
                c_id = $course_id AND
4083
                tool = '$tool' AND
4084
                ref = $id AND
4085
                (session_id = $session OR session_id = 0 OR session_id IS NULL)
4086
                $userCondition $typeCondition $groupCondition
4087
            ORDER BY session_id DESC, lastedit_date DESC
4088
            LIMIT 1";
4089
4090
    $res = Database::query($sql);
4091
    if ($res === false || Database::num_rows($res) == 0) {
4092
        return -1;
4093
    }
4094
    $row = Database::fetch_array($res);
4095
4096
    return (int) $row['visibility'];
4097
}
4098
4099
/**
4100
 * Delete a row in the c_item_property table.
4101
 *
4102
 * @param array  $courseInfo
4103
 * @param string $tool
4104
 * @param int    $itemId
4105
 * @param int    $userId
4106
 * @param int    $groupId    group.iid
4107
 * @param int    $sessionId
4108
 *
4109
 * @return false|null
4110
 */
4111
function api_item_property_delete(
4112
    $courseInfo,
4113
    $tool,
4114
    $itemId,
4115
    $userId,
4116
    $groupId = 0,
4117
    $sessionId = 0
4118
) {
4119
    if (empty($courseInfo)) {
4120
        return false;
4121
    }
4122
4123
    $courseId = (int) $courseInfo['real_id'];
4124
4125
    if (empty($courseId) || empty($tool) || empty($itemId)) {
4126
        return false;
4127
    }
4128
4129
    $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4130
    $tool = Database::escape_string($tool);
4131
    $itemId = intval($itemId);
4132
    $userId = intval($userId);
4133
    $groupId = intval($groupId);
4134
    $sessionId = intval($sessionId);
4135
4136
    $groupCondition = " AND to_group_id = $groupId ";
4137
    if (empty($groupId)) {
4138
        $groupCondition = " AND (to_group_id is NULL OR to_group_id = 0) ";
4139
    }
4140
4141
    $userCondition = " AND to_user_id = $userId ";
4142
    if (empty($userId)) {
4143
        $userCondition = " AND (to_user_id is NULL OR to_user_id = 0) ";
4144
    }
4145
    $sessionCondition = api_get_session_condition($sessionId, true, false, 'session_id');
4146
    $sql = "DELETE FROM $table
4147
            WHERE
4148
                c_id = $courseId AND
4149
                tool  = '$tool' AND
4150
                ref = $itemId
4151
                $sessionCondition
4152
                $userCondition
4153
                $groupCondition
4154
            ";
4155
4156
    Database::query($sql);
4157
}
4158
4159
/**
4160
 * Updates or adds item properties to the Item_propetry table
4161
 * Tool and lastedit_type are language independant strings (langvars->get_lang!).
4162
 *
4163
 * @param array  $_course        array with course properties
4164
 * @param string $tool           tool id, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4165
 * @param int    $item_id        id of the item itself, linked to key of every tool ('id', ...)
4166
 * @param string $last_edit_type add or update action
4167
 *                               (1) message to be translated (in trad4all) : e.g. DocumentAdded, DocumentUpdated;
4168
 *                               (2) "delete"
4169
 *                               (3) "visible"
4170
 *                               (4) "invisible"
4171
 * @param int    $user_id        id of the editing/adding user
4172
 * @param array  $groupInfo      must include group.iid/group.od
4173
 * @param int    $to_user_id     id of the intended user (always has priority over $to_group_id !), only relevant for $type (1)
4174
 * @param string $start_visible  0000-00-00 00:00:00 format
4175
 * @param string $end_visible    0000-00-00 00:00:00 format
4176
 * @param int    $session_id     The session ID, if any, otherwise will default to 0
4177
 *
4178
 * @return bool false if update fails
4179
 *
4180
 * @author Toon Van Hoecke <[email protected]>, Ghent University
4181
 *
4182
 * @version January 2005
4183
 * @desc update the item_properties table (if entry not exists, insert) of the course
4184
 */
4185
function api_item_property_update(
4186
    $_course,
4187
    $tool,
4188
    $item_id,
4189
    $last_edit_type,
4190
    $user_id,
4191
    $groupInfo = [],
4192
    $to_user_id = null,
4193
    $start_visible = '',
4194
    $end_visible = '',
4195
    $session_id = 0
4196
) {
4197
    if (empty($_course)) {
4198
        return false;
4199
    }
4200
4201
    $course_id = $_course['real_id'];
4202
4203
    if (empty($course_id)) {
4204
        return false;
4205
    }
4206
4207
    $to_group_id = 0;
4208
    if (!empty($groupInfo) && isset($groupInfo['iid'])) {
4209
        $to_group_id = (int) $groupInfo['iid'];
4210
    }
4211
4212
    $em = Database::getManager();
4213
4214
    // Definition of variables.
4215
    $tool = Database::escape_string($tool);
4216
    $item_id = (int) $item_id;
4217
    $lastEditTypeNoFilter = $last_edit_type;
4218
    $last_edit_type = Database::escape_string($last_edit_type);
4219
    $user_id = (int) $user_id;
4220
4221
    $startVisible = "NULL";
4222
    if (!empty($start_visible)) {
4223
        $start_visible = Database::escape_string($start_visible);
4224
        $startVisible = "'$start_visible'";
4225
    }
4226
4227
    $endVisible = "NULL";
4228
    if (!empty($end_visible)) {
4229
        $end_visible = Database::escape_string($end_visible);
4230
        $endVisible = "'$end_visible'";
4231
    }
4232
4233
    $to_filter = '';
4234
    $time = api_get_utc_datetime();
4235
4236
    if (!empty($session_id)) {
4237
        $session_id = (int) $session_id;
4238
    } else {
4239
        $session_id = api_get_session_id();
4240
    }
4241
4242
    // Definition of tables.
4243
    $tableItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
4244
4245
    if ($to_user_id <= 0) {
4246
        $to_user_id = null; // No to_user_id set
4247
    }
4248
4249
    if (!is_null($to_user_id)) {
4250
        // $to_user_id has more priority than $to_group_id
4251
        $to_user_id = (int) $to_user_id;
4252
        $to_field = 'to_user_id';
4253
        $to_value = $to_user_id;
4254
    } else {
4255
        // $to_user_id is not set.
4256
        $to_field = 'to_group_id';
4257
        $to_value = $to_group_id;
4258
    }
4259
4260
    $toValueCondition = empty($to_value) ? 'NULL' : "'$to_value'";
4261
    // Set filters for $to_user_id and $to_group_id, with priority for $to_user_id
4262
    $condition_session = " AND session_id = $session_id ";
4263
    if (empty($session_id)) {
4264
        $condition_session = ' AND (session_id = 0 OR session_id IS NULL) ';
4265
    }
4266
4267
    $filter = " c_id = $course_id AND tool = '$tool' AND ref = $item_id $condition_session ";
4268
4269
    // Check whether $to_user_id and $to_group_id are passed in the function call.
4270
    // If both are not passed (both are null) then it is a message for everybody and $to_group_id should be 0 !
4271
    if (is_null($to_user_id) && is_null($to_group_id)) {
4272
        $to_group_id = 0;
4273
    }
4274
4275
    if (!is_null($to_user_id)) {
4276
        // Set filter to intended user.
4277
        $to_filter = " AND to_user_id = $to_user_id $condition_session";
4278
    } else {
4279
        // Set filter to intended group.
4280
        if (($to_group_id != 0) && $to_group_id == strval(intval($to_group_id))) {
4281
            $to_filter = " AND to_group_id = $to_group_id $condition_session";
4282
        }
4283
    }
4284
4285
    // Adding filter if set.
4286
    $filter .= $to_filter;
4287
4288
    // Update if possible
4289
    $set_type = '';
4290
4291
    switch ($lastEditTypeNoFilter) {
4292
        case 'delete':
4293
            // delete = make item only visible for the platform admin.
4294
            $visibility = '2';
4295
            if (!empty($session_id)) {
4296
                // Check whether session id already exist into item_properties for updating visibility or add it.
4297
                $sql = "SELECT session_id FROM $tableItemProperty
4298
                        WHERE
4299
                            c_id = $course_id AND
4300
                            tool = '$tool' AND
4301
                            ref = $item_id AND
4302
                            session_id = $session_id";
4303
                $rs = Database::query($sql);
4304
                if (Database::num_rows($rs) > 0) {
4305
                    $sql = "UPDATE $tableItemProperty
4306
                            SET lastedit_type       = '".str_replace('_', '', ucwords($tool))."Deleted',
4307
                                lastedit_date       = '$time',
4308
                                lastedit_user_id    = $user_id,
4309
                                visibility          = $visibility,
4310
                                session_id          = $session_id $set_type
4311
                            WHERE $filter";
4312
                    $result = Database::query($sql);
4313
                } else {
4314
                    $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)
4315
                            VALUES ($course_id, '$tool',$item_id, '$time', $user_id, '$time', '$last_edit_type',$user_id, $toValueCondition, $visibility, $startVisible, $endVisible, $session_id)";
4316
                    $result = Database::query($sql);
4317
                    $id = Database::insert_id();
4318
                    if ($id) {
4319
                        $sql = "UPDATE $tableItemProperty SET id = iid WHERE iid = $id";
4320
                        Database::query($sql);
4321
                    }
4322
                }
4323
            } else {
4324
                $sql = "UPDATE $tableItemProperty
4325
                        SET
4326
                            lastedit_type='".str_replace('_', '', ucwords($tool))."Deleted',
4327
                            lastedit_date='$time',
4328
                            lastedit_user_id = $user_id,
4329
                            visibility = $visibility $set_type
4330
                        WHERE $filter";
4331
                $result = Database::query($sql);
4332
            }
4333
            break;
4334
        case 'visible': // Change item to visible.
4335
            $visibility = '1';
4336
            if (!empty($session_id)) {
4337
                // Check whether session id already exist into item_properties for updating visibility or add it.
4338
                $sql = "SELECT session_id FROM $tableItemProperty
4339
                        WHERE
4340
                            c_id = $course_id AND
4341
                            tool = '$tool' AND
4342
                            ref = $item_id AND
4343
                            session_id = $session_id";
4344
                $rs = Database::query($sql);
4345
                if (Database::num_rows($rs) > 0) {
4346
                    $sql = "UPDATE $tableItemProperty
4347
                            SET
4348
                                lastedit_type='".str_replace('_', '', ucwords($tool))."Visible',
4349
                                lastedit_date='$time',
4350
                                lastedit_user_id = $user_id,
4351
                                visibility = $visibility,
4352
                                session_id = $session_id $set_type
4353
                            WHERE $filter";
4354
                    $result = Database::query($sql);
4355
                } else {
4356
                    $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)
4357
                            VALUES ($course_id, '$tool', $item_id, '$time', $user_id, '$time', '$last_edit_type', $user_id, $toValueCondition, $visibility, $startVisible, $endVisible, $session_id)";
4358
                    $result = Database::query($sql);
4359
                    $id = Database::insert_id();
4360
                    if ($id) {
4361
                        $sql = "UPDATE $tableItemProperty SET id = iid WHERE iid = $id";
4362
                        Database::query($sql);
4363
                    }
4364
                }
4365
            } else {
4366
                $sql = "UPDATE $tableItemProperty
4367
                        SET
4368
                            lastedit_type='".str_replace('_', '', ucwords($tool))."Visible',
4369
                            lastedit_date='$time',
4370
                            lastedit_user_id = $user_id,
4371
                            visibility = $visibility $set_type
4372
                        WHERE $filter";
4373
                $result = Database::query($sql);
4374
            }
4375
            break;
4376
        case 'invisible': // Change item to invisible.
4377
            $visibility = '0';
4378
            if (!empty($session_id)) {
4379
                // Check whether session id already exist into item_properties for updating visibility or add it
4380
                $sql = "SELECT session_id FROM $tableItemProperty
4381
                        WHERE
4382
                            c_id = $course_id AND
4383
                            tool = '$tool' AND
4384
                            ref = $item_id AND
4385
                            session_id = $session_id";
4386
                $rs = Database::query($sql);
4387
                if (Database::num_rows($rs) > 0) {
4388
                    $sql = "UPDATE $tableItemProperty
4389
                            SET
4390
                                lastedit_type = '".str_replace('_', '', ucwords($tool))."Invisible',
4391
                                lastedit_date = '$time',
4392
                                lastedit_user_id = $user_id,
4393
                                visibility = $visibility,
4394
                                session_id = $session_id $set_type
4395
                            WHERE $filter";
4396
                    $result = Database::query($sql);
4397
                } else {
4398
                    $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)
4399
                            VALUES ($course_id, '$tool', $item_id, '$time', $user_id, '$time', '$last_edit_type', $user_id, $toValueCondition, $visibility, $startVisible, $endVisible, $session_id)";
4400
                    $result = Database::query($sql);
4401
                    $id = Database::insert_id();
4402
                    if ($id) {
4403
                        $sql = "UPDATE $tableItemProperty SET id = iid WHERE iid = $id";
4404
                        Database::query($sql);
4405
                    }
4406
                }
4407
            } else {
4408
                $sql = "UPDATE $tableItemProperty
4409
                        SET
4410
                            lastedit_type = '".str_replace('_', '', ucwords($tool))."Invisible',
4411
                            lastedit_date = '$time',
4412
                            lastedit_user_id = $user_id,
4413
                            visibility = $visibility $set_type
4414
                        WHERE $filter";
4415
                $result = Database::query($sql);
4416
            }
4417
            break;
4418
        default: // The item will be added or updated.
4419
            $set_type = ", lastedit_type = '$last_edit_type' ";
4420
            $visibility = '1';
4421
            //$filter .= $to_filter; already added
4422
            $sql = "UPDATE $tableItemProperty
4423
                    SET
4424
                      lastedit_date = '$time',
4425
                      lastedit_user_id = $user_id $set_type
4426
                    WHERE $filter";
4427
            $result = Database::query($sql);
4428
    }
4429
4430
    // Insert if no entries are found (can only happen in case of $last_edit_type switch is 'default').
4431
    if ($result == false || Database::affected_rows($result) == 0) {
4432
        $objCourse = $em->find('ChamiloCoreBundle:Course', intval($course_id));
4433
        $objTime = new DateTime('now', new DateTimeZone('UTC'));
4434
        $objUser = api_get_user_entity($user_id);
4435
        if (empty($objUser)) {
4436
            // Use anonymous
4437
            $user_id = api_get_anonymous_id();
4438
            $objUser = api_get_user_entity($user_id);
4439
        }
4440
4441
        $objGroup = null;
4442
        if (!empty($to_group_id)) {
4443
            $objGroup = $em->find('ChamiloCourseBundle:CGroupInfo', $to_group_id);
4444
        }
4445
4446
        $objToUser = api_get_user_entity($to_user_id);
4447
        $objSession = $em->find('ChamiloCoreBundle:Session', intval($session_id));
4448
4449
        $startVisibleDate = !empty($start_visible) ? new DateTime($start_visible, new DateTimeZone('UTC')) : null;
4450
        $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...
4451
4452
        $cItemProperty = new CItemProperty($objCourse);
4453
        $cItemProperty
4454
            ->setTool($tool)
4455
            ->setRef($item_id)
4456
            ->setInsertDate($objTime)
4457
            ->setInsertUser($objUser)
4458
            ->setLasteditDate($objTime)
4459
            ->setLasteditType($last_edit_type)
4460
            ->setGroup($objGroup)
4461
            ->setToUser($objToUser)
4462
            ->setVisibility($visibility)
4463
            ->setStartVisible($startVisibleDate)
4464
            ->setEndVisible($endVisibleDate)
4465
            ->setSession($objSession);
4466
4467
        $em->persist($cItemProperty);
4468
        $em->flush();
4469
4470
        $id = $cItemProperty->getIid();
4471
4472
        if ($id) {
4473
            $cItemProperty->setId($id);
4474
            $em->merge($cItemProperty);
4475
            $em->flush();
4476
4477
            return false;
4478
        }
4479
    }
4480
4481
    return true;
4482
}
4483
4484
/**
4485
 * Gets item property by tool.
4486
 *
4487
 * @param string    course code
4488
 * @param string    tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4489
 * @param int       id of the item itself, linked to key of every tool ('id', ...), "*" = all items of the tool
4490
 * @param int    $session_id
4491
 * @param string $tool
4492
 * @param string $course_code
4493
 *
4494
 * @return array All fields from c_item_property (all rows found) or empty array
4495
 */
4496
function api_get_item_property_by_tool($tool, $course_code, $session_id = null)
4497
{
4498
    $course_info = api_get_course_info($course_code);
4499
    $tool = Database::escape_string($tool);
4500
4501
    // Definition of tables.
4502
    $item_property_table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4503
    $session_id = (int) $session_id;
4504
    $session_condition = ' AND session_id = '.$session_id;
4505
    if (empty($session_id)) {
4506
        $session_condition = " AND (session_id = 0 OR session_id IS NULL) ";
4507
    }
4508
    $course_id = $course_info['real_id'];
4509
4510
    $sql = "SELECT * FROM $item_property_table
4511
            WHERE
4512
                c_id = $course_id AND
4513
                tool = '$tool'
4514
                $session_condition ";
4515
    $rs = Database::query($sql);
4516
    $list = [];
4517
    if (Database::num_rows($rs) > 0) {
4518
        while ($row = Database::fetch_array($rs, 'ASSOC')) {
4519
            $list[] = $row;
4520
        }
4521
    }
4522
4523
    return $list;
4524
}
4525
4526
/**
4527
 * Gets item property by tool and user.
4528
 *
4529
 * @param int $userId
4530
 * @param int $tool
4531
 * @param int $courseId
4532
 * @param int $session_id
4533
 *
4534
 * @return array
4535
 */
4536
function api_get_item_property_list_by_tool_by_user(
4537
    $userId,
4538
    $tool,
4539
    $courseId,
4540
    $session_id = 0
4541
) {
4542
    $userId = intval($userId);
4543
    $tool = Database::escape_string($tool);
4544
    $session_id = intval($session_id);
4545
    $courseId = intval($courseId);
4546
4547
    // Definition of tables.
4548
    $item_property_table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4549
    $session_condition = ' AND session_id = '.$session_id;
4550
    if (empty($session_id)) {
4551
        $session_condition = " AND (session_id = 0 OR session_id IS NULL) ";
4552
    }
4553
    $sql = "SELECT * FROM $item_property_table
4554
            WHERE
4555
                insert_user_id = $userId AND
4556
                c_id = $courseId AND
4557
                tool = '$tool'
4558
                $session_condition ";
4559
4560
    $rs = Database::query($sql);
4561
    $list = [];
4562
    if (Database::num_rows($rs) > 0) {
4563
        while ($row = Database::fetch_array($rs, 'ASSOC')) {
4564
            $list[] = $row;
4565
        }
4566
    }
4567
4568
    return $list;
4569
}
4570
4571
/**
4572
 * Gets item property id from tool of a course.
4573
 *
4574
 * @param string $course_code course code
4575
 * @param string $tool        tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4576
 * @param int    $ref         id of the item itself, linked to key of every tool ('id', ...), "*" = all items of the tool
4577
 * @param int    $sessionId   Session ID (optional)
4578
 *
4579
 * @return int
4580
 */
4581
function api_get_item_property_id($course_code, $tool, $ref, $sessionId = 0)
4582
{
4583
    $course_info = api_get_course_info($course_code);
4584
    $tool = Database::escape_string($tool);
4585
    $ref = (int) $ref;
4586
4587
    // Definition of tables.
4588
    $tableItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
4589
    $course_id = $course_info['real_id'];
4590
    $sessionId = (int) $sessionId;
4591
    $sessionCondition = " AND session_id = $sessionId ";
4592
    if (empty($sessionId)) {
4593
        $sessionCondition = ' AND (session_id = 0 OR session_id IS NULL) ';
4594
    }
4595
    $sql = "SELECT id FROM $tableItemProperty
4596
            WHERE
4597
                c_id = $course_id AND
4598
                tool = '$tool' AND
4599
                ref = $ref
4600
                $sessionCondition";
4601
    $rs = Database::query($sql);
4602
    $item_property_id = '';
4603
    if (Database::num_rows($rs) > 0) {
4604
        $row = Database::fetch_array($rs);
4605
        $item_property_id = $row['id'];
4606
    }
4607
4608
    return $item_property_id;
4609
}
4610
4611
/**
4612
 * Inserts a record in the track_e_item_property table (No update).
4613
 *
4614
 * @param string $tool
4615
 * @param int    $ref
4616
 * @param string $title
4617
 * @param string $content
4618
 * @param int    $progress
4619
 *
4620
 * @return bool|int
4621
 */
4622
function api_track_item_property_update($tool, $ref, $title, $content, $progress)
4623
{
4624
    $tbl_stats_item_property = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ITEM_PROPERTY);
4625
    $course_id = api_get_course_int_id(); //numeric
4626
    $course_code = api_get_course_id(); //alphanumeric
4627
    $item_property_id = api_get_item_property_id($course_code, $tool, $ref);
4628
    if (!empty($item_property_id)) {
4629
        $sql = "INSERT IGNORE INTO $tbl_stats_item_property SET
4630
                course_id           = '$course_id',
4631
                item_property_id    = '$item_property_id',
4632
                title               = '".Database::escape_string($title)."',
4633
                content             = '".Database::escape_string($content)."',
4634
                progress            = '".intval($progress)."',
4635
                lastedit_date       = '".api_get_utc_datetime()."',
4636
                lastedit_user_id    = '".api_get_user_id()."',
4637
                session_id          = '".api_get_session_id()."'";
4638
        $result = Database::query($sql);
4639
        $affected_rows = Database::affected_rows($result);
4640
4641
        return $affected_rows;
4642
    }
4643
4644
    return false;
4645
}
4646
4647
/**
4648
 * @param string $tool
4649
 * @param int    $ref
4650
 *
4651
 * @return array|resource
4652
 */
4653
function api_get_track_item_property_history($tool, $ref)
4654
{
4655
    $tbl_stats_item_property = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ITEM_PROPERTY);
4656
    $course_id = api_get_course_int_id(); //numeric
4657
    $course_code = api_get_course_id(); //alphanumeric
4658
    $item_property_id = api_get_item_property_id($course_code, $tool, $ref);
4659
    $sql = "SELECT * FROM $tbl_stats_item_property
4660
            WHERE item_property_id = $item_property_id AND course_id = $course_id
4661
            ORDER BY lastedit_date DESC";
4662
    $result = Database::query($sql);
4663
    if ($result === false or $result === null) {
4664
        $result = [];
4665
    } else {
4666
        $result = Database::store_result($result, 'ASSOC');
4667
    }
4668
4669
    return $result;
4670
}
4671
4672
/**
4673
 * Gets item property data from tool of a course id.
4674
 *
4675
 * @param int    $course_id
4676
 * @param string $tool       tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4677
 * @param int    $ref        id of the item itself, linked to key of every tool ('id', ...), "*" = all items of the tool
4678
 * @param int    $session_id
4679
 * @param int    $groupId
4680
 *
4681
 * @return array with all fields from c_item_property, empty array if not found or false if course could not be found
4682
 */
4683
function api_get_item_property_info($course_id, $tool, $ref, $session_id = 0, $groupId = 0)
4684
{
4685
    $courseInfo = api_get_course_info_by_id($course_id);
4686
4687
    if (empty($courseInfo)) {
4688
        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...
4689
    }
4690
4691
    $tool = Database::escape_string($tool);
4692
    $course_id = $courseInfo['real_id'];
4693
    $ref = (int) $ref;
4694
    $session_id = (int) $session_id;
4695
4696
    $sessionCondition = " session_id = $session_id";
4697
    if (empty($session_id)) {
4698
        $sessionCondition = ' (session_id = 0 OR session_id IS NULL) ';
4699
    }
4700
4701
    // Definition of tables.
4702
    $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4703
4704
    $sql = "SELECT * FROM $table
4705
            WHERE
4706
                c_id = $course_id AND
4707
                tool = '$tool' AND
4708
                ref = $ref AND
4709
                $sessionCondition ";
4710
4711
    if (!empty($groupId)) {
4712
        $groupId = (int) $groupId;
4713
        $sql .= " AND to_group_id = $groupId ";
4714
    }
4715
4716
    $rs = Database::query($sql);
4717
    $row = [];
4718
    if (Database::num_rows($rs) > 0) {
4719
        $row = Database::fetch_array($rs, 'ASSOC');
4720
    }
4721
4722
    return $row;
4723
}
4724
4725
/**
4726
 * Displays a combo box so the user can select his/her preferred language.
4727
 *
4728
 * @param string The desired name= value for the select
4729
 * @param bool Whether we use the JQuery Chozen library or not
4730
 * (in some cases, like the indexing language picker, it can alter the presentation)
4731
 *
4732
 * @deprecated
4733
 *
4734
 * @return string
4735
 */
4736
function api_get_languages_combo($name = 'language')
4737
{
4738
    $ret = '';
4739
    $platformLanguage = api_get_setting('platformLanguage');
4740
4741
    // Retrieve a complete list of all the languages.
4742
    $language_list = api_get_languages();
4743
4744
    if (count($language_list) < 2) {
4745
        return $ret;
4746
    }
4747
4748
    // The the current language of the user so that his/her language occurs as selected in the dropdown menu.
4749
    if (isset($_SESSION['user_language_choice'])) {
4750
        $default = $_SESSION['user_language_choice'];
4751
    } else {
4752
        $default = $platformLanguage;
4753
    }
4754
4755
    $ret .= '<select name="'.$name.'" id="language_chosen" class="selectpicker show-tick form-control">';
4756
    foreach ($language_list as $key => $value) {
4757
        if ($key == $default) {
4758
            $selected = ' selected="selected"';
4759
        } else {
4760
            $selected = '';
4761
        }
4762
        $ret .= sprintf('<option value=%s" %s>%s</option>', $key, $selected, $value);
4763
    }
4764
    $ret .= '</select>';
4765
4766
    return $ret;
4767
}
4768
4769
/**
4770
 * @param string $languageIsoCode
4771
 *
4772
 * @return string
4773
 */
4774
function languageToCountryIsoCode($languageIsoCode)
4775
{
4776
    // @todo save in DB
4777
    switch ($languageIsoCode) {
4778
        case 'ko':
4779
            $country = 'kr';
4780
            break;
4781
        case 'ja':
4782
            $country = 'jp';
4783
            break;
4784
        case 'ca':
4785
            $country = 'es';
4786
            break;
4787
        case 'gl':
4788
            $country = 'es';
4789
            break;
4790
        case 'ka':
4791
            $country = 'ge';
4792
            break;
4793
        case 'sl':
4794
            $country = 'si';
4795
            break;
4796
        case 'eu':
4797
            $country = 'es';
4798
            break;
4799
        case 'cs':
4800
            $country = 'cz';
4801
            break;
4802
        case 'el':
4803
            $country = 'ae';
4804
            break;
4805
        case 'ar':
4806
            $country = 'ae';
4807
            break;
4808
        case 'en_US':
4809
        case 'en':
4810
            $country = 'gb';
4811
            break;
4812
        case 'he':
4813
            $country = 'il';
4814
            break;
4815
        case 'uk':
4816
            $country = 'ua'; // Ukraine
4817
            break;
4818
        case 'da':
4819
            $country = 'dk';
4820
            break;
4821
        case 'pt-BR':
4822
            $country = 'br';
4823
            break;
4824
        case 'qu':
4825
            $country = 'pe';
4826
            break;
4827
        case 'sv':
4828
            $country = 'se';
4829
            break;
4830
        case 'zh-TW':
4831
        case 'zh':
4832
            $country = 'cn';
4833
            break;
4834
        default:
4835
            $country = $languageIsoCode;
4836
            break;
4837
    }
4838
    $country = strtolower($country);
4839
4840
    return $country;
4841
}
4842
4843
/**
4844
 * Returns a list of all the languages that are made available by the admin.
4845
 *
4846
 * @return array An array with all languages. Structure of the array is
4847
 *               array['name'] = An array with the name of every language
4848
 *               array['folder'] = An array with the corresponding names of the language-folders in the filesystem
4849
 */
4850
function api_get_languages()
4851
{
4852
    $tbl_language = Database::get_main_table(TABLE_MAIN_LANGUAGE);
4853
    $sql = "SELECT * FROM $tbl_language WHERE available='1' 
4854
            ORDER BY original_name ASC";
4855
    $result = Database::query($sql);
4856
    $languages = [];
4857
    while ($row = Database::fetch_array($result, 'ASSOC')) {
4858
        $languages[$row['isocode']] = $row['original_name'];
4859
    }
4860
4861
    return $languages;
4862
}
4863
4864
/**
4865
 * Returns a list of all the languages that are made available by the admin.
4866
 *
4867
 * @return array
4868
 */
4869
function api_get_languages_to_array()
4870
{
4871
    $tbl_language = Database::get_main_table(TABLE_MAIN_LANGUAGE);
4872
    $sql = "SELECT * FROM $tbl_language WHERE available='1' ORDER BY original_name ASC";
4873
    $result = Database::query($sql);
4874
    $languages = [];
4875
    while ($row = Database::fetch_array($result)) {
4876
        $languages[$row['dokeos_folder']] = $row['original_name'];
4877
    }
4878
4879
    return $languages;
4880
}
4881
4882
/**
4883
 * Returns the id (the database id) of a language.
4884
 *
4885
 * @param   string  language name (the corresponding name of the language-folder in the filesystem)
4886
 *
4887
 * @return int id of the language
4888
 */
4889
function api_get_language_id($language)
4890
{
4891
    $tbl_language = Database::get_main_table(TABLE_MAIN_LANGUAGE);
4892
    if (empty($language)) {
4893
        return null;
4894
    }
4895
    $language = Database::escape_string($language);
4896
    $sql = "SELECT id FROM $tbl_language
4897
            WHERE dokeos_folder = '$language' LIMIT 1";
4898
    $result = Database::query($sql);
4899
    $row = Database::fetch_array($result);
4900
4901
    return $row['id'];
4902
}
4903
4904
/**
4905
 * Get the language information by its id.
4906
 *
4907
 * @param int $languageId
4908
 *
4909
 * @throws Exception
4910
 *
4911
 * @return array
4912
 */
4913
function api_get_language_info($languageId)
4914
{
4915
    if (empty($languageId)) {
4916
        return [];
4917
    }
4918
4919
    $language = Database::getManager()
4920
        ->find('ChamiloCoreBundle:Language', $languageId);
4921
4922
    if (!$language) {
4923
        return [];
4924
    }
4925
4926
    return [
4927
        'id' => $language->getId(),
4928
        'original_name' => $language->getOriginalName(),
4929
        'english_name' => $language->getEnglishName(),
4930
        'isocode' => $language->getIsocode(),
4931
        'dokeos_folder' => $language->getDokeosFolder(),
4932
        'available' => $language->getAvailable(),
4933
        'parent_id' => $language->getParent() ? $language->getParent()->getId() : null,
4934
    ];
4935
}
4936
4937
/**
4938
 * @param string $code
4939
 *
4940
 * @return \Chamilo\CoreBundle\Entity\Language
4941
 */
4942
function api_get_language_from_iso($code)
4943
{
4944
    $em = Database::getManager();
4945
    $language = $em->getRepository('ChamiloCoreBundle:Language')->findOneBy(['isocode' => $code]);
4946
4947
    return $language;
4948
}
4949
4950
/**
4951
 * Returns the name of the visual (CSS) theme to be applied on the current page.
4952
 * The returned name depends on the platform, course or user -wide settings.
4953
 *
4954
 * @return string The visual theme's name, it is the name of a folder inside web/css/themes
4955
 */
4956
function api_get_visual_theme()
4957
{
4958
    static $visual_theme;
4959
    if (!isset($visual_theme)) {
4960
        // Get style directly from DB
4961
        $styleFromDatabase = api_get_settings_params_simple(
4962
            [
4963
                'variable = ? AND access_url = ?' => [
4964
                    'stylesheets',
4965
                    api_get_current_access_url_id(),
4966
                ],
4967
            ]
4968
        );
4969
        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...
4970
            $platform_theme = $styleFromDatabase['selected_value'];
4971
        } else {
4972
            $platform_theme = api_get_setting('stylesheets');
4973
        }
4974
4975
        // Platform's theme.
4976
        $visual_theme = $platform_theme;
4977
        if (api_get_setting('user_selected_theme') == 'true') {
4978
            $user_info = api_get_user_info();
4979
            if (isset($user_info['theme'])) {
4980
                $user_theme = $user_info['theme'];
4981
4982
                if (!empty($user_theme)) {
4983
                    $visual_theme = $user_theme;
4984
                    // User's theme.
4985
                }
4986
            }
4987
        }
4988
4989
        $course_id = api_get_course_id();
4990
        if (!empty($course_id)) {
4991
            if (api_get_setting('allow_course_theme') == 'true') {
4992
                $course_theme = api_get_course_setting('course_theme', $course_id);
4993
4994
                if (!empty($course_theme) && $course_theme != -1) {
4995
                    if (!empty($course_theme)) {
4996
                        // Course's theme.
4997
                        $visual_theme = $course_theme;
4998
                    }
4999
                }
5000
5001
                $allow_lp_theme = api_get_course_setting('allow_learning_path_theme');
5002
                if ($allow_lp_theme == 1) {
5003
                    global $lp_theme_css, $lp_theme_config;
5004
                    // These variables come from the file lp_controller.php.
5005
                    if (!$lp_theme_config) {
5006
                        if (!empty($lp_theme_css)) {
5007
                            // LP's theme.
5008
                            $visual_theme = $lp_theme_css;
5009
                        }
5010
                    }
5011
                }
5012
            }
5013
        }
5014
5015
        if (empty($visual_theme)) {
5016
            $visual_theme = 'chamilo';
5017
        }
5018
5019
        global $lp_theme_log;
5020
        if ($lp_theme_log) {
5021
            $visual_theme = $platform_theme;
5022
        }
5023
    }
5024
5025
    return $visual_theme;
5026
}
5027
5028
/**
5029
 * Returns a list of CSS themes currently available in the CSS folder
5030
 * The folder must have a default.css file.
5031
 *
5032
 * @param bool $getOnlyThemeFromVirtualInstance Used by the vchamilo plugin
5033
 *
5034
 * @return array list of themes directories from the css folder
5035
 *               Note: Directory names (names of themes) in the file system should contain ASCII-characters only
5036
 */
5037
function api_get_themes($getOnlyThemeFromVirtualInstance = false)
5038
{
5039
    // This configuration value is set by the vchamilo plugin
5040
    $virtualTheme = api_get_configuration_value('virtual_css_theme_folder');
5041
5042
    $readCssFolder = function ($dir) use ($virtualTheme) {
5043
        $finder = new Finder();
5044
        $themes = $finder->directories()->in($dir)->depth(0)->sortByName();
5045
        $list = [];
5046
        /** @var Symfony\Component\Finder\SplFileInfo $theme */
5047
        foreach ($themes as $theme) {
5048
            $folder = $theme->getFilename();
5049
            // A theme folder is consider if there's a default.css file
5050
            if (!file_exists($theme->getPathname().'/default.css')) {
5051
                continue;
5052
            }
5053
            $name = ucwords(str_replace('_', ' ', $folder));
5054
            if ($folder == $virtualTheme) {
5055
                continue;
5056
            }
5057
            $list[$folder] = $name;
5058
        }
5059
5060
        return $list;
5061
    };
5062
5063
    $dir = api_get_path(SYS_CSS_PATH).'themes/';
5064
    $list = $readCssFolder($dir);
5065
5066
    if (!empty($virtualTheme)) {
5067
        $newList = $readCssFolder($dir.'/'.$virtualTheme);
5068
        if ($getOnlyThemeFromVirtualInstance) {
5069
            return $newList;
5070
        }
5071
        $list = $list + $newList;
5072
        asort($list);
5073
    }
5074
5075
    return $list;
5076
}
5077
5078
/**
5079
 * Find the largest sort value in a given user_course_category
5080
 * This function is used when we are moving a course to a different category
5081
 * and also when a user subscribes to courses (the new course is added at the end of the main category.
5082
 *
5083
 * @author Patrick Cool <[email protected]>, Ghent University
5084
 *
5085
 * @param int $user_course_category the id of the user_course_category
5086
 * @param int $user_id
5087
 *
5088
 * @return int the value of the highest sort of the user_course_category
5089
 */
5090
function api_max_sort_value($user_course_category, $user_id)
5091
{
5092
    $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
5093
    $sql = "SELECT max(sort) as max_sort FROM $tbl_course_user
5094
            WHERE
5095
                user_id='".intval($user_id)."' AND
5096
                relation_type<>".COURSE_RELATION_TYPE_RRHH." AND
5097
                user_course_cat='".intval($user_course_category)."'";
5098
    $result_max = Database::query($sql);
5099
    if (Database::num_rows($result_max) == 1) {
5100
        $row_max = Database::fetch_array($result_max);
5101
5102
        return $row_max['max_sort'];
5103
    }
5104
5105
    return 0;
5106
}
5107
5108
/**
5109
 * Transforms a number of seconds in hh:mm:ss format.
5110
 *
5111
 * @author Julian Prud'homme
5112
 *
5113
 * @param int the number of seconds
5114
 *
5115
 * @return string the formated time
5116
 */
5117
function api_time_to_hms($seconds, $space = ':')
5118
{
5119
    // $seconds = -1 means that we have wrong data in the db.
5120
    if ($seconds == -1) {
5121
        return
5122
            get_lang('Unknown').
5123
            Display::return_icon(
5124
                'info2.gif',
5125
                get_lang('WrongDatasForTimeSpentOnThePlatform'),
5126
                ['align' => 'absmiddle', 'hspace' => '3px']
5127
            );
5128
    }
5129
5130
    // How many hours ?
5131
    $hours = floor($seconds / 3600);
5132
5133
    // How many minutes ?
5134
    $min = floor(($seconds - ($hours * 3600)) / 60);
5135
5136
    // How many seconds
5137
    $sec = floor($seconds - ($hours * 3600) - ($min * 60));
5138
5139
    if ($hours < 10) {
5140
        $hours = "0$hours";
5141
    }
5142
5143
    if ($sec < 10) {
5144
        $sec = "0$sec";
5145
    }
5146
5147
    if ($min < 10) {
5148
        $min = "0$min";
5149
    }
5150
5151
    return $hours.$space.$min.$space.$sec;
5152
}
5153
5154
/* FILE SYSTEM RELATED FUNCTIONS */
5155
5156
/**
5157
 * Returns the permissions to be assigned to every newly created directory by the web-server.
5158
 * The return value is based on the platform administrator's setting
5159
 * "Administration > Configuration settings > Security > Permissions for new directories".
5160
 *
5161
 * @return int returns the permissions in the format "Owner-Group-Others, Read-Write-Execute", as an integer value
5162
 */
5163
function api_get_permissions_for_new_directories()
5164
{
5165
    static $permissions;
5166
    if (!isset($permissions)) {
5167
        $permissions = trim(api_get_setting('permissions_for_new_directories'));
5168
        // The default value 0777 is according to that in the platform administration panel after fresh system installation.
5169
        $permissions = octdec(!empty($permissions) ? $permissions : '0777');
5170
    }
5171
5172
    return $permissions;
5173
}
5174
5175
/**
5176
 * Returns the permissions to be assigned to every newly created directory by the web-server.
5177
 * The return value is based on the platform administrator's setting
5178
 * "Administration > Configuration settings > Security > Permissions for new files".
5179
 *
5180
 * @return int returns the permissions in the format
5181
 *             "Owner-Group-Others, Read-Write-Execute", as an integer value
5182
 */
5183
function api_get_permissions_for_new_files()
5184
{
5185
    static $permissions;
5186
    if (!isset($permissions)) {
5187
        $permissions = trim(api_get_setting('permissions_for_new_files'));
5188
        // The default value 0666 is according to that in the platform
5189
        // administration panel after fresh system installation.
5190
        $permissions = octdec(!empty($permissions) ? $permissions : '0666');
5191
    }
5192
5193
    return $permissions;
5194
}
5195
5196
/**
5197
 * Deletes a file, or a folder and its contents.
5198
 *
5199
 * @author      Aidan Lister <[email protected]>
5200
 *
5201
 * @version     1.0.3
5202
 *
5203
 * @param string $dirname Directory to delete
5204
 * @param       bool     Deletes only the content or not
5205
 * @param bool $strict if one folder/file fails stop the loop
5206
 *
5207
 * @return bool Returns TRUE on success, FALSE on failure
5208
 *
5209
 * @see http://aidanlister.com/2004/04/recursively-deleting-a-folder-in-php/
5210
 *
5211
 * @author      Yannick Warnier, adaptation for the Chamilo LMS, April, 2008
5212
 * @author      Ivan Tcholakov, a sanity check about Directory class creation has been added, September, 2009
5213
 */
5214
function rmdirr($dirname, $delete_only_content_in_folder = false, $strict = false)
5215
{
5216
    $res = true;
5217
    // A sanity check.
5218
    if (!file_exists($dirname)) {
5219
        return false;
5220
    }
5221
    $php_errormsg = '';
5222
    // Simple delete for a file.
5223
    if (is_file($dirname) || is_link($dirname)) {
5224
        $res = unlink($dirname);
5225
        if ($res === false) {
5226
            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);
5227
        }
5228
5229
        return $res;
5230
    }
5231
5232
    // Loop through the folder.
5233
    $dir = dir($dirname);
5234
    // A sanity check.
5235
    $is_object_dir = is_object($dir);
5236
    if ($is_object_dir) {
5237
        while (false !== $entry = $dir->read()) {
5238
            // Skip pointers.
5239
            if ($entry == '.' || $entry == '..') {
5240
                continue;
5241
            }
5242
5243
            // Recurse.
5244
            if ($strict) {
5245
                $result = rmdirr("$dirname/$entry");
5246
                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...
5247
                    $res = false;
5248
                    break;
5249
                }
5250
            } else {
5251
                rmdirr("$dirname/$entry");
5252
            }
5253
        }
5254
    }
5255
5256
    // Clean up.
5257
    if ($is_object_dir) {
5258
        $dir->close();
5259
    }
5260
5261
    if ($delete_only_content_in_folder == false) {
5262
        $res = rmdir($dirname);
5263
        if ($res === false) {
5264
            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);
5265
        }
5266
    }
5267
5268
    return $res;
5269
}
5270
5271
// TODO: This function is to be simplified. File access modes to be implemented.
5272
/**
5273
 * function adapted from a php.net comment
5274
 * copy recursively a folder.
5275
 *
5276
 * @param the source folder
5277
 * @param the dest folder
5278
 * @param an array of excluded file_name (without extension)
5279
 * @param copied_files the returned array of copied files
5280
 * @param string $source
5281
 * @param string $dest
5282
 */
5283
function copyr($source, $dest, $exclude = [], $copied_files = [])
5284
{
5285
    if (empty($dest)) {
5286
        return false;
5287
    }
5288
    // Simple copy for a file
5289
    if (is_file($source)) {
5290
        $path_info = pathinfo($source);
5291
        if (!in_array($path_info['filename'], $exclude)) {
5292
            copy($source, $dest);
5293
        }
5294
5295
        return true;
5296
    } elseif (!is_dir($source)) {
5297
        //then source is not a dir nor a file, return
5298
        return false;
5299
    }
5300
5301
    // Make destination directory.
5302
    if (!is_dir($dest)) {
5303
        mkdir($dest, api_get_permissions_for_new_directories());
5304
    }
5305
5306
    // Loop through the folder.
5307
    $dir = dir($source);
5308
    while (false !== $entry = $dir->read()) {
5309
        // Skip pointers
5310
        if ($entry == '.' || $entry == '..') {
5311
            continue;
5312
        }
5313
5314
        // Deep copy directories.
5315
        if ($dest !== "$source/$entry") {
5316
            $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

5316
            $files = copyr("$source/$entry", "$dest/$entry", $exclude, /** @scrutinizer ignore-type */ $copied_files);
Loading history...
5317
        }
5318
    }
5319
    // Clean up.
5320
    $dir->close();
5321
5322
    return true;
5323
}
5324
5325
/**
5326
 * @todo: Using DIRECTORY_SEPARATOR is not recommended, this is an obsolete approach.
5327
 * Documentation header to be added here.
5328
 *
5329
 * @param string $pathname
5330
 * @param string $base_path_document
5331
 * @param int    $session_id
5332
 *
5333
 * @return mixed True if directory already exists, false if a file already exists at
5334
 *               the destination and null if everything goes according to plan
5335
 */
5336
function copy_folder_course_session(
5337
    $pathname,
5338
    $base_path_document,
5339
    $session_id,
5340
    $course_info,
5341
    $document,
5342
    $source_course_id
5343
) {
5344
    $table = Database::get_course_table(TABLE_DOCUMENT);
5345
    $session_id = intval($session_id);
5346
    $source_course_id = intval($source_course_id);
5347
5348
    // Check whether directory already exists.
5349
    if (is_dir($pathname) || empty($pathname)) {
5350
        return true;
5351
    }
5352
5353
    // Ensure that a file with the same name does not already exist.
5354
    if (is_file($pathname)) {
5355
        trigger_error('copy_folder_course_session(): File exists', E_USER_WARNING);
5356
5357
        return false;
5358
    }
5359
5360
    $course_id = $course_info['real_id'];
5361
    $folders = explode(DIRECTORY_SEPARATOR, str_replace($base_path_document.DIRECTORY_SEPARATOR, '', $pathname));
5362
    $new_pathname = $base_path_document;
5363
    $path = '';
5364
5365
    foreach ($folders as $folder) {
5366
        $new_pathname .= DIRECTORY_SEPARATOR.$folder;
5367
        $path .= DIRECTORY_SEPARATOR.$folder;
5368
5369
        if (!file_exists($new_pathname)) {
5370
            $path = Database::escape_string($path);
5371
5372
            $sql = "SELECT * FROM $table
5373
                    WHERE
5374
                        c_id = $source_course_id AND
5375
                        path = '$path' AND
5376
                        filetype = 'folder' AND
5377
                        session_id = '$session_id'";
5378
            $rs1 = Database::query($sql);
5379
            $num_rows = Database::num_rows($rs1);
5380
5381
            if ($num_rows == 0) {
5382
                mkdir($new_pathname, api_get_permissions_for_new_directories());
5383
5384
                // Insert new folder with destination session_id.
5385
                $params = [
5386
                    'c_id' => $course_id,
5387
                    'path' => $path,
5388
                    'comment' => $document->comment,
5389
                    'title' => basename($new_pathname),
5390
                    'filetype' => 'folder',
5391
                    'size' => '0',
5392
                    'session_id' => $session_id,
5393
                ];
5394
                $document_id = Database::insert($table, $params);
5395
                if ($document_id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $document_id of type false|integer is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.

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

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

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

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
5396
                    $sql = "UPDATE $table SET id = iid WHERE iid = $document_id";
5397
                    Database::query($sql);
5398
5399
                    api_item_property_update(
5400
                        $course_info,
5401
                        TOOL_DOCUMENT,
5402
                        $document_id,
5403
                        'FolderCreated',
5404
                        api_get_user_id(),
5405
                        0,
5406
                        0,
5407
                        null,
5408
                        null,
5409
                        $session_id
5410
                    );
5411
                }
5412
            }
5413
        }
5414
    } // en foreach
5415
}
5416
5417
// TODO: chmodr() is a better name. Some corrections are needed. Documentation header to be added here.
5418
/**
5419
 * @param string $path
5420
 */
5421
function api_chmod_R($path, $filemode)
5422
{
5423
    if (!is_dir($path)) {
5424
        return chmod($path, $filemode);
5425
    }
5426
5427
    $handler = opendir($path);
5428
    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

5428
    while ($file = readdir(/** @scrutinizer ignore-type */ $handler)) {
Loading history...
5429
        if ($file != '.' && $file != '..') {
5430
            $fullpath = "$path/$file";
5431
            if (!is_dir($fullpath)) {
5432
                if (!chmod($fullpath, $filemode)) {
5433
                    return false;
5434
                }
5435
            } else {
5436
                if (!api_chmod_R($fullpath, $filemode)) {
5437
                    return false;
5438
                }
5439
            }
5440
        }
5441
    }
5442
5443
    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

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

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

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

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

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

8763
    /** @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...
8764
    $additionalParameters = []
8765
) {
8766
    if (!api_valid_email($recipientEmail)) {
8767
        return false;
8768
    }
8769
8770
    // Default values
8771
    $notification = new Notification();
8772
    $defaultEmail = $notification->getDefaultPlatformSenderEmail();
8773
    $defaultName = $notification->getDefaultPlatformSenderName();
8774
8775
    // If the parameter is set don't use the admin.
8776
    $senderName = !empty($senderName) ? $senderName : $defaultName;
8777
    $senderEmail = !empty($senderEmail) ? $senderEmail : $defaultEmail;
8778
8779
    // Reply to first
8780
    $replyToName = '';
8781
    $replyToEmail = '';
8782
    if (isset($extra_headers['reply_to'])) {
8783
        $replyToEmail = $extra_headers['reply_to']['mail'];
8784
        $replyToName = $extra_headers['reply_to']['name'];
8785
    }
8786
8787
    //If the SMTP configuration only accept one sender
8788
    /*if (isset($platform_email['SMTP_UNIQUE_SENDER']) && $platform_email['SMTP_UNIQUE_SENDER']) {
8789
        $senderName = $platform_email['SMTP_FROM_NAME'];
8790
        $senderEmail = $platform_email['SMTP_FROM_EMAIL'];
8791
        $valid = PHPMailer::validateAddress($senderEmail);
8792
        if ($valid) {
8793
            //force-set Sender to $senderEmail, otherwise SetFrom only does it if it is currently empty
8794
            $mail->Sender = $senderEmail;
8795
        }
8796
    }*/
8797
8798
    /*$mail->SetFrom($senderEmail, $senderName);
8799
    $mail->Subject = $subject;
8800
    $mail->AltBody = strip_tags(
8801
        str_replace('<br />', "\n", api_html_entity_decode($message))
8802
    );*/
8803
8804
    /*if (is_array($extra_headers) && count($extra_headers) > 0) {
8805
        foreach ($extra_headers as $key => $value) {
8806
            switch (strtolower($key)) {
8807
                case 'encoding':
8808
                case 'content-transfer-encoding':
8809
                    $mail->Encoding = $value;
8810
                    break;
8811
                case 'charset':
8812
                    $mail->Charset = $value;
8813
                    break;
8814
                case 'contenttype':
8815
                case 'content-type':
8816
                    $mail->ContentType = $value;
8817
                    break;
8818
                default:
8819
                    $mail->AddCustomHeader($key.':'.$value);
8820
                    break;
8821
            }
8822
        }
8823
    } else {
8824
        if (!empty($extra_headers)) {
8825
            $mail->AddCustomHeader($extra_headers);
8826
        }
8827
    }*/
8828
8829
    // WordWrap the html body (phpMailer only fixes AltBody) FS#2988
8830
    //$mail->Body = $mail->WrapText($mail->Body, $mail->WordWrap);
8831
    try {
8832
        $message = new \Swift_Message($subject);
8833
8834
        $list = api_get_configuration_value('send_all_emails_to');
8835
        if (!empty($list) && isset($list['emails'])) {
8836
            foreach ($list['emails'] as $email) {
8837
                $message->addCc($email);
8838
            }
8839
        }
8840
8841
        // Attachment
8842
        if (!empty($data_file)) {
8843
            foreach ($data_file as $file_attach) {
8844
                if (!empty($file_attach['path']) && !empty($file_attach['filename'])) {
8845
                    //$message->attach(Swift_Attachment::fromPath($file_attach['path'], $file_attach['filename']);
8846
                    $message->attach(
8847
                        Swift_Attachment::fromPath($file_attach['path'])->setFilename($file_attach['filename'])
8848
                    );
8849
                }
8850
            }
8851
        }
8852
8853
        $noReply = api_get_setting('noreply_email_address');
8854
        $automaticEmailText = '';
8855
        if (!empty($noReply)) {
8856
            $automaticEmailText = '<br />'.get_lang('ThisIsAutomaticEmailNoReply');
8857
        }
8858
8859
        $params = [
8860
            'content' => '',
8861
            'mail_header_style' => api_get_configuration_value('mail_header_style'),
8862
            'mail_content_style' => api_get_configuration_value('mail_content_style'),
8863
            'link' => $additionalParameters['link'] ?? '',
8864
            'automatic_email_text' => $automaticEmailText,
8865
        ];
8866
8867
        $paramsHtml = $paramsText = $params;
8868
8869
        $paramsHtml['content'] = $body;
8870
        $paramsText['content'] = str_replace('<br />', "\n", api_html_entity_decode($body));
8871
8872
        if (!empty($senderEmail)) {
8873
            $message->setFrom([$senderEmail => $senderName]);
8874
        }
8875
8876
        if (!empty($recipientEmail)) {
8877
            $message->setTo([$recipientEmail => $recipientName]);
8878
        }
8879
8880
        if (!empty($replyToEmail)) {
8881
            $message->setReplyTo([$replyToEmail => $replyToName]);
8882
        }
8883
8884
        $message
8885
            ->setBody(
8886
                Container::getTwig()->render(
8887
                    'ChamiloThemeBundle:Mailer:Default/default.html.twig',
8888
                    $paramsHtml
8889
                ),
8890
                'text/html'
8891
            )
8892
            ->addPart(
8893
                Container::getTwig()->render(
8894
                    'ChamiloThemeBundle:Mailer:Default/default.text.twig',
8895
                    $paramsText
8896
                ),
8897
                'text/plain'
8898
            )
8899
            //->setEncoder(\Swift_Encoding::get8BitEncoding())
8900
        ;
8901
8902
        $type = $message->getHeaders()->get('Content-Type');
8903
        $type->setCharset('utf-8');
8904
        Container::getMailer()->send($message);
8905
8906
        return true;
8907
    } catch (Exception $e) {
8908
        error_log($e->getMessage());
8909
    }
8910
8911
    if (!empty($additionalParameters)) {
8912
        $plugin = new AppPlugin();
8913
        $smsPlugin = $plugin->getSMSPluginLibrary();
8914
        if ($smsPlugin) {
0 ignored issues
show
introduced by
$smsPlugin is of type SmsPluginLibraryInterface, thus it always evaluated to true.
Loading history...
8915
            $smsPlugin->send($additionalParameters);
8916
        }
8917
    }
8918
8919
    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...
8920
}
8921
8922
/**
8923
 * @param string $tool       Possible values: GroupManager::GROUP_TOOL_*
8924
 * @param bool   $showHeader
8925
 */
8926
function api_protect_course_group($tool, $showHeader = true)
8927
{
8928
    $userId = api_get_user_id();
8929
    $groupId = api_get_group_id();
8930
    $groupInfo = GroupManager::get_group_properties($groupId);
8931
8932
    if (!empty($groupInfo)) {
8933
        $allow = GroupManager::user_has_access(
8934
            $userId,
8935
            $groupInfo['iid'],
8936
            $tool
8937
        );
8938
8939
        if (!$allow) {
8940
            api_not_allowed($showHeader);
8941
        }
8942
    }
8943
}
8944
8945
/**
8946
 * Check if a date is in a date range.
8947
 *
8948
 * @param datetime $startDate
8949
 * @param datetime $endDate
8950
 * @param datetime $currentDate
8951
 *
8952
 * @return bool true if date is in rage, false otherwise
8953
 */
8954
function api_is_date_in_date_range($startDate, $endDate, $currentDate = null)
8955
{
8956
    $startDate = strtotime(api_get_local_time($startDate));
8957
    $endDate = strtotime(api_get_local_time($endDate));
8958
    $currentDate = strtotime(api_get_local_time($currentDate));
8959
8960
    if ($currentDate >= $startDate && $currentDate <= $endDate) {
8961
        return true;
8962
    }
8963
8964
    return false;
8965
}
8966
8967
/**
8968
 * Eliminate the duplicates of a multidimensional array by sending the key.
8969
 *
8970
 * @param array $array multidimensional array
8971
 * @param int   $key   key to find to compare
8972
 *
8973
 * @return array
8974
 */
8975
function api_unique_multidim_array($array, $key)
8976
{
8977
    $temp_array = [];
8978
    $i = 0;
8979
    $key_array = [];
8980
8981
    foreach ($array as $val) {
8982
        if (!in_array($val[$key], $key_array)) {
8983
            $key_array[$i] = $val[$key];
8984
            $temp_array[$i] = $val;
8985
        }
8986
        $i++;
8987
    }
8988
8989
    return $temp_array;
8990
}
8991
8992
/**
8993
 * Limit the access to Session Admins when the limit_session_admin_role
8994
 * configuration variable is set to true.
8995
 */
8996
function api_protect_limit_for_session_admin()
8997
{
8998
    $limitAdmin = api_get_setting('limit_session_admin_role');
8999
    if (api_is_session_admin() && $limitAdmin === 'true') {
9000
        api_not_allowed(true);
9001
    }
9002
}
9003
9004
/**
9005
 * Limits that a session admin has access to list users.
9006
 * When limit_session_admin_list_users configuration variable is set to true.
9007
 */
9008
function api_protect_session_admin_list_users()
9009
{
9010
    $limitAdmin = api_get_configuration_value('limit_session_admin_list_users');
9011
9012
    if (api_is_session_admin() && true === $limitAdmin) {
9013
        api_not_allowed(true);
9014
    }
9015
}
9016
9017
/**
9018
 * @return bool
9019
 */
9020
function api_is_student_view_active()
9021
{
9022
    $studentView = Session::read('studentview');
9023
9024
    return $studentView === 'studentview';
9025
}
9026
9027
/**
9028
 * Adds a file inside the upload/$type/id.
9029
 *
9030
 * @param string $type
9031
 * @param array  $file
9032
 * @param int    $itemId
9033
 * @param string $cropParameters
9034
 *
9035
 * @return array|bool
9036
 */
9037
function api_upload_file($type, $file, $itemId, $cropParameters = '')
9038
{
9039
    $upload = process_uploaded_file($file);
9040
    if ($upload) {
9041
        $name = api_replace_dangerous_char($file['name']);
9042
9043
        // No "dangerous" files
9044
        $name = disable_dangerous_file($name);
9045
9046
        $pathId = '/'.substr((string) $itemId, 0, 1).'/'.$itemId.'/';
9047
        $path = api_get_path(SYS_UPLOAD_PATH).$type.$pathId;
9048
9049
        if (!is_dir($path)) {
9050
            mkdir($path, api_get_permissions_for_new_directories(), true);
9051
        }
9052
9053
        $pathToSave = $path.$name;
9054
        $result = moveUploadedFile($file, $pathToSave);
9055
9056
        if ($result) {
9057
            if (!empty($cropParameters)) {
9058
                $image = new Image($pathToSave);
9059
                $image->crop($cropParameters);
9060
            }
9061
9062
            return ['path_to_save' => $pathId.$name];
9063
        }
9064
9065
        return false;
9066
    }
9067
}
9068
9069
/**
9070
 * @param string $type
9071
 * @param int    $itemId
9072
 * @param string $file
9073
 *
9074
 * @return bool
9075
 */
9076
function api_get_uploaded_web_url($type, $itemId, $file)
9077
{
9078
    return api_get_uploaded_file($type, $itemId, $file, true);
9079
}
9080
9081
/**
9082
 * @param string $type
9083
 * @param int    $itemId
9084
 * @param string $file
9085
 * @param bool   $getUrl
9086
 *
9087
 * @return bool
9088
 */
9089
function api_get_uploaded_file($type, $itemId, $file, $getUrl = false)
9090
{
9091
    $itemId = (int) $itemId;
9092
    $pathId = '/'.substr((string) $itemId, 0, 1).'/'.$itemId.'/';
9093
    $path = api_get_path(SYS_UPLOAD_PATH).$type.$pathId;
9094
    $file = basename($file);
9095
    $file = $path.'/'.$file;
9096
    if (Security::check_abs_path($file, $path) && is_file($file) && file_exists($file)) {
9097
        if ($getUrl) {
9098
            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...
9099
        }
9100
9101
        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...
9102
    }
9103
9104
    return false;
9105
}
9106
9107
/**
9108
 * @param string $type
9109
 * @param int    $itemId
9110
 * @param string $file
9111
 * @param string $title
9112
 */
9113
function api_download_uploaded_file($type, $itemId, $file, $title = '')
9114
{
9115
    $file = api_get_uploaded_file($type, $itemId, $file);
9116
    if ($file) {
9117
        if (Security::check_abs_path($file, api_get_path(SYS_UPLOAD_PATH).$type)) {
9118
            DocumentManager::file_send_for_download($file, true, $title);
9119
            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...
9120
        }
9121
    }
9122
    api_not_allowed(true);
9123
}
9124
9125
/**
9126
 * @param string $type
9127
 * @param string $file
9128
 */
9129
function api_remove_uploaded_file($type, $file)
9130
{
9131
    $typePath = api_get_path(SYS_UPLOAD_PATH).$type;
9132
    $path = $typePath.'/'.$file;
9133
    if (Security::check_abs_path($path, $typePath) && file_exists($path) && is_file($path)) {
9134
        unlink($path);
9135
    }
9136
}
9137
9138
/**
9139
 * @param string $type
9140
 * @param int    $itemId
9141
 * @param string $file
9142
 *
9143
 * @return bool
9144
 */
9145
function api_remove_uploaded_file_by_id($type, $itemId, $file)
9146
{
9147
    $file = api_get_uploaded_file($type, $itemId, $file, false);
9148
    $typePath = api_get_path(SYS_UPLOAD_PATH).$type;
9149
    if (Security::check_abs_path($file, $typePath) && file_exists($file) && is_file($file)) {
9150
        unlink($file);
9151
9152
        return true;
9153
    }
9154
9155
    return false;
9156
}
9157
9158
/**
9159
 * Converts string value to float value.
9160
 *
9161
 * 3.141516 => 3.141516
9162
 * 3,141516 => 3.141516
9163
 *
9164
 * @todo WIP
9165
 *
9166
 * @param string $number
9167
 *
9168
 * @return float
9169
 */
9170
function api_float_val($number)
9171
{
9172
    $number = (float) str_replace(',', '.', trim($number));
9173
9174
    return $number;
9175
}
9176
9177
/**
9178
 * Converts float values
9179
 * Example if $decimals = 2.
9180
 *
9181
 * 3.141516 => 3.14
9182
 * 3,141516 => 3,14
9183
 *
9184
 * @param string $number            number in iso code
9185
 * @param int    $decimals
9186
 * @param string $decimalSeparator
9187
 * @param string $thousandSeparator
9188
 *
9189
 * @return bool|string
9190
 */
9191
function api_number_format($number, $decimals = 0, $decimalSeparator = '.', $thousandSeparator = ',')
9192
{
9193
    $number = api_float_val($number);
9194
9195
    return number_format($number, $decimals, $decimalSeparator, $thousandSeparator);
9196
}
9197
9198
/**
9199
 * Set location url with a exit break by default.
9200
 *
9201
 * @param $url
9202
 * @param bool $exit
9203
 */
9204
function location($url, $exit = true)
9205
{
9206
    header('Location: '.$url);
9207
9208
    if ($exit) {
9209
        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...
9210
    }
9211
}
9212
9213
/**
9214
 * @return string
9215
 */
9216
function api_get_web_url()
9217
{
9218
    if (api_get_setting('server_type') === 'test') {
9219
        return api_get_path(WEB_PATH).'web/app_dev.php/';
9220
    } else {
9221
        return api_get_path(WEB_PATH).'web/';
9222
    }
9223
}
9224
9225
/**
9226
 * @param string $from
9227
 * @param string $to
9228
 *
9229
 * @return string
9230
 */
9231
function api_get_relative_path($from, $to)
9232
{
9233
    // some compatibility fixes for Windows paths
9234
    $from = is_dir($from) ? rtrim($from, '\/').'/' : $from;
9235
    $to = is_dir($to) ? rtrim($to, '\/').'/' : $to;
9236
    $from = str_replace('\\', '/', $from);
9237
    $to = str_replace('\\', '/', $to);
9238
9239
    $from = explode('/', $from);
9240
    $to = explode('/', $to);
9241
    $relPath = $to;
9242
9243
    foreach ($from as $depth => $dir) {
9244
        // find first non-matching dir
9245
        if ($dir === $to[$depth]) {
9246
            // ignore this directory
9247
            array_shift($relPath);
9248
        } else {
9249
            // get number of remaining dirs to $from
9250
            $remaining = count($from) - $depth;
9251
            if ($remaining > 1) {
9252
                // add traversals up to first matching dir
9253
                $padLength = (count($relPath) + $remaining - 1) * -1;
9254
                $relPath = array_pad($relPath, $padLength, '..');
9255
                break;
9256
            } else {
9257
                $relPath[0] = './'.$relPath[0];
9258
            }
9259
        }
9260
    }
9261
9262
    return implode('/', $relPath);
9263
}
9264
9265
/**
9266
 * Unserialize content using Brummann\Polyfill\Unserialize.
9267
 *
9268
 * @param string $type
9269
 * @param string $serialized
9270
 * @param bool   $ignoreErrors. Optional.
9271
 *
9272
 * @return mixed
9273
 */
9274
function api_unserialize_content($type, $serialized, $ignoreErrors = false)
9275
{
9276
    switch ($type) {
9277
        case 'career':
9278
        case 'sequence_graph':
9279
            $allowedClasses = [Graph::class, VerticesMap::class, Vertices::class, Edges::class];
9280
            break;
9281
        case 'lp':
9282
            $allowedClasses = [
9283
                learnpath::class,
9284
                learnpathItem::class,
9285
                aicc::class,
9286
                aiccBlock::class,
9287
                aiccItem::class,
9288
                aiccObjective::class,
9289
                aiccResource::class,
9290
                scorm::class,
9291
                scormItem::class,
9292
                scormMetadata::class,
9293
                scormOrganization::class,
9294
                scormResource::class,
9295
                Link::class,
9296
                LpItem::class,
9297
            ];
9298
            break;
9299
        case 'course':
9300
            $allowedClasses = [
9301
                Course::class,
9302
                Announcement::class,
9303
                Attendance::class,
9304
                CalendarEvent::class,
9305
                CourseCopyLearnpath::class,
9306
                CourseCopyTestCategory::class,
9307
                CourseDescription::class,
9308
                CourseSession::class,
9309
                Document::class,
9310
                Forum::class,
9311
                ForumCategory::class,
9312
                ForumPost::class,
9313
                ForumTopic::class,
9314
                Glossary::class,
9315
                GradeBookBackup::class,
9316
                Link::class,
9317
                LinkCategory::class,
9318
                Quiz::class,
9319
                QuizQuestion::class,
9320
                QuizQuestionOption::class,
9321
                ScormDocument::class,
9322
                Survey::class,
9323
                SurveyInvitation::class,
9324
                SurveyQuestion::class,
9325
                Thematic::class,
9326
                ToolIntro::class,
9327
                Wiki::class,
9328
                Work::class,
9329
                stdClass::class,
9330
            ];
9331
            break;
9332
        case 'not_allowed_classes':
9333
        default:
9334
            $allowedClasses = false;
9335
    }
9336
9337
    if ($ignoreErrors) {
9338
        return @Unserialize::unserialize(
9339
            $serialized,
9340
            ['allowed_classes' => $allowedClasses]
9341
        );
9342
    }
9343
9344
    return Unserialize::unserialize(
9345
        $serialized,
9346
        ['allowed_classes' => $allowedClasses]
9347
    );
9348
}
9349
9350
/**
9351
 * Set the From and ReplyTo properties to PHPMailer instance.
9352
 *
9353
 * @param PHPMailer $mailer
9354
 * @param array     $sender
9355
 * @param array     $replyToAddress
9356
 *
9357
 * @throws phpmailerException
9358
 */
9359
function api_set_noreply_and_from_address_to_mailer(PHPMailer $mailer, array $sender, array $replyToAddress = [])
9360
{
9361
    $platformEmail = $GLOBALS['platform_email'];
9362
9363
    $noReplyAddress = api_get_setting('noreply_email_address');
9364
    $avoidReplyToAddress = false;
9365
9366
    if (!empty($noReplyAddress)) {
9367
        $avoidReplyToAddress = api_get_configuration_value('mail_no_reply_avoid_reply_to');
9368
    }
9369
9370
    $notification = new Notification();
9371
9372
    // If the parameter is set don't use the admin.
9373
    $senderName = !empty($sender['name']) ? $sender['name'] : $notification->getDefaultPlatformSenderName();
9374
    $senderEmail = !empty($sender['email']) ? $sender['email'] : $notification->getDefaultPlatformSenderEmail();
9375
9376
    // Reply to first
9377
    if (!$avoidReplyToAddress) {
9378
        $mailer->AddCustomHeader('Errors-To: '.$notification->getDefaultPlatformSenderEmail());
9379
9380
        if (
9381
            !empty($replyToAddress) &&
9382
            $platformEmail['SMTP_UNIQUE_REPLY_TO'] &&
9383
            PHPMailer::ValidateAddress($replyToAddress['mail'])
9384
        ) {
9385
            $mailer->AddReplyTo($replyToAddress['email'], $replyToAddress['name']);
9386
            // Errors to sender
9387
            $mailer->AddCustomHeader('Errors-To: '.$replyToAddress['mail']);
9388
            $mailer->Sender = $replyToAddress['mail'];
9389
        }
9390
    }
9391
9392
    //If the SMTP configuration only accept one sender
9393
    if (
9394
        isset($platformEmail['SMTP_UNIQUE_SENDER']) &&
9395
        $platformEmail['SMTP_UNIQUE_SENDER']
9396
    ) {
9397
        $senderName = $platformEmail['SMTP_FROM_NAME'];
9398
        $senderEmail = $platformEmail['SMTP_FROM_EMAIL'];
9399
9400
        if (PHPMailer::ValidateAddress($senderEmail)) {
9401
            //force-set Sender to $senderEmail, otherwise SetFrom only does it if it is currently empty
9402
            $mailer->Sender = $senderEmail;
9403
        }
9404
    }
9405
9406
    $mailer->SetFrom($senderEmail, $senderName, !$avoidReplyToAddress);
9407
}
9408
9409
/**
9410
 * @param string $template
9411
 *
9412
 * @return string
9413
 */
9414
function api_find_template($template)
9415
{
9416
    return Template::findTemplateFilePath($template);
9417
}
9418
9419
/**
9420
 * @return array
9421
 */
9422
function api_get_language_list_for_flag()
9423
{
9424
    $table = Database::get_main_table(TABLE_MAIN_LANGUAGE);
9425
    $sql = "SELECT english_name, isocode FROM $table 
9426
            ORDER BY original_name ASC";
9427
    static $languages = [];
9428
    if (empty($languages)) {
9429
        $result = Database::query($sql);
9430
        while ($row = Database::fetch_array($result)) {
9431
            $languages[$row['english_name']] = $row['isocode'];
9432
        }
9433
        $languages['english'] = 'gb';
9434
    }
9435
9436
    return $languages;
9437
}
9438
9439
/**
9440
 * @return string
9441
 */
9442
function api_get_language_translate_html()
9443
{
9444
    $translate = api_get_configuration_value('translate_html');
9445
9446
    if (!$translate) {
9447
        return '';
9448
    }
9449
9450
    $languageList = api_get_languages();
9451
    $hideAll = '';
9452
    foreach ($languageList['all'] as $language) {
9453
        $hideAll .=
9454
            '$("span:lang('.$language['isocode'].')").filter(
9455
                function() {
9456
                    // Ignore ckeditor classes
9457
                    return !this.className.match(/cke(.*)/);
9458
            }).hide();';
9459
    }
9460
9461
    $userInfo = api_get_user_info();
9462
    $languageId = api_get_language_id($userInfo['language']);
9463
    $languageInfo = api_get_language_info($languageId);
9464
9465
    return '
9466
            $(function() {
9467
                '.$hideAll.'                 
9468
                var defaultLanguageFromUser = "'.$languageInfo['isocode'].'";   
9469
                                             
9470
                $("span:lang('.$languageInfo['isocode'].')").filter(
9471
                    function() {
9472
                        // Ignore ckeditor classes
9473
                        return !this.className.match(/cke(.*)/);
9474
                }).show();
9475
                
9476
                var defaultLanguage = "";
9477
                var langFromUserFound = false;
9478
                
9479
                $(this).find("span").filter(
9480
                    function() {
9481
                        // Ignore ckeditor classes
9482
                        return !this.className.match(/cke(.*)/);
9483
                }).each(function() {
9484
                    defaultLanguage = $(this).attr("lang");                            
9485
                    if (defaultLanguage) {
9486
                        $(this).before().next("br").remove();                
9487
                        if (defaultLanguageFromUser == defaultLanguage) {
9488
                            langFromUserFound = true;
9489
                        }
9490
                    }
9491
                });
9492
                
9493
                // Show default language
9494
                if (langFromUserFound == false && defaultLanguage) {
9495
                    $("span:lang("+defaultLanguage+")").filter(
9496
                    function() {
9497
                            // Ignore ckeditor classes
9498
                            return !this.className.match(/cke(.*)/);
9499
                    }).show();
9500
                }
9501
            });
9502
    ';
9503
}
9504