Completed
Push — master ( 57664d...2bb74b )
by Julito
10:27
created

api_time_to_hms()   D

Complexity

Conditions 14
Paths 273

Size

Total Lines 58
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 14
eloc 29
nc 273
nop 4
dl 0
loc 58
rs 4.5208
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
/* For licensing terms, see /license.txt */
3
4
use Chamilo\CoreBundle\Entity\AccessUrl;
5
use Chamilo\CoreBundle\Entity\Course;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Course. Consider defining an alias.

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

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

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

// Bar.php
namespace OtherDir;

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

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

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

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

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
6
use Chamilo\CoreBundle\Entity\Session as SessionEntity;
7
use Chamilo\CoreBundle\Entity\SettingsCurrent;
8
use Chamilo\CoreBundle\Framework\Container;
9
use Chamilo\CourseBundle\Entity\CItemProperty;
10
use Chamilo\ThemeBundle\Controller\ExceptionController;
11
use Chamilo\UserBundle\Entity\User;
12
use ChamiloSession as Session;
13
use Symfony\Component\Debug\Exception\FlattenException;
14
use Symfony\Component\Finder\Finder;
15
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
16
17
/**
18
 * This is a code library for Chamilo.
19
 * It is included by default in every Chamilo file (through including the global.inc.php)
20
 * This library is in process of being transferred to src/Chamilo/CoreBundle/Component/Utils/ChamiloApi.
21
 * Whenever a function is transferred to the ChamiloApi class, the places where it is used should include
22
 * the "use Chamilo\CoreBundle\Component\Utils\ChamiloApi;" statement.
23
 *
24
 * @package chamilo.library
25
 */
26
27
// PHP version requirement.
28
define('REQUIRED_PHP_VERSION', '7.2');
29
define('REQUIRED_MIN_MEMORY_LIMIT', '128');
30
define('REQUIRED_MIN_UPLOAD_MAX_FILESIZE', '10');
31
define('REQUIRED_MIN_POST_MAX_SIZE', '10');
32
33
// USER STATUS CONSTANTS
34
/** global status of a user: student */
35
define('STUDENT', 5);
36
/** global status of a user: course manager */
37
define('COURSEMANAGER', 1);
38
/** global status of a user: session admin */
39
define('SESSIONADMIN', 3);
40
/** global status of a user: human ressource manager */
41
define('DRH', 4);
42
/** global status of a user: human ressource manager */
43
define('ANONYMOUS', 6);
44
/** global status of a user: low security, necessary for inserting data from
45
 * the teacher through HTMLPurifier */
46
define('COURSEMANAGERLOWSECURITY', 10);
47
// Soft user status
48
define('PLATFORM_ADMIN', 11);
49
define('SESSION_COURSE_COACH', 12);
50
define('SESSION_GENERAL_COACH', 13);
51
define('COURSE_STUDENT', 14); //student subscribed in a course
52
define('SESSION_STUDENT', 15); //student subscribed in a session course
53
define('COURSE_TUTOR', 16); // student is tutor of a course (NOT in session)
54
define('STUDENT_BOSS', 17); // student is boss
55
define('INVITEE', 20);
56
define('HRM_REQUEST', 21); //HRM has request for vinculation with user
57
58
// Table of status
59
$_status_list[COURSEMANAGER] = 'teacher'; // 1
60
$_status_list[SESSIONADMIN] = 'session_admin'; // 3
61
$_status_list[DRH] = 'drh'; // 4
62
$_status_list[STUDENT] = 'user'; // 5
63
$_status_list[ANONYMOUS] = 'anonymous'; // 6
64
$_status_list[INVITEE] = 'invited'; // 20
65
66
// COURSE VISIBILITY CONSTANTS
67
/** only visible for course admin */
68
define('COURSE_VISIBILITY_CLOSED', 0);
69
/** only visible for users registered in the course */
70
define('COURSE_VISIBILITY_REGISTERED', 1);
71
/** Open for all registered users on the platform */
72
define('COURSE_VISIBILITY_OPEN_PLATFORM', 2);
73
/** Open for the whole world */
74
define('COURSE_VISIBILITY_OPEN_WORLD', 3);
75
/** Invisible to all except admin */
76
define('COURSE_VISIBILITY_HIDDEN', 4);
77
78
define('COURSE_REQUEST_PENDING', 0);
79
define('COURSE_REQUEST_ACCEPTED', 1);
80
define('COURSE_REQUEST_REJECTED', 2);
81
define('DELETE_ACTION_ENABLED', false);
82
83
// EMAIL SENDING RECIPIENT CONSTANTS
84
define('SEND_EMAIL_EVERYONE', 1);
85
define('SEND_EMAIL_STUDENTS', 2);
86
define('SEND_EMAIL_TEACHERS', 3);
87
88
// SESSION VISIBILITY CONSTANTS
89
define('SESSION_VISIBLE_READ_ONLY', 1);
90
define('SESSION_VISIBLE', 2);
91
define('SESSION_INVISIBLE', 3); // not available
92
define('SESSION_AVAILABLE', 4);
93
94
define('SESSION_LINK_TARGET', '_self');
95
96
define('SUBSCRIBE_ALLOWED', 1);
97
define('SUBSCRIBE_NOT_ALLOWED', 0);
98
define('UNSUBSCRIBE_ALLOWED', 1);
99
define('UNSUBSCRIBE_NOT_ALLOWED', 0);
100
101
// SURVEY VISIBILITY CONSTANTS
102
define('SURVEY_VISIBLE_TUTOR', 0);
103
define('SURVEY_VISIBLE_TUTOR_STUDENT', 1);
104
define('SURVEY_VISIBLE_PUBLIC', 2);
105
106
// CONSTANTS defining all tools, using the english version
107
/* When you add a new tool you must add it into function api_get_tools_lists() too */
108
define('TOOL_DOCUMENT', 'document');
109
define('TOOL_LP_FINAL_ITEM', 'final_item');
110
define('TOOL_READOUT_TEXT', 'readout_text');
111
define('TOOL_THUMBNAIL', 'thumbnail');
112
define('TOOL_HOTPOTATOES', 'hotpotatoes');
113
define('TOOL_CALENDAR_EVENT', 'calendar_event');
114
define('TOOL_LINK', 'link');
115
define('TOOL_LINK_CATEGORY', 'link_category');
116
define('TOOL_COURSE_DESCRIPTION', 'course_description');
117
define('TOOL_SEARCH', 'search');
118
define('TOOL_LEARNPATH', 'learnpath');
119
define('TOOL_LEARNPATH_CATEGORY', 'learnpath_category');
120
define('TOOL_AGENDA', 'agenda');
121
define('TOOL_ANNOUNCEMENT', 'announcement');
122
define('TOOL_FORUM', 'forum');
123
define('TOOL_FORUM_CATEGORY', 'forum_category');
124
define('TOOL_FORUM_THREAD', 'forum_thread');
125
define('TOOL_FORUM_POST', 'forum_post');
126
define('TOOL_FORUM_ATTACH', 'forum_attachment');
127
define('TOOL_FORUM_THREAD_QUALIFY', 'forum_thread_qualify');
128
define('TOOL_THREAD', 'thread');
129
define('TOOL_POST', 'post');
130
define('TOOL_DROPBOX', 'dropbox');
131
define('TOOL_QUIZ', 'quiz');
132
define('TOOL_TEST_CATEGORY', 'test_category');
133
define('TOOL_USER', 'user');
134
define('TOOL_GROUP', 'group');
135
define('TOOL_BLOGS', 'blog_management');
136
define('TOOL_CHAT', 'chat');
137
define('TOOL_STUDENTPUBLICATION', 'student_publication');
138
define('TOOL_TRACKING', 'tracking');
139
define('TOOL_HOMEPAGE_LINK', 'homepage_link');
140
define('TOOL_COURSE_SETTING', 'course_setting');
141
define('TOOL_BACKUP', 'backup');
142
define('TOOL_COPY_COURSE_CONTENT', 'copy_course_content');
143
define('TOOL_RECYCLE_COURSE', 'recycle_course');
144
define('TOOL_COURSE_HOMEPAGE', 'course_homepage');
145
define('TOOL_COURSE_RIGHTS_OVERVIEW', 'course_rights');
146
define('TOOL_UPLOAD', 'file_upload');
147
define('TOOL_COURSE_MAINTENANCE', 'course_maintenance');
148
define('TOOL_SURVEY', 'survey');
149
define('TOOL_WIKI', 'wiki');
150
define('TOOL_GLOSSARY', 'glossary');
151
define('TOOL_GRADEBOOK', 'gradebook');
152
define('TOOL_NOTEBOOK', 'notebook');
153
define('TOOL_ATTENDANCE', 'attendance');
154
define('TOOL_COURSE_PROGRESS', 'course_progress');
155
define('TOOL_PORTFOLIO', 'portfolio');
156
define('TOOL_PLAGIARISM', 'compilatio');
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
// iconv extension, for PHP5 on Windows it is installed by default.
301
define('ICONV_INSTALLED', function_exists('iconv'));
302
define('MBSTRING_INSTALLED', function_exists('mb_strlen')); // mbstring extension.
303
304
// Patterns for processing paths. Examples.
305
define('REPEATED_SLASHES_PURIFIER', '/\/{2,}/'); // $path = preg_replace(REPEATED_SLASHES_PURIFIER, '/', $path);
306
define('VALID_WEB_PATH', '/https?:\/\/[^\/]*(\/.*)?/i'); // $is_valid_path = preg_match(VALID_WEB_PATH, $path);
307
// $new_path = preg_replace(VALID_WEB_SERVER_BASE, $new_base, $path);
308
define('VALID_WEB_SERVER_BASE', '/https?:\/\/[^\/]*/i');
309
// Constants for api_get_path() and api_get_path_type(), etc. - registered path types.
310
// basic (leaf elements)
311
define('REL_CODE_PATH', 'REL_CODE_PATH');
312
define('REL_COURSE_PATH', 'REL_COURSE_PATH');
313
define('REL_HOME_PATH', 'REL_HOME_PATH');
314
315
// Constants for api_get_path() and api_get_path_type(), etc. - registered path types.
316
define('WEB_PATH', 'WEB_PATH');
317
define('SYS_PATH', 'SYS_PATH');
318
define('SYS_APP_PATH', 'SYS_APP_PATH');
319
define('SYS_UPLOAD_PATH', 'SYS_UPLOAD_PATH');
320
define('WEB_UPLOAD_PATH', 'WEB_UPLOAD_PATH');
321
322
define('REL_PATH', 'REL_PATH');
323
define('WEB_COURSE_PATH', 'WEB_COURSE_PATH');
324
define('SYS_COURSE_PATH', 'SYS_COURSE_PATH');
325
define('WEB_CODE_PATH', 'WEB_CODE_PATH');
326
define('SYS_CODE_PATH', 'SYS_CODE_PATH');
327
define('SYS_LANG_PATH', 'SYS_LANG_PATH');
328
define('WEB_IMG_PATH', 'WEB_IMG_PATH');
329
define('WEB_CSS_PATH', 'WEB_CSS_PATH');
330
define('WEB_PUBLIC_PATH', 'WEB_PUBLIC_PATH');
331
define('SYS_CSS_PATH', 'SYS_CSS_PATH');
332
define('SYS_PLUGIN_PATH', 'SYS_PLUGIN_PATH');
333
define('WEB_PLUGIN_PATH', 'WEB_PLUGIN_PATH');
334
define('WEB_PLUGIN_ASSET_PATH', 'WEB_PLUGIN_ASSET_PATH');
335
define('SYS_ARCHIVE_PATH', 'SYS_ARCHIVE_PATH');
336
define('WEB_ARCHIVE_PATH', 'WEB_ARCHIVE_PATH');
337
define('SYS_INC_PATH', 'SYS_INC_PATH');
338
define('LIBRARY_PATH', 'LIBRARY_PATH');
339
define('CONFIGURATION_PATH', 'CONFIGURATION_PATH');
340
define('WEB_LIBRARY_PATH', 'WEB_LIBRARY_PATH');
341
define('WEB_LIBRARY_JS_PATH', 'WEB_LIBRARY_JS_PATH');
342
define('WEB_AJAX_PATH', 'WEB_AJAX_PATH');
343
define('SYS_TEST_PATH', 'SYS_TEST_PATH');
344
define('WEB_TEMPLATE_PATH', 'WEB_TEMPLATE_PATH');
345
define('SYS_TEMPLATE_PATH', 'SYS_TEMPLATE_PATH');
346
define('SYS_PUBLIC_PATH', 'SYS_PUBLIC_PATH');
347
define('SYS_HOME_PATH', 'SYS_HOME_PATH');
348
define('WEB_HOME_PATH', 'WEB_HOME_PATH');
349
define('WEB_FONTS_PATH', 'WEB_FONTS_PATH');
350
define('SYS_FONTS_PATH', 'SYS_FONTS_PATH');
351
352
// Relations type with Course manager
353
define('COURSE_RELATION_TYPE_COURSE_MANAGER', 1);
354
define('SESSION_RELATION_TYPE_COURSE_MANAGER', 1);
355
356
// Relations type with Human resources manager
357
define('COURSE_RELATION_TYPE_RRHH', 1);
358
define('SESSION_RELATION_TYPE_RRHH', 1);
359
360
//User image sizes
361
define('USER_IMAGE_SIZE_ORIGINAL', 1);
362
define('USER_IMAGE_SIZE_BIG', 2);
363
define('USER_IMAGE_SIZE_MEDIUM', 3);
364
define('USER_IMAGE_SIZE_SMALL', 4);
365
366
// Relation type between users
367
define('USER_UNKNOWN', 0);
368
define('USER_RELATION_TYPE_UNKNOWN', 1);
369
define('USER_RELATION_TYPE_PARENT', 2); // should be deprecated is useless
370
define('USER_RELATION_TYPE_FRIEND', 3);
371
define('USER_RELATION_TYPE_GOODFRIEND', 4); // should be deprecated is useless
372
define('USER_RELATION_TYPE_ENEMY', 5); // should be deprecated is useless
373
define('USER_RELATION_TYPE_DELETED', 6);
374
define('USER_RELATION_TYPE_RRHH', 7);
375
define('USER_RELATION_TYPE_BOSS', 8);
376
define('USER_RELATION_TYPE_HRM_REQUEST', 9);
377
378
// Gradebook link constants
379
// Please do not change existing values, they are used in the database !
380
define('GRADEBOOK_ITEM_LIMIT', 1000);
381
382
define('LINK_EXERCISE', 1);
383
define('LINK_DROPBOX', 2);
384
define('LINK_STUDENTPUBLICATION', 3);
385
define('LINK_LEARNPATH', 4);
386
define('LINK_FORUM_THREAD', 5);
387
//define('LINK_WORK',6);
388
define('LINK_ATTENDANCE', 7);
389
define('LINK_SURVEY', 8);
390
define('LINK_HOTPOTATOES', 9);
391
392
// Score display types constants
393
define('SCORE_DIV', 1); // X / Y
394
define('SCORE_PERCENT', 2); // XX %
395
define('SCORE_DIV_PERCENT', 3); // X / Y (XX %)
396
define('SCORE_AVERAGE', 4); // XX %
397
define('SCORE_DECIMAL', 5); // 0.50  (X/Y)
398
define('SCORE_BAR', 6); // Uses the Display::bar_progress function
399
define('SCORE_SIMPLE', 7); // X
400
define('SCORE_IGNORE_SPLIT', 8); //  ??
401
define('SCORE_DIV_PERCENT_WITH_CUSTOM', 9); // X / Y (XX %) - Good!
402
define('SCORE_CUSTOM', 10); // Good!
403
define('SCORE_DIV_SIMPLE_WITH_CUSTOM', 11); // X - Good!
404
define('SCORE_DIV_SIMPLE_WITH_CUSTOM_LETTERS', 12); // X - Good!
405
define('SCORE_ONLY_SCORE', 13); // X - Good!
406
define('SCORE_NUMERIC', 14);
407
408
define('SCORE_BOTH', 1);
409
define('SCORE_ONLY_DEFAULT', 2);
410
define('SCORE_ONLY_CUSTOM', 3);
411
412
// From display.lib.php
413
414
define('MAX_LENGTH_BREADCRUMB', 100);
415
define('ICON_SIZE_ATOM', 8);
416
define('ICON_SIZE_TINY', 16);
417
define('ICON_SIZE_SMALL', 22);
418
define('ICON_SIZE_MEDIUM', 32);
419
define('ICON_SIZE_LARGE', 48);
420
define('ICON_SIZE_BIG', 64);
421
define('ICON_SIZE_HUGE', 128);
422
define('SHOW_TEXT_NEAR_ICONS', false);
423
424
// Session catalog
425
define('CATALOG_COURSES', 0);
426
define('CATALOG_SESSIONS', 1);
427
define('CATALOG_COURSES_SESSIONS', 2);
428
429
// Hook type events, pre-process and post-process.
430
// All means to be executed for both hook event types
431
define('HOOK_EVENT_TYPE_PRE', 0);
432
define('HOOK_EVENT_TYPE_POST', 1);
433
define('HOOK_EVENT_TYPE_ALL', 10);
434
435
define('CAREER_STATUS_ACTIVE', 1);
436
define('CAREER_STATUS_INACTIVE', 0);
437
438
define('PROMOTION_STATUS_ACTIVE', 1);
439
define('PROMOTION_STATUS_INACTIVE', 0);
440
441
// Group permissions
442
define('GROUP_PERMISSION_OPEN', '1');
443
define('GROUP_PERMISSION_CLOSED', '2');
444
445
// Group user permissions
446
define('GROUP_USER_PERMISSION_ADMIN', '1'); // the admin of a group
447
define('GROUP_USER_PERMISSION_READER', '2'); // a normal user
448
define('GROUP_USER_PERMISSION_PENDING_INVITATION', '3'); // When an admin/moderator invites a user
449
define('GROUP_USER_PERMISSION_PENDING_INVITATION_SENT_BY_USER', '4'); // an user joins a group
450
define('GROUP_USER_PERMISSION_MODERATOR', '5'); // a moderator
451
define('GROUP_USER_PERMISSION_ANONYMOUS', '6'); // an anonymous user
452
define('GROUP_USER_PERMISSION_HRM', '7'); // a human resources manager
453
454
define('GROUP_IMAGE_SIZE_ORIGINAL', 1);
455
define('GROUP_IMAGE_SIZE_BIG', 2);
456
define('GROUP_IMAGE_SIZE_MEDIUM', 3);
457
define('GROUP_IMAGE_SIZE_SMALL', 4);
458
define('GROUP_TITLE_LENGTH', 50);
459
460
// Exercise
461
// @todo move into a class
462
define('ALL_ON_ONE_PAGE', 1);
463
define('ONE_PER_PAGE', 2);
464
465
define('EXERCISE_FEEDBACK_TYPE_END', 0); //Feedback 		 - show score and expected answers
466
define('EXERCISE_FEEDBACK_TYPE_DIRECT', 1); //DirectFeedback - Do not show score nor answers
467
define('EXERCISE_FEEDBACK_TYPE_EXAM', 2); // NoFeedback 	 - Show score only
468
define('EXERCISE_FEEDBACK_TYPE_POPUP', 3); // Popup BT#15827
469
470
define('RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS', 0); //show score and expected answers
471
define('RESULT_DISABLE_NO_SCORE_AND_EXPECTED_ANSWERS', 1); //Do not show score nor answers
472
define('RESULT_DISABLE_SHOW_SCORE_ONLY', 2); //Show score only
473
define('RESULT_DISABLE_SHOW_FINAL_SCORE_ONLY_WITH_CATEGORIES', 3); //Show final score only with categories
474
define('RESULT_DISABLE_SHOW_SCORE_ATTEMPT_SHOW_ANSWERS_LAST_ATTEMPT', 4);
475
define('RESULT_DISABLE_DONT_SHOW_SCORE_ONLY_IF_USER_FINISHES_ATTEMPTS_SHOW_ALWAYS_FEEDBACK', 5);
476
define('RESULT_DISABLE_RANKING', 6);
477
define('RESULT_DISABLE_SHOW_ONLY_IN_CORRECT_ANSWER', 7);
478
define('RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS_AND_RANKING', 8);
479
480
define('EXERCISE_MAX_NAME_SIZE', 80);
481
482
// Question types (edit next array as well when adding values)
483
// @todo move into a class
484
define('UNIQUE_ANSWER', 1);
485
define('MULTIPLE_ANSWER', 2);
486
define('FILL_IN_BLANKS', 3);
487
define('MATCHING', 4);
488
define('FREE_ANSWER', 5);
489
define('HOT_SPOT', 6);
490
define('HOT_SPOT_ORDER', 7);
491
define('HOT_SPOT_DELINEATION', 8);
492
define('MULTIPLE_ANSWER_COMBINATION', 9);
493
define('UNIQUE_ANSWER_NO_OPTION', 10);
494
define('MULTIPLE_ANSWER_TRUE_FALSE', 11);
495
define('MULTIPLE_ANSWER_COMBINATION_TRUE_FALSE', 12);
496
define('ORAL_EXPRESSION', 13);
497
define('GLOBAL_MULTIPLE_ANSWER', 14);
498
define('MEDIA_QUESTION', 15);
499
define('CALCULATED_ANSWER', 16);
500
define('UNIQUE_ANSWER_IMAGE', 17);
501
define('DRAGGABLE', 18);
502
define('MATCHING_DRAGGABLE', 19);
503
define('ANNOTATION', 20);
504
define('READING_COMPREHENSION', 21);
505
define('MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY', 22);
506
507
define('EXERCISE_CATEGORY_RANDOM_SHUFFLED', 1);
508
define('EXERCISE_CATEGORY_RANDOM_ORDERED', 2);
509
define('EXERCISE_CATEGORY_RANDOM_DISABLED', 0);
510
511
// Question selection type
512
define('EX_Q_SELECTION_ORDERED', 1);
513
define('EX_Q_SELECTION_RANDOM', 2);
514
define('EX_Q_SELECTION_CATEGORIES_ORDERED_QUESTIONS_ORDERED', 3);
515
define('EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_ORDERED', 4);
516
define('EX_Q_SELECTION_CATEGORIES_ORDERED_QUESTIONS_RANDOM', 5);
517
define('EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_RANDOM', 6);
518
define('EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_ORDERED_NO_GROUPED', 7);
519
define('EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_RANDOM_NO_GROUPED', 8);
520
define('EX_Q_SELECTION_CATEGORIES_ORDERED_BY_PARENT_QUESTIONS_ORDERED', 9);
521
define('EX_Q_SELECTION_CATEGORIES_ORDERED_BY_PARENT_QUESTIONS_RANDOM', 10);
522
523
// Used to save the skill_rel_item table
524
define('ITEM_TYPE_EXERCISE', 1);
525
define('ITEM_TYPE_HOTPOTATOES', 2);
526
define('ITEM_TYPE_LINK', 3);
527
define('ITEM_TYPE_LEARNPATH', 4);
528
define('ITEM_TYPE_GRADEBOOK', 5);
529
define('ITEM_TYPE_STUDENT_PUBLICATION', 6);
530
//define('ITEM_TYPE_FORUM', 7);
531
define('ITEM_TYPE_ATTENDANCE', 8);
532
define('ITEM_TYPE_SURVEY', 9);
533
define('ITEM_TYPE_FORUM_THREAD', 10);
534
535
// one big string with all question types, for the validator in pear/HTML/QuickForm/Rule/QuestionType
536
define(
537
    'QUESTION_TYPES',
538
    UNIQUE_ANSWER.':'.
539
    MULTIPLE_ANSWER.':'.
540
    FILL_IN_BLANKS.':'.
541
    MATCHING.':'.
542
    FREE_ANSWER.':'.
543
    HOT_SPOT.':'.
544
    HOT_SPOT_ORDER.':'.
545
    HOT_SPOT_DELINEATION.':'.
546
    MULTIPLE_ANSWER_COMBINATION.':'.
547
    UNIQUE_ANSWER_NO_OPTION.':'.
548
    MULTIPLE_ANSWER_TRUE_FALSE.':'.
549
    MULTIPLE_ANSWER_COMBINATION_TRUE_FALSE.':'.
550
    ORAL_EXPRESSION.':'.
551
    GLOBAL_MULTIPLE_ANSWER.':'.
552
    MEDIA_QUESTION.':'.
553
    CALCULATED_ANSWER.':'.
554
    UNIQUE_ANSWER_IMAGE.':'.
555
    DRAGGABLE.':'.
556
    MATCHING_DRAGGABLE.':'.
557
    MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY.':'.
558
    ANNOTATION
559
);
560
561
//Some alias used in the QTI exports
562
define('MCUA', 1);
563
define('TF', 1);
564
define('MCMA', 2);
565
define('FIB', 3);
566
567
// Skills
568
define('SKILL_TYPE_REQUIREMENT', 'required');
569
define('SKILL_TYPE_ACQUIRED', 'acquired');
570
define('SKILL_TYPE_BOTH', 'both');
571
572
// Message
573
define('MESSAGE_STATUS_NEW', '0');
574
define('MESSAGE_STATUS_UNREAD', '1');
575
//2 ??
576
define('MESSAGE_STATUS_DELETED', '3');
577
define('MESSAGE_STATUS_OUTBOX', '4');
578
define('MESSAGE_STATUS_INVITATION_PENDING', '5');
579
define('MESSAGE_STATUS_INVITATION_ACCEPTED', '6');
580
define('MESSAGE_STATUS_INVITATION_DENIED', '7');
581
define('MESSAGE_STATUS_WALL', '8');
582
define('MESSAGE_STATUS_WALL_DELETE', '9');
583
define('MESSAGE_STATUS_WALL_POST', '10');
584
define('MESSAGE_STATUS_CONVERSATION', '11');
585
define('MESSAGE_STATUS_FORUM', '12');
586
define('MESSAGE_STATUS_PROMOTED', '13');
587
588
// Images
589
define('IMAGE_WALL_SMALL_SIZE', 200);
590
define('IMAGE_WALL_MEDIUM_SIZE', 500);
591
define('IMAGE_WALL_BIG_SIZE', 2000);
592
define('IMAGE_WALL_SMALL', 'small');
593
define('IMAGE_WALL_MEDIUM', 'medium');
594
define('IMAGE_WALL_BIG', 'big');
595
596
// Social PLUGIN PLACES
597
define('SOCIAL_LEFT_PLUGIN', 1);
598
define('SOCIAL_CENTER_PLUGIN', 2);
599
define('SOCIAL_RIGHT_PLUGIN', 3);
600
define('CUT_GROUP_NAME', 50);
601
602
/**
603
 * FormValidator Filter.
604
 */
605
define('NO_HTML', 1);
606
define('STUDENT_HTML', 2);
607
define('TEACHER_HTML', 3);
608
define('STUDENT_HTML_FULLPAGE', 4);
609
define('TEACHER_HTML_FULLPAGE', 5);
610
611
// Timeline
612
define('TIMELINE_STATUS_ACTIVE', '1');
613
define('TIMELINE_STATUS_INACTIVE', '2');
614
615
// Event email template class
616
define('EVENT_EMAIL_TEMPLATE_ACTIVE', 1);
617
define('EVENT_EMAIL_TEMPLATE_INACTIVE', 0);
618
619
// Course home
620
define('SHORTCUTS_HORIZONTAL', 0);
621
define('SHORTCUTS_VERTICAL', 1);
622
623
// Image class
624
define('IMAGE_PROCESSOR', 'gd'); // 'imagick' or 'gd' strings
625
626
// Course copy
627
define('FILE_SKIP', 1);
628
define('FILE_RENAME', 2);
629
define('FILE_OVERWRITE', 3);
630
define('UTF8_CONVERT', false); //false by default
631
632
define('DOCUMENT', 'file');
633
define('FOLDER', 'folder');
634
635
define('RESOURCE_ASSET', 'asset');
636
define('RESOURCE_DOCUMENT', 'document');
637
define('RESOURCE_GLOSSARY', 'glossary');
638
define('RESOURCE_EVENT', 'calendar_event');
639
define('RESOURCE_LINK', 'link');
640
define('RESOURCE_COURSEDESCRIPTION', 'course_description');
641
define('RESOURCE_LEARNPATH', 'learnpath');
642
define('RESOURCE_LEARNPATH_CATEGORY', 'learnpath_category');
643
define('RESOURCE_ANNOUNCEMENT', 'announcement');
644
define('RESOURCE_FORUM', 'forum');
645
define('RESOURCE_FORUMTOPIC', 'thread');
646
define('RESOURCE_FORUMPOST', 'post');
647
define('RESOURCE_QUIZ', 'quiz');
648
define('RESOURCE_TEST_CATEGORY', 'test_category');
649
define('RESOURCE_QUIZQUESTION', 'Exercise_Question');
650
define('RESOURCE_TOOL_INTRO', 'Tool introduction');
651
define('RESOURCE_LINKCATEGORY', 'Link_Category');
652
define('RESOURCE_FORUMCATEGORY', 'Forum_Category');
653
define('RESOURCE_SCORM', 'Scorm');
654
define('RESOURCE_SURVEY', 'survey');
655
define('RESOURCE_SURVEYQUESTION', 'survey_question');
656
define('RESOURCE_SURVEYINVITATION', 'survey_invitation');
657
define('RESOURCE_WIKI', 'wiki');
658
define('RESOURCE_THEMATIC', 'thematic');
659
define('RESOURCE_ATTENDANCE', 'attendance');
660
define('RESOURCE_WORK', 'work');
661
define('RESOURCE_SESSION_COURSE', 'session_course');
662
define('RESOURCE_GRADEBOOK', 'gradebook');
663
define('ADD_THEMATIC_PLAN', 6);
664
665
// Max online users to show per page (whoisonline)
666
define('MAX_ONLINE_USERS', 12);
667
668
// Number of characters maximum to show in preview of course blog posts
669
define('BLOG_MAX_PREVIEW_CHARS', 800);
670
// HTML string to replace with a 'Read more...' link
671
define('BLOG_PAGE_BREAK', '<div style="page-break-after: always"><span style="display: none;">&nbsp;</span></div>');
672
673
// Make sure the CHAMILO_LOAD_WYSIWYG constant is defined
674
// To remove CKeditor libs from HTML, set this constant to true before loading
675
if (!defined('CHAMILO_LOAD_WYSIWYG')) {
676
    define('CHAMILO_LOAD_WYSIWYG', true);
677
}
678
679
/* Constants for course home */
680
define('TOOL_PUBLIC', 'Public');
681
define('TOOL_PUBLIC_BUT_HIDDEN', 'PublicButHide');
682
define('TOOL_COURSE_ADMIN', 'courseAdmin');
683
define('TOOL_PLATFORM_ADMIN', 'platformAdmin');
684
define('TOOL_AUTHORING', 'toolauthoring');
685
define('TOOL_INTERACTION', 'toolinteraction');
686
define('TOOL_COURSE_PLUGIN', 'toolcourseplugin'); //all plugins that can be enabled in courses
687
define('TOOL_ADMIN', 'tooladmin');
688
define('TOOL_ADMIN_PLATFORM', 'tooladminplatform');
689
define('TOOL_DRH', 'tool_drh');
690
define('TOOL_STUDENT_VIEW', 'toolstudentview');
691
define('TOOL_ADMIN_VISIBLE', 'tooladminvisible');
692
693
/**
694
 * Returns a path to a certain resource within the Chamilo area, specifyed through a parameter.
695
 * Also, this function provides conversion between path types, in this case the input path points inside the Chamilo area too.
696
 *
697
 * See $_configuration['course_folder'] in the configuration.php to alter the WEB_COURSE_PATH and SYS_COURSE_PATH parameters.
698
699
 *
700
 * @param string $path (optional)   A path which type is to be converted. Also, it may be a defined constant for a path.
701
 *                     This parameter has meaning when $type parameter has one of the following values: TO_WEB, TO_SYS, TO_REL. Otherwise it is ignored.
702
 *
703
 * @return string the requested path or the converted path
704
 *
705
 *
706
 * Notes about the current behaviour model:
707
 * 1. Windows back-slashes are converted to slashes in the result.
708
 * 2. A semi-absolute web-path is detected by its leading slash. On Linux systems, absolute system paths start with
709
 * a slash too, so an additional check about presence of leading system server base is implemented. For example, the function is
710
 * able to distinguish type difference between /var/www/chamilo/courses/ (SYS) and /chamilo/courses/ (REL).
711
 * 3. The function api_get_path() returns only these three types of paths, which in some sense are absolute. The function has
712
 * no a mechanism for processing relative web/system paths, such as: lesson01.html, ./lesson01.html, ../css/my_styles.css.
713
 * It has not been identified as needed yet.
714
 * 4. Also, resolving the meta-symbols "." and ".." within paths has not been implemented, it is to be identified as needed.
715
 *
716
 * For examples go to: *
717
 * See main/admin/system_status.php?section=paths
718
 *
719
 * Vchamilo changes : allow using an alternate configuration
720
 * to get vchamilo  instance paths
721
 */
722
function api_get_path($path = '', $configuration = [])
723
{
724
    global $paths;
725
726
    // get proper configuration data if exists
727
    global $_configuration;
728
729
    $emptyConfigurationParam = false;
730
    if (empty($configuration)) {
731
        $configuration = (array) $_configuration;
732
        $emptyConfigurationParam = true;
733
    }
734
735
    $course_folder = 'courses/';
736
    $code_folder = 'main/';
737
    $root_sys = Container::getRootDir();
738
    $root_web = '';
739
    // If no $root_web has been set so far *and* no custom config has been passed to the function
740
    // then re-use the previously-calculated (run-specific) $root_web and skip this complex calculation
741
    if (empty($root_web) || $emptyConfigurationParam === false || empty($configuration)) {
742
        // Resolve master hostname.
743
        if (!empty($configuration) && array_key_exists('root_web', $configuration)) {
744
            $root_web = $configuration['root_web'];
745
        } else {
746
            $root_web = '';
747
            // Try guess it from server.
748
            if (defined('SYSTEM_INSTALLATION') && SYSTEM_INSTALLATION) {
749
                if (($pos = strpos(($requested_page_rel = api_get_self()), 'main/install')) !== false) {
750
                    $root_rel = substr($requested_page_rel, 0, $pos);
751
                    // See http://www.mediawiki.org/wiki/Manual:$wgServer
752
                    $server_protocol = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https' : 'http';
753
                    $server_name =
754
                        isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME']
755
                            : (isset($_SERVER['HOSTNAME']) ? $_SERVER['HOSTNAME']
756
                            : (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST']
757
                                : (isset($_SERVER['SERVER_ADDR']) ? $_SERVER['SERVER_ADDR']
758
                                    : 'localhost')));
759
                    if (isset($_SERVER['SERVER_PORT']) && !strpos($server_name, ':')
760
                        && (($server_protocol == 'http'
761
                                && $_SERVER['SERVER_PORT'] != 80) || ($server_protocol == 'https' && $_SERVER['SERVER_PORT'] != 443))
762
                    ) {
763
                        $server_name .= ":".$_SERVER['SERVER_PORT'];
764
                    }
765
                    $root_web = $server_protocol.'://'.$server_name.$root_rel;
766
                    $root_sys = str_replace('\\', '/', realpath(__DIR__.'/../../../')).'/';
767
                }
768
                // Here we give up, so we don't touch anything.
769
            }
770
        }
771
    }
772
773
    if (isset(Container::$container)) {
774
        $root_web = Container::$container->get('router')->generate(
775
            'legacy_index',
776
            [],
777
            UrlGeneratorInterface::ABSOLUTE_URL
778
        );
779
780
        // Fix for php files inside main
781
        if (strpos($root_web, 'main') !== false) {
782
            $pos = (int) strpos($root_web, 'main');
783
            $root_web = substr($root_web, 0, $pos);
784
        }
785
786
        // Fix for php files inside courses
787
        if (strpos($root_web, '/courses/') !== false) {
788
            $pos = (int) strpos($root_web, '/courses/');
789
            $root_web = substr($root_web, 0, $pos);
790
        }
791
792
        $root_web = urldecode($root_web);
793
    }
794
795
    $root_web = str_replace('public/../', '', $root_web);
796
797
    if (isset($configuration['multiple_access_urls']) &&
798
        $configuration['multiple_access_urls']
799
    ) {
800
        // To avoid that the api_get_access_url() function fails since global.inc.php also calls the main_api.lib.php
801
        if (isset($configuration['access_url']) && !empty($configuration['access_url'])) {
802
            // We look into the DB the function api_get_access_url
803
            $urlInfo = api_get_access_url($configuration['access_url']);
804
            // Avoid default value
805
            $defaultValues = ['http://localhost/', 'https://localhost/'];
806
            if (!empty($urlInfo['url']) && !in_array($urlInfo['url'], $defaultValues)) {
807
                $root_web = $urlInfo['active'] == 1 ? $urlInfo['url'] : $configuration['root_web'];
808
            }
809
        }
810
    }
811
812
    $paths = [];
813
    // Initialise cache with default values.
814
    if (!array_key_exists($root_web, $paths)) {
815
        $paths[$root_web] = [
816
            WEB_PATH => '',
817
            SYS_PATH => '',
818
            REL_PATH => '',
819
            WEB_COURSE_PATH => '',
820
            SYS_COURSE_PATH => '',
821
            REL_COURSE_PATH => '',
822
            WEB_CODE_PATH => 'main/',
823
            SYS_CODE_PATH => 'main/',
824
            REL_CODE_PATH => '/main/',
825
            SYS_LANG_PATH => 'lang/',
826
            WEB_IMG_PATH => 'public/img/',
827
            WEB_CSS_PATH => 'public/build/css/',
828
            SYS_CSS_PATH => 'public/build/css/',
829
            SYS_PLUGIN_PATH => 'plugin/',
830
            WEB_PLUGIN_PATH => 'plugin/',
831
            WEB_PLUGIN_ASSET_PATH => 'public/plugins/',
832
            SYS_ARCHIVE_PATH => 'var/cache/',
833
            WEB_ARCHIVE_PATH => 'var/cache/',
834
            SYS_HOME_PATH => 'app/home/',
835
            WEB_HOME_PATH => 'app/home/',
836
            REL_HOME_PATH => 'app/home/',
837
            SYS_APP_PATH => 'var/',
838
            SYS_UPLOAD_PATH => 'var/upload/',
839
            SYS_INC_PATH => 'inc/',
840
            CONFIGURATION_PATH => 'app/config/',
841
            LIBRARY_PATH => 'inc/lib/',
842
            WEB_LIBRARY_PATH => 'inc/lib/',
843
            WEB_LIBRARY_JS_PATH => 'inc/lib/javascript/',
844
            WEB_AJAX_PATH => 'inc/ajax/',
845
            SYS_TEST_PATH => 'tests/',
846
            WEB_TEMPLATE_PATH => 'template/',
847
            SYS_TEMPLATE_PATH => 'template/',
848
            WEB_UPLOAD_PATH => 'var/upload/',
849
            WEB_PUBLIC_PATH => 'public/',
850
            SYS_PUBLIC_PATH => 'public/',
851
            WEB_FONTS_PATH => 'fonts/',
852
            SYS_FONTS_PATH => 'fonts/',
853
        ];
854
    }
855
856
    $isInitialized = [];
857
    $root_rel = $_SERVER['APP_URL_APPEND'] ?? '';
858
859
    if (!empty($root_rel)) {
860
        // Adds "/" to the root_rel
861
        $hasSlash = substr($root_rel, 0, 1);
862
        if ($hasSlash !== '/') {
863
            $root_rel = '/'.$root_rel;
864
        }
865
    }
866
867
    // Web server base and system server base.
868
    if (!array_key_exists($root_web, $isInitialized)) {
869
        // Dealing with trailing slashes.
870
        $rootWebWithSlash = api_add_trailing_slash($root_web);
871
        $root_sys = api_add_trailing_slash($root_sys);
872
        $root_rel = api_add_trailing_slash($root_rel);
873
874
        // Initialization of a table that contains common-purpose paths.
875
        $paths[$root_web][REL_PATH] = $root_rel;
876
        $paths[$root_web][REL_COURSE_PATH] = $root_rel.$course_folder;
877
        $paths[$root_web][REL_CODE_PATH] = $root_rel.$code_folder;
878
        $paths[$root_web][WEB_PATH] = $rootWebWithSlash;
879
        $paths[$root_web][WEB_CODE_PATH] = $rootWebWithSlash.$code_folder;
880
        $paths[$root_web][WEB_COURSE_PATH] = $rootWebWithSlash.$course_folder;
881
        $paths[$root_web][WEB_PLUGIN_PATH] = $rootWebWithSlash.$paths[$root_web][WEB_PLUGIN_PATH];
882
        $paths[$root_web][WEB_PLUGIN_ASSET_PATH] = $rootWebWithSlash.$paths[$root_web][WEB_PLUGIN_ASSET_PATH];
883
        $paths[$root_web][WEB_ARCHIVE_PATH] = $rootWebWithSlash.$paths[$root_web][WEB_ARCHIVE_PATH];
884
        $paths[$root_web][WEB_CSS_PATH] = $rootWebWithSlash.$paths[$root_web][WEB_CSS_PATH];
885
        $paths[$root_web][WEB_UPLOAD_PATH] = $rootWebWithSlash.$paths[$root_web][WEB_UPLOAD_PATH];
886
        $paths[$root_web][WEB_PUBLIC_PATH] = $rootWebWithSlash.$paths[$root_web][WEB_PUBLIC_PATH];
887
        $paths[$root_web][WEB_HOME_PATH] = $rootWebWithSlash.$paths[$root_web][REL_HOME_PATH];
888
889
        $paths[$root_web][WEB_IMG_PATH] = $rootWebWithSlash.$paths[$root_web][WEB_IMG_PATH];
890
        $paths[$root_web][WEB_LIBRARY_PATH] = $paths[$root_web][WEB_CODE_PATH].$paths[$root_web][WEB_LIBRARY_PATH];
891
        $paths[$root_web][WEB_LIBRARY_JS_PATH] = $paths[$root_web][WEB_CODE_PATH].$paths[$root_web][WEB_LIBRARY_JS_PATH];
892
        $paths[$root_web][WEB_AJAX_PATH] = $paths[$root_web][WEB_CODE_PATH].$paths[$root_web][WEB_AJAX_PATH];
893
        $paths[$root_web][WEB_FONTS_PATH] = $paths[$root_web][WEB_CODE_PATH].$paths[$root_web][WEB_FONTS_PATH];
894
        $paths[$root_web][WEB_TEMPLATE_PATH] = $paths[$root_web][WEB_CODE_PATH].$paths[$root_web][WEB_TEMPLATE_PATH];
895
896
        $paths[$root_web][SYS_PATH] = $root_sys;
897
        $paths[$root_web][SYS_CODE_PATH] = $root_sys.$code_folder;
898
        $paths[$root_web][SYS_TEST_PATH] = $paths[$root_web][SYS_PATH].$paths[$root_web][SYS_TEST_PATH];
899
        $paths[$root_web][SYS_TEMPLATE_PATH] = $paths[$root_web][SYS_CODE_PATH].$paths[$root_web][SYS_TEMPLATE_PATH];
900
        $paths[$root_web][SYS_PUBLIC_PATH] = $paths[$root_web][SYS_PATH].$paths[$root_web][SYS_PUBLIC_PATH];
901
        $paths[$root_web][SYS_CSS_PATH] = $paths[$root_web][SYS_PATH].$paths[$root_web][SYS_CSS_PATH];
902
        $paths[$root_web][SYS_FONTS_PATH] = $paths[$root_web][SYS_CODE_PATH].$paths[$root_web][SYS_FONTS_PATH];
903
        $paths[$root_web][SYS_ARCHIVE_PATH] = $paths[$root_web][SYS_PATH].$paths[$root_web][SYS_ARCHIVE_PATH];
904
        $paths[$root_web][SYS_APP_PATH] = $paths[$root_web][SYS_PATH].$paths[$root_web][SYS_APP_PATH];
905
        $paths[$root_web][SYS_COURSE_PATH] = $paths[$root_web][SYS_APP_PATH].$course_folder;
906
        $paths[$root_web][SYS_UPLOAD_PATH] = $paths[$root_web][SYS_PATH].$paths[$root_web][SYS_UPLOAD_PATH];
907
        $paths[$root_web][SYS_LANG_PATH] = $paths[$root_web][SYS_CODE_PATH].$paths[$root_web][SYS_LANG_PATH];
908
        $paths[$root_web][SYS_HOME_PATH] = $paths[$root_web][SYS_PATH].$paths[$root_web][SYS_HOME_PATH];
909
        $paths[$root_web][SYS_PLUGIN_PATH] = $paths[$root_web][SYS_PATH].$paths[$root_web][SYS_PLUGIN_PATH];
910
        $paths[$root_web][SYS_INC_PATH] = $paths[$root_web][SYS_CODE_PATH].$paths[$root_web][SYS_INC_PATH];
911
912
        $paths[$root_web][LIBRARY_PATH] = $paths[$root_web][SYS_CODE_PATH].$paths[$root_web][LIBRARY_PATH];
913
        $paths[$root_web][CONFIGURATION_PATH] = $paths[$root_web][SYS_PATH].$paths[$root_web][CONFIGURATION_PATH];
914
915
        global $virtualChamilo;
916
        if (!empty($virtualChamilo)) {
917
            $paths[$root_web][SYS_ARCHIVE_PATH] = api_add_trailing_slash($virtualChamilo[SYS_ARCHIVE_PATH]);
918
            $paths[$root_web][SYS_HOME_PATH] = api_add_trailing_slash($virtualChamilo[SYS_HOME_PATH]);
919
            $paths[$root_web][SYS_COURSE_PATH] = api_add_trailing_slash($virtualChamilo[SYS_COURSE_PATH]);
920
            $paths[$root_web][SYS_UPLOAD_PATH] = api_add_trailing_slash($virtualChamilo[SYS_UPLOAD_PATH]);
921
922
            $paths[$root_web][WEB_HOME_PATH] = api_add_trailing_slash($virtualChamilo[WEB_HOME_PATH]);
923
            $paths[$root_web][WEB_UPLOAD_PATH] = api_add_trailing_slash($virtualChamilo[WEB_UPLOAD_PATH]);
924
            $paths[$root_web][WEB_ARCHIVE_PATH] = api_add_trailing_slash($virtualChamilo[WEB_ARCHIVE_PATH]);
925
            //$paths[$root_web][WEB_COURSE_PATH] = api_add_trailing_slash($virtualChamilo[WEB_COURSE_PATH]);
926
927
            // WEB_UPLOAD_PATH should be handle by apache htaccess in the vhost
928
929
            // RewriteEngine On
930
            // RewriteRule /app/upload/(.*)$ http://localhost/other/upload/my-chamilo111-net/$1 [QSA,L]
931
932
            //$paths[$root_web][WEB_UPLOAD_PATH] = api_add_trailing_slash($virtualChamilo[WEB_UPLOAD_PATH]);
933
            //$paths[$root_web][REL_PATH] = $virtualChamilo[REL_PATH];
934
            //$paths[$root_web][REL_COURSE_PATH] = $virtualChamilo[REL_COURSE_PATH];
935
        }
936
937
        $isInitialized[$root_web] = true;
938
    }
939
940
    $path = trim($path);
941
942
    // Retrieving a common-purpose path.
943
    if (isset($paths[$root_web][$path])) {
944
        return $paths[$root_web][$path];
945
    }
946
947
    // Second purification.
948
949
    // Replacing Windows back slashes.
950
    $path = str_replace('\\', '/', $path);
951
    // Query strings sometimes mighth wrongly appear in non-URLs.
952
    // Let us check remove them from all types of paths.
953
    if (($pos = strpos($path, '?')) !== false) {
954
        $path = substr($path, 0, $pos);
955
    }
956
957
    // Path now is semi-absolute. It is convenient at this moment repeated slashes to be removed.
958
    $path = preg_replace(REPEATED_SLASHES_PURIFIER, '/', $path);
959
960
    return $path;
961
}
962
963
/**
964
 * Adds to a given path a trailing slash if it is necessary (adds "/" character at the end of the string).
965
 *
966
 * @param string $path the input path
967
 *
968
 * @return string returns the modified path
969
 */
970
function api_add_trailing_slash($path)
971
{
972
    return substr($path, -1) == '/' ? $path : $path.'/';
973
}
974
975
/**
976
 * Removes from a given path the trailing slash if it is necessary (removes "/" character from the end of the string).
977
 *
978
 * @param string $path the input path
979
 *
980
 * @return string returns the modified path
981
 */
982
function api_remove_trailing_slash($path)
983
{
984
    return substr($path, -1) == '/' ? substr($path, 0, -1) : $path;
985
}
986
987
/**
988
 * Checks the RFC 3986 syntax of a given URL.
989
 *
990
 * @param string $url      the URL to be checked
991
 * @param bool   $absolute whether the URL is absolute (beginning with a scheme such as "http:")
992
 *
993
 * @return string|false Returns the URL if it is valid, FALSE otherwise.
994
 *                      This function is an adaptation from the function valid_url(), Drupal CMS.
995
 *
996
 * @see http://drupal.org
997
 * Note: The built-in function filter_var($urs, FILTER_VALIDATE_URL) has a bug for some versions of PHP.
998
 * @see http://bugs.php.net/51192
999
 */
1000
function api_valid_url($url, $absolute = false)
1001
{
1002
    if ($absolute) {
1003
        if (preg_match("
1004
            /^                                                      # Start at the beginning of the text
1005
            (?:ftp|https?|feed):\/\/                                # Look for ftp, http, https or feed schemes
1006
            (?:                                                     # Userinfo (optional) which is typically
1007
                (?:(?:[\w\.\-\+!$&'\(\)*\+,;=]|%[0-9a-f]{2})+:)*    # a username or a username and password
1008
                (?:[\w\.\-\+%!$&'\(\)*\+,;=]|%[0-9a-f]{2})+@        # combination
1009
            )?
1010
            (?:
1011
                (?:[a-z0-9\-\.]|%[0-9a-f]{2})+                      # A domain name or a IPv4 address
1012
                |(?:\[(?:[0-9a-f]{0,4}:)*(?:[0-9a-f]{0,4})\])       # or a well formed IPv6 address
1013
            )
1014
            (?::[0-9]+)?                                            # Server port number (optional)
1015
            (?:[\/|\?]
1016
                (?:[\w#!:\.\?\+=&@$'~*,;\/\(\)\[\]\-]|%[0-9a-f]{2}) # The path and query (optional)
1017
            *)?
1018
            $/xi", $url)) {
1019
            return $url;
1020
        }
1021
1022
        return false;
1023
    } else {
1024
        return preg_match("/^(?:[\w#!:\.\?\+=&@$'~*,;\/\(\)\[\]\-]|%[0-9a-f]{2})+$/i", $url) ? $url : false;
1025
    }
1026
}
1027
1028
/**
1029
 * Checks whether a given string looks roughly like an email address.
1030
 *
1031
 * @param string $address the e-mail address to be checked
1032
 *
1033
 * @return mixed returns the e-mail if it is valid, FALSE otherwise
1034
 */
1035
function api_valid_email($address)
1036
{
1037
    return filter_var($address, FILTER_VALIDATE_EMAIL);
1038
}
1039
1040
/* PROTECTION FUNCTIONS
1041
   Use these functions to protect your scripts. */
1042
1043
/**
1044
 * Function used to protect a course script.
1045
 * The function blocks access when
1046
 * - there is no $_SESSION["_course"] defined; or
1047
 * - $is_allowed_in_course is set to false (this depends on the course
1048
 * visibility and user status).
1049
 *
1050
 * This is only the first proposal, test and improve!
1051
 *
1052
 * @param bool Option to print headers when displaying error message. Default: false
1053
 * @param bool whether session admins should be allowed or not
1054
 * @param bool $checkTool check if tool is available for users (user, group)
1055
 *
1056
 * @return bool True if the user has access to the current course or is out of a course context, false otherwise
1057
 *
1058
 * @todo replace global variable
1059
 *
1060
 * @author Roan Embrechts
1061
 */
1062
function api_protect_course_script($print_headers = false, $allow_session_admins = false, $checkTool = '')
1063
{
1064
    $course_info = api_get_course_info();
1065
    if (empty($course_info)) {
1066
        api_not_allowed($print_headers);
1067
1068
        return false;
1069
    }
1070
1071
    if (api_is_drh()) {
1072
        return true;
1073
    }
1074
1075
    // Session admin has access to course
1076
    $sessionAccess = api_get_configuration_value('session_admins_access_all_content');
1077
    if ($sessionAccess) {
1078
        $allow_session_admins = true;
1079
    }
1080
1081
    if (api_is_platform_admin($allow_session_admins)) {
1082
        return true;
1083
    }
1084
1085
    $isAllowedInCourse = api_is_allowed_in_course();
1086
    $is_visible = false;
1087
    if (isset($course_info) && isset($course_info['visibility'])) {
1088
        switch ($course_info['visibility']) {
1089
            default:
1090
            case COURSE_VISIBILITY_CLOSED:
1091
                // Completely closed: the course is only accessible to the teachers. - 0
1092
                if (api_get_user_id() && !api_is_anonymous() && $isAllowedInCourse) {
1093
                    $is_visible = true;
1094
                }
1095
                break;
1096
            case COURSE_VISIBILITY_REGISTERED:
1097
                // Private - access authorized to course members only - 1
1098
                if (api_get_user_id() && !api_is_anonymous() && $isAllowedInCourse) {
1099
                    $is_visible = true;
1100
                }
1101
                break;
1102
            case COURSE_VISIBILITY_OPEN_PLATFORM:
1103
                // Open - access allowed for users registered on the platform - 2
1104
                if (api_get_user_id() && !api_is_anonymous() && $isAllowedInCourse) {
1105
                    $is_visible = true;
1106
                }
1107
                break;
1108
            case COURSE_VISIBILITY_OPEN_WORLD:
1109
                //Open - access allowed for the whole world - 3
1110
                $is_visible = true;
1111
                break;
1112
            case COURSE_VISIBILITY_HIDDEN:
1113
                //Completely closed: the course is only accessible to the teachers. - 0
1114
                if (api_is_platform_admin()) {
1115
                    $is_visible = true;
1116
                }
1117
                break;
1118
        }
1119
1120
        //If password is set and user is not registered to the course then the course is not visible
1121
        if ($isAllowedInCourse == false &&
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

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

Loading history...
1122
            isset($course_info['registration_code']) &&
1123
            !empty($course_info['registration_code'])
1124
        ) {
1125
            $is_visible = false;
1126
        }
1127
    }
1128
1129
    if (!empty($checkTool)) {
1130
        if (!api_is_allowed_to_edit(true, true, true)) {
1131
            $toolInfo = api_get_tool_information_by_name($checkTool);
1132
            if (!empty($toolInfo) && isset($toolInfo['visibility']) && $toolInfo['visibility'] == 0) {
1133
                api_not_allowed(true);
1134
1135
                return false;
1136
            }
1137
        }
1138
    }
1139
1140
    // Check session visibility
1141
    $session_id = api_get_session_id();
1142
1143
    if (!empty($session_id)) {
1144
        // $isAllowedInCourse was set in local.inc.php
1145
        if (!$isAllowedInCourse) {
1146
            $is_visible = false;
1147
        }
1148
    }
1149
1150
    if (!$is_visible) {
1151
        api_not_allowed($print_headers);
1152
1153
        return false;
1154
    }
1155
1156
    return true;
1157
}
1158
1159
/**
1160
 * Function used to protect an admin script.
1161
 *
1162
 * The function blocks access when the user has no platform admin rights
1163
 * with an error message printed on default output
1164
 *
1165
 * @param bool Whether to allow session admins as well
1166
 * @param bool Whether to allow HR directors as well
1167
 * @param string An optional message (already passed through get_lang)
1168
 *
1169
 * @return bool True if user is allowed, false otherwise.
1170
 *              The function also outputs an error message in case not allowed
1171
 *
1172
 * @author Roan Embrechts (original author)
1173
 */
1174
function api_protect_admin_script($allow_sessions_admins = false, $allow_drh = false, $message = null)
1175
{
1176
    if (!api_is_platform_admin($allow_sessions_admins, $allow_drh)) {
1177
        api_not_allowed(true, $message);
1178
1179
        return false;
1180
    }
1181
1182
    return true;
1183
}
1184
1185
/**
1186
 * Function used to protect a teacher script.
1187
 * The function blocks access when the user has no teacher rights.
1188
 *
1189
 * @return bool True if the current user can access the script, false otherwise
1190
 *
1191
 * @author Yoselyn Castillo
1192
 */
1193
function api_protect_teacher_script()
1194
{
1195
    if (!api_is_allowed_to_edit()) {
1196
        api_not_allowed(true);
1197
1198
        return false;
1199
    }
1200
1201
    return true;
1202
}
1203
1204
/**
1205
 * Function used to prevent anonymous users from accessing a script.
1206
 *
1207
 * @param bool|true $printHeaders
1208
 *
1209
 * @author Roan Embrechts
1210
 *
1211
 * @return bool
1212
 */
1213
function api_block_anonymous_users($printHeaders = true)
1214
{
1215
    $user = api_get_user_info();
1216
    if (!(isset($user['user_id']) && $user['user_id']) || api_is_anonymous($user['user_id'], true)) {
1217
        api_not_allowed($printHeaders);
1218
1219
        return false;
1220
    }
1221
1222
    return true;
1223
}
1224
1225
/**
1226
 * Returns a rough evaluation of the browser's name and version based on very
1227
 * simple regexp.
1228
 *
1229
 * @return array with the navigator name and version ['name' => '...', 'version' => '...']
1230
 */
1231
function api_get_navigator()
1232
{
1233
    $navigator = 'Unknown';
1234
    $version = 0;
1235
1236
    if (!isset($_SERVER['HTTP_USER_AGENT'])) {
1237
        return ['name' => 'Unknown', 'version' => '0.0.0'];
1238
    }
1239
1240
    if (strpos($_SERVER['HTTP_USER_AGENT'], 'Opera') !== false) {
1241
        $navigator = 'Opera';
1242
        list(, $version) = explode('Opera', $_SERVER['HTTP_USER_AGENT']);
1243
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Edge') !== false) {
1244
        $navigator = 'Edge';
1245
        list(, $version) = explode('Edge', $_SERVER['HTTP_USER_AGENT']);
1246
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== false) {
1247
        $navigator = 'Internet Explorer';
1248
        list(, $version) = explode('MSIE ', $_SERVER['HTTP_USER_AGENT']);
1249
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Chrome') !== false) {
1250
        $navigator = 'Chrome';
1251
        list(, $version) = explode('Chrome', $_SERVER['HTTP_USER_AGENT']);
1252
    } elseif (stripos($_SERVER['HTTP_USER_AGENT'], 'Safari') !== false) {
1253
        $navigator = 'Safari';
1254
        if (stripos($_SERVER['HTTP_USER_AGENT'], 'Version/') !== false) {
1255
            // If this Safari does have the "Version/" string in its user agent
1256
            // then use that as a version indicator rather than what's after
1257
            // "Safari/" which is rather a "build number" or something
1258
            list(, $version) = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1259
        } else {
1260
            list(, $version) = explode('Safari/', $_SERVER['HTTP_USER_AGENT']);
1261
        }
1262
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Firefox') !== false) {
1263
        $navigator = 'Firefox';
1264
        list(, $version) = explode('Firefox', $_SERVER['HTTP_USER_AGENT']);
1265
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Netscape') !== false) {
1266
        $navigator = 'Netscape';
1267
        if (stripos($_SERVER['HTTP_USER_AGENT'], 'Netscape/') !== false) {
1268
            list(, $version) = explode('Netscape', $_SERVER['HTTP_USER_AGENT']);
1269
        } else {
1270
            list(, $version) = explode('Navigator', $_SERVER['HTTP_USER_AGENT']);
1271
        }
1272
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Konqueror') !== false) {
1273
        $navigator = 'Konqueror';
1274
        list(, $version) = explode('Konqueror', $_SERVER['HTTP_USER_AGENT']);
1275
    } elseif (stripos($_SERVER['HTTP_USER_AGENT'], 'applewebkit') !== false) {
1276
        $navigator = 'AppleWebKit';
1277
        list(, $version) = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1278
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Gecko') !== false) {
1279
        $navigator = 'Mozilla';
1280
        list(, $version) = explode('; rv:', $_SERVER['HTTP_USER_AGENT']);
1281
    }
1282
1283
    // Now cut extra stuff around (mostly *after*) the version number
1284
    $version = preg_replace('/^([\/\s])?([\d\.]+)?.*/', '\2', $version);
1285
1286
    if (strpos($version, '.') === false) {
1287
        $version = number_format(doubleval($version), 1);
1288
    }
1289
    $return = ['name' => $navigator, 'version' => $version];
1290
1291
    return $return;
1292
}
1293
1294
/**
1295
 * @return true if user self registration is allowed, false otherwise
1296
 */
1297
function api_is_self_registration_allowed()
1298
{
1299
    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...
1300
}
1301
1302
/**
1303
 * This function returns the id of the user which is stored in the $_user array.
1304
 *
1305
 * example: The function can be used to check if a user is logged in
1306
 *          if (api_get_user_id())
1307
 *
1308
 * @return int the id of the current user, 0 if is empty
1309
 */
1310
function api_get_user_id()
1311
{
1312
    $userInfo = Session::read('_user');
1313
    if ($userInfo && isset($userInfo['user_id'])) {
1314
        return (int) $userInfo['user_id'];
1315
    }
1316
1317
    return 0;
1318
}
1319
1320
/**
1321
 * Gets the list of courses a specific user is subscribed to.
1322
 *
1323
 * @param int       User ID
1324
 * @param bool $fetch_session Whether to get session courses or not - NOT YET IMPLEMENTED
1325
 *
1326
 * @return array Array of courses in the form [0]=>('code'=>xxx,'db'=>xxx,'dir'=>xxx,'status'=>d)
1327
 *
1328
 * @deprecated use CourseManager::get_courses_list_by_user_id()
1329
 */
1330
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

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

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

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

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

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

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

Loading history...
4984
            $platform_theme = $styleFromDatabase['selected_value'];
4985
        } else {
4986
            $platform_theme = api_get_setting('stylesheets');
4987
        }
4988
4989
        // Platform's theme.
4990
        $visual_theme = $platform_theme;
4991
        if (api_get_setting('user_selected_theme') == 'true') {
4992
            $user_info = api_get_user_info();
4993
            if (isset($user_info['theme'])) {
4994
                $user_theme = $user_info['theme'];
4995
4996
                if (!empty($user_theme)) {
4997
                    $visual_theme = $user_theme;
4998
                    // User's theme.
4999
                }
5000
            }
5001
        }
5002
5003
        $course_id = api_get_course_id();
5004
        if (!empty($course_id)) {
5005
            if (api_get_setting('allow_course_theme') == 'true') {
5006
                $course_theme = api_get_course_setting('course_theme', $course_id);
5007
5008
                if (!empty($course_theme) && $course_theme != -1) {
5009
                    if (!empty($course_theme)) {
5010
                        // Course's theme.
5011
                        $visual_theme = $course_theme;
5012
                    }
5013
                }
5014
5015
                $allow_lp_theme = api_get_course_setting('allow_learning_path_theme');
5016
                if ($allow_lp_theme == 1) {
5017
                    global $lp_theme_css, $lp_theme_config;
5018
                    // These variables come from the file lp_controller.php.
5019
                    if (!$lp_theme_config) {
5020
                        if (!empty($lp_theme_css)) {
5021
                            // LP's theme.
5022
                            $visual_theme = $lp_theme_css;
5023
                        }
5024
                    }
5025
                }
5026
            }
5027
        }
5028
5029
        if (empty($visual_theme)) {
5030
            $visual_theme = 'chamilo';
5031
        }
5032
5033
        global $lp_theme_log;
5034
        if ($lp_theme_log) {
5035
            $visual_theme = $platform_theme;
5036
        }
5037
    }
5038
5039
    return $visual_theme;
5040
}
5041
5042
/**
5043
 * Returns a list of CSS themes currently available in the CSS folder
5044
 * The folder must have a default.css file.
5045
 *
5046
 * @param bool $getOnlyThemeFromVirtualInstance Used by the vchamilo plugin
5047
 *
5048
 * @return array list of themes directories from the css folder
5049
 *               Note: Directory names (names of themes) in the file system should contain ASCII-characters only
5050
 */
5051
function api_get_themes($getOnlyThemeFromVirtualInstance = false)
5052
{
5053
    // This configuration value is set by the vchamilo plugin
5054
    $virtualTheme = api_get_configuration_value('virtual_css_theme_folder');
5055
5056
    $readCssFolder = function ($dir) use ($virtualTheme) {
5057
        $finder = new Finder();
5058
        $themes = $finder->directories()->in($dir)->depth(0)->sortByName();
5059
        $list = [];
5060
        /** @var Symfony\Component\Finder\SplFileInfo $theme */
5061
        foreach ($themes as $theme) {
5062
            $folder = $theme->getFilename();
5063
            // A theme folder is consider if there's a default.css file
5064
            if (!file_exists($theme->getPathname().'/default.css')) {
5065
                continue;
5066
            }
5067
            $name = ucwords(str_replace('_', ' ', $folder));
5068
            if ($folder == $virtualTheme) {
5069
                continue;
5070
            }
5071
            $list[$folder] = $name;
5072
        }
5073
5074
        return $list;
5075
    };
5076
5077
    $dir = api_get_path(SYS_CSS_PATH).'themes/';
5078
    $list = $readCssFolder($dir);
5079
5080
    if (!empty($virtualTheme)) {
5081
        $newList = $readCssFolder($dir.'/'.$virtualTheme);
5082
        if ($getOnlyThemeFromVirtualInstance) {
5083
            return $newList;
5084
        }
5085
        $list = $list + $newList;
5086
        asort($list);
5087
    }
5088
5089
    return $list;
5090
}
5091
5092
/**
5093
 * Find the largest sort value in a given user_course_category
5094
 * This function is used when we are moving a course to a different category
5095
 * and also when a user subscribes to courses (the new course is added at the end of the main category.
5096
 *
5097
 * @author Patrick Cool <[email protected]>, Ghent University
5098
 *
5099
 * @param int $user_course_category the id of the user_course_category
5100
 * @param int $user_id
5101
 *
5102
 * @return int the value of the highest sort of the user_course_category
5103
 */
5104
function api_max_sort_value($user_course_category, $user_id)
5105
{
5106
    $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
5107
    $sql = "SELECT max(sort) as max_sort FROM $tbl_course_user
5108
            WHERE
5109
                user_id='".intval($user_id)."' AND
5110
                relation_type<>".COURSE_RELATION_TYPE_RRHH." AND
5111
                user_course_cat='".intval($user_course_category)."'";
5112
    $result_max = Database::query($sql);
5113
    if (Database::num_rows($result_max) == 1) {
5114
        $row_max = Database::fetch_array($result_max);
5115
5116
        return $row_max['max_sort'];
5117
    }
5118
5119
    return 0;
5120
}
5121
5122
/**
5123
 * Transforms a number of seconds in hh:mm:ss format.
5124
 *
5125
 * @author Julian Prud'homme
5126
 *
5127
 * @param int    $seconds      number of seconds
5128
 * @param string $space
5129
 * @param bool   $showSeconds
5130
 * @param bool   $roundMinutes
5131
 *
5132
 * @return string the formatted time
5133
 */
5134
function api_time_to_hms($seconds, $space = ':', $showSeconds = true, $roundMinutes = false)
5135
{
5136
    // $seconds = -1 means that we have wrong data in the db.
5137
    if ($seconds == -1) {
5138
        return
5139
            get_lang('Unknown').
5140
            Display::return_icon(
5141
                'info2.gif',
5142
                get_lang('WrongDatasForTimeSpentOnThePlatform'),
5143
                ['align' => 'absmiddle', 'hspace' => '3px']
5144
            );
5145
    }
5146
5147
    // How many hours ?
5148
    $hours = floor($seconds / 3600);
5149
5150
    // How many minutes ?
5151
    $min = floor(($seconds - ($hours * 3600)) / 60);
5152
5153
    if ($roundMinutes) {
5154
        if ($min >= 45) {
5155
            $min = 45;
5156
        }
5157
5158
        if ($min >= 30 && $min <= 44) {
5159
            $min = 30;
5160
        }
5161
5162
        if ($min >= 15 && $min <= 29) {
5163
            $min = 15;
5164
        }
5165
5166
        if ($min >= 0 && $min <= 14) {
5167
            $min = 0;
5168
        }
5169
    }
5170
5171
    // How many seconds
5172
    $sec = floor($seconds - ($hours * 3600) - ($min * 60));
5173
5174
    if ($hours < 10) {
5175
        $hours = "0$hours";
5176
    }
5177
5178
    if ($sec < 10) {
5179
        $sec = "0$sec";
5180
    }
5181
5182
    if ($min < 10) {
5183
        $min = "0$min";
5184
    }
5185
5186
    $seconds = '';
5187
    if ($showSeconds) {
5188
        $seconds = $space.$sec;
5189
    }
5190
5191
    return $hours.$space.$min.$seconds;
5192
}
5193
5194
/* FILE SYSTEM RELATED FUNCTIONS */
5195
5196
/**
5197
 * Returns the permissions to be assigned to every newly created directory by the web-server.
5198
 * The return value is based on the platform administrator's setting
5199
 * "Administration > Configuration settings > Security > Permissions for new directories".
5200
 *
5201
 * @return int returns the permissions in the format "Owner-Group-Others, Read-Write-Execute", as an integer value
5202
 */
5203
function api_get_permissions_for_new_directories()
5204
{
5205
    static $permissions;
5206
    if (!isset($permissions)) {
5207
        $permissions = trim(api_get_setting('permissions_for_new_directories'));
5208
        // The default value 0777 is according to that in the platform administration panel after fresh system installation.
5209
        $permissions = octdec(!empty($permissions) ? $permissions : '0777');
5210
    }
5211
5212
    return $permissions;
5213
}
5214
5215
/**
5216
 * Returns the permissions to be assigned to every newly created directory by the web-server.
5217
 * The return value is based on the platform administrator's setting
5218
 * "Administration > Configuration settings > Security > Permissions for new files".
5219
 *
5220
 * @return int returns the permissions in the format
5221
 *             "Owner-Group-Others, Read-Write-Execute", as an integer value
5222
 */
5223
function api_get_permissions_for_new_files()
5224
{
5225
    static $permissions;
5226
    if (!isset($permissions)) {
5227
        $permissions = trim(api_get_setting('permissions_for_new_files'));
5228
        // The default value 0666 is according to that in the platform
5229
        // administration panel after fresh system installation.
5230
        $permissions = octdec(!empty($permissions) ? $permissions : '0666');
5231
    }
5232
5233
    return $permissions;
5234
}
5235
5236
/**
5237
 * Deletes a file, or a folder and its contents.
5238
 *
5239
 * @author      Aidan Lister <[email protected]>
5240
 *
5241
 * @version     1.0.3
5242
 *
5243
 * @param string $dirname Directory to delete
5244
 * @param       bool     Deletes only the content or not
5245
 * @param bool $strict if one folder/file fails stop the loop
5246
 *
5247
 * @return bool Returns TRUE on success, FALSE on failure
5248
 *
5249
 * @see http://aidanlister.com/2004/04/recursively-deleting-a-folder-in-php/
5250
 *
5251
 * @author      Yannick Warnier, adaptation for the Chamilo LMS, April, 2008
5252
 * @author      Ivan Tcholakov, a sanity check about Directory class creation has been added, September, 2009
5253
 */
5254
function rmdirr($dirname, $delete_only_content_in_folder = false, $strict = false)
5255
{
5256
    $res = true;
5257
    // A sanity check.
5258
    if (!file_exists($dirname)) {
5259
        return false;
5260
    }
5261
    $php_errormsg = '';
5262
    // Simple delete for a file.
5263
    if (is_file($dirname) || is_link($dirname)) {
5264
        $res = unlink($dirname);
5265
        if ($res === false) {
5266
            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);
5267
        }
5268
5269
        return $res;
5270
    }
5271
5272
    // Loop through the folder.
5273
    $dir = dir($dirname);
5274
    // A sanity check.
5275
    $is_object_dir = is_object($dir);
5276
    if ($is_object_dir) {
5277
        while (false !== $entry = $dir->read()) {
5278
            // Skip pointers.
5279
            if ($entry == '.' || $entry == '..') {
5280
                continue;
5281
            }
5282
5283
            // Recurse.
5284
            if ($strict) {
5285
                $result = rmdirr("$dirname/$entry");
5286
                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...
5287
                    $res = false;
5288
                    break;
5289
                }
5290
            } else {
5291
                rmdirr("$dirname/$entry");
5292
            }
5293
        }
5294
    }
5295
5296
    // Clean up.
5297
    if ($is_object_dir) {
5298
        $dir->close();
5299
    }
5300
5301
    if ($delete_only_content_in_folder == false) {
5302
        $res = rmdir($dirname);
5303
        if ($res === false) {
5304
            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);
5305
        }
5306
    }
5307
5308
    return $res;
5309
}
5310
5311
// TODO: This function is to be simplified. File access modes to be implemented.
5312
/**
5313
 * function adapted from a php.net comment
5314
 * copy recursively a folder.
5315
 *
5316
 * @param the source folder
5317
 * @param the dest folder
5318
 * @param an array of excluded file_name (without extension)
5319
 * @param copied_files the returned array of copied files
5320
 * @param string $source
5321
 * @param string $dest
5322
 */
5323
function copyr($source, $dest, $exclude = [], $copied_files = [])
5324
{
5325
    if (empty($dest)) {
5326
        return false;
5327
    }
5328
    // Simple copy for a file
5329
    if (is_file($source)) {
5330
        $path_info = pathinfo($source);
5331
        if (!in_array($path_info['filename'], $exclude)) {
5332
            copy($source, $dest);
5333
        }
5334
5335
        return true;
5336
    } elseif (!is_dir($source)) {
5337
        //then source is not a dir nor a file, return
5338
        return false;
5339
    }
5340
5341
    // Make destination directory.
5342
    if (!is_dir($dest)) {
5343
        mkdir($dest, api_get_permissions_for_new_directories());
5344
    }
5345
5346
    // Loop through the folder.
5347
    $dir = dir($source);
5348
    while (false !== $entry = $dir->read()) {
5349
        // Skip pointers
5350
        if ($entry == '.' || $entry == '..') {
5351
            continue;
5352
        }
5353
5354
        // Deep copy directories.
5355
        if ($dest !== "$source/$entry") {
5356
            $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

5356
            $files = copyr("$source/$entry", "$dest/$entry", $exclude, /** @scrutinizer ignore-type */ $copied_files);
Loading history...
5357
        }
5358
    }
5359
    // Clean up.
5360
    $dir->close();
5361
5362
    return true;
5363
}
5364
5365
/**
5366
 * @todo: Using DIRECTORY_SEPARATOR is not recommended, this is an obsolete approach.
5367
 * Documentation header to be added here.
5368
 *
5369
 * @param string $pathname
5370
 * @param string $base_path_document
5371
 * @param int    $session_id
5372
 *
5373
 * @return mixed True if directory already exists, false if a file already exists at
5374
 *               the destination and null if everything goes according to plan
5375
 */
5376
function copy_folder_course_session(
5377
    $pathname,
5378
    $base_path_document,
5379
    $session_id,
5380
    $course_info,
5381
    $document,
5382
    $source_course_id
5383
) {
5384
    $table = Database::get_course_table(TABLE_DOCUMENT);
5385
    $session_id = intval($session_id);
5386
    $source_course_id = intval($source_course_id);
5387
5388
    // Check whether directory already exists.
5389
    if (is_dir($pathname) || empty($pathname)) {
5390
        return true;
5391
    }
5392
5393
    // Ensure that a file with the same name does not already exist.
5394
    if (is_file($pathname)) {
5395
        trigger_error('copy_folder_course_session(): File exists', E_USER_WARNING);
5396
5397
        return false;
5398
    }
5399
5400
    $course_id = $course_info['real_id'];
5401
    $folders = explode(DIRECTORY_SEPARATOR, str_replace($base_path_document.DIRECTORY_SEPARATOR, '', $pathname));
5402
    $new_pathname = $base_path_document;
5403
    $path = '';
5404
5405
    foreach ($folders as $folder) {
5406
        $new_pathname .= DIRECTORY_SEPARATOR.$folder;
5407
        $path .= DIRECTORY_SEPARATOR.$folder;
5408
5409
        if (!file_exists($new_pathname)) {
5410
            $path = Database::escape_string($path);
5411
5412
            $sql = "SELECT * FROM $table
5413
                    WHERE
5414
                        c_id = $source_course_id AND
5415
                        path = '$path' AND
5416
                        filetype = 'folder' AND
5417
                        session_id = '$session_id'";
5418
            $rs1 = Database::query($sql);
5419
            $num_rows = Database::num_rows($rs1);
5420
5421
            if ($num_rows == 0) {
5422
                mkdir($new_pathname, api_get_permissions_for_new_directories());
5423
5424
                // Insert new folder with destination session_id.
5425
                $params = [
5426
                    'c_id' => $course_id,
5427
                    'path' => $path,
5428
                    'comment' => $document->comment,
5429
                    'title' => basename($new_pathname),
5430
                    'filetype' => 'folder',
5431
                    'size' => '0',
5432
                    'session_id' => $session_id,
5433
                ];
5434
                $document_id = Database::insert($table, $params);
5435
                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...
5436
                    $sql = "UPDATE $table SET id = iid WHERE iid = $document_id";
5437
                    Database::query($sql);
5438
5439
                    api_item_property_update(
5440
                        $course_info,
5441
                        TOOL_DOCUMENT,
5442
                        $document_id,
5443
                        'FolderCreated',
5444
                        api_get_user_id(),
5445
                        0,
5446
                        0,
5447
                        null,
5448
                        null,
5449
                        $session_id
5450
                    );
5451
                }
5452
            }
5453
        }
5454
    } // en foreach
5455
}
5456
5457
// TODO: chmodr() is a better name. Some corrections are needed. Documentation header to be added here.
5458
/**
5459
 * @param string $path
5460
 */
5461
function api_chmod_R($path, $filemode)
5462
{
5463
    if (!is_dir($path)) {
5464
        return chmod($path, $filemode);
5465
    }
5466
5467
    $handler = opendir($path);
5468
    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

5468
    while ($file = readdir(/** @scrutinizer ignore-type */ $handler)) {
Loading history...
5469
        if ($file != '.' && $file != '..') {
5470
            $fullpath = "$path/$file";
5471
            if (!is_dir($fullpath)) {
5472
                if (!chmod($fullpath, $filemode)) {
5473
                    return false;
5474
                }
5475
            } else {
5476
                if (!api_chmod_R($fullpath, $filemode)) {
5477
                    return false;
5478
                }
5479
            }
5480
        }
5481
    }
5482
5483
    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

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

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

7584
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...
7585
{
7586
    return Container::getAuthorizationChecker()->isGranted('IS_AUTHENTICATED_FULLY');
7587
}
7588
7589
/**
7590
 * Guess the real ip for register in the database, even in reverse proxy cases.
7591
 * To be recognized, the IP has to be found in either $_SERVER['REMOTE_ADDR'] or
7592
 * in $_SERVER['HTTP_X_FORWARDED_FOR'], which is in common use with rproxies.
7593
 * Note: the result of this function is not SQL-safe. Please escape it before
7594
 * inserting in a database.
7595
 *
7596
 * @return string the user's real ip (unsafe - escape it before inserting to db)
7597
 *
7598
 * @author Jorge Frisancho Jibaja <[email protected]>, USIL - Some changes to allow the use of real IP using reverse proxy
7599
 *
7600
 * @version CEV CHANGE 24APR2012
7601
 */
7602
function api_get_real_ip()
7603
{
7604
    $ip = trim($_SERVER['REMOTE_ADDR']);
7605
    if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
7606
        if (preg_match('/,/', $_SERVER['HTTP_X_FORWARDED_FOR'])) {
7607
            @list($ip1, $ip2) = @explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
7608
        } else {
7609
            $ip1 = $_SERVER['HTTP_X_FORWARDED_FOR'];
7610
        }
7611
        $ip = trim($ip1);
7612
    }
7613
7614
    return $ip;
7615
}
7616
7617
/**
7618
 * Checks whether an IP is included inside an IP range.
7619
 *
7620
 * @param string IP address
7621
 * @param string IP range
7622
 * @param string $ip
7623
 *
7624
 * @return bool True if IP is in the range, false otherwise
7625
 *
7626
 * @author claudiu at cnixs dot com  on http://www.php.net/manual/fr/ref.network.php#55230
7627
 * @author Yannick Warnier for improvements and managment of multiple ranges
7628
 *
7629
 * @todo check for IPv6 support
7630
 */
7631
function api_check_ip_in_range($ip, $range)
7632
{
7633
    if (empty($ip) or empty($range)) {
7634
        return false;
7635
    }
7636
    $ip_ip = ip2long($ip);
7637
    // divide range param into array of elements
7638
    if (strpos($range, ',') !== false) {
7639
        $ranges = explode(',', $range);
7640
    } else {
7641
        $ranges = [$range];
7642
    }
7643
    foreach ($ranges as $range) {
0 ignored issues
show
introduced by
$range is overwriting one of the parameters of this function.
Loading history...
7644
        $range = trim($range);
7645
        if (empty($range)) {
7646
            continue;
7647
        }
7648
        if (strpos($range, '/') === false) {
7649
            if (strcmp($ip, $range) === 0) {
7650
                return true; // there is a direct IP match, return OK
7651
            }
7652
            continue; //otherwise, get to the next range
7653
        }
7654
        // the range contains a "/", so analyse completely
7655
        list($net, $mask) = explode("/", $range);
7656
7657
        $ip_net = ip2long($net);
7658
        // mask binary magic
7659
        $ip_mask = ~((1 << (32 - $mask)) - 1);
7660
7661
        $ip_ip_net = $ip_ip & $ip_mask;
7662
        if ($ip_ip_net == $ip_net) {
7663
            return true;
7664
        }
7665
    }
7666
7667
    return false;
7668
}
7669
7670
function api_check_user_access_to_legal($course_visibility)
7671
{
7672
    $course_visibility_list = [COURSE_VISIBILITY_OPEN_WORLD, COURSE_VISIBILITY_OPEN_PLATFORM];
7673
7674
    return in_array($course_visibility, $course_visibility_list) || api_is_drh();
7675
}
7676
7677
/**
7678
 * Checks if the global chat is enabled or not.
7679
 *
7680
 * @return bool
7681
 */
7682
function api_is_global_chat_enabled()
7683
{
7684
    return
7685
        !api_is_anonymous() &&
7686
        api_get_setting('allow_global_chat') === 'true' &&
7687
        api_get_setting('allow_social_tool') === 'true';
7688
}
7689
7690
/**
7691
 * @todo Fix tool_visible_by_default_at_creation labels
7692
 * @todo Add sessionId parameter to avoid using context
7693
 *
7694
 * @param int   $item_id
7695
 * @param int   $tool_id
7696
 * @param int   $group_id   id
7697
 * @param array $courseInfo
7698
 * @param int   $sessionId
7699
 * @param int   $userId
7700
 */
7701
function api_set_default_visibility(
7702
    $item_id,
7703
    $tool_id,
7704
    $group_id = 0,
7705
    $courseInfo = [],
7706
    $sessionId = 0,
7707
    $userId = 0
7708
) {
7709
    $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
7710
    $courseId = $courseInfo['real_id'];
7711
    $courseCode = $courseInfo['code'];
7712
    $sessionId = empty($sessionId) ? api_get_session_id() : $sessionId;
7713
    $userId = empty($userId) ? api_get_user_id() : $userId;
7714
7715
    // if group is null force group_id = 0, this force is needed to create a LP folder with group = 0
7716
    if (is_null($group_id)) {
7717
        $group_id = 0;
7718
    } else {
7719
        $group_id = empty($group_id) ? api_get_group_id() : $group_id;
7720
    }
7721
7722
    $groupInfo = [];
7723
    if (!empty($group_id)) {
7724
        $groupInfo = GroupManager::get_group_properties($group_id);
7725
    }
7726
    $original_tool_id = $tool_id;
7727
7728
    switch ($tool_id) {
7729
        case TOOL_LINK:
7730
        case TOOL_LINK_CATEGORY:
7731
            $tool_id = 'links';
7732
            break;
7733
        case TOOL_DOCUMENT:
7734
            $tool_id = 'documents';
7735
            break;
7736
        case TOOL_LEARNPATH:
7737
            $tool_id = 'learning';
7738
            break;
7739
        case TOOL_ANNOUNCEMENT:
7740
            $tool_id = 'announcements';
7741
            break;
7742
        case TOOL_FORUM:
7743
        case TOOL_FORUM_CATEGORY:
7744
        case TOOL_FORUM_THREAD:
7745
            $tool_id = 'forums';
7746
            break;
7747
        case TOOL_QUIZ:
7748
            $tool_id = 'quiz';
7749
            break;
7750
    }
7751
    $setting = api_get_setting('tool_visible_by_default_at_creation');
7752
7753
    if (isset($setting[$tool_id])) {
7754
        $visibility = 'invisible';
7755
        if ($setting[$tool_id] == 'true') {
7756
            $visibility = 'visible';
7757
        }
7758
7759
        // Read the portal and course default visibility
7760
        if ($tool_id === 'documents') {
7761
            $visibility = DocumentManager::getDocumentDefaultVisibility($courseInfo);
7762
        }
7763
7764
        api_item_property_update(
7765
            $courseInfo,
7766
            $original_tool_id,
7767
            $item_id,
7768
            $visibility,
7769
            $userId,
7770
            $groupInfo,
7771
            null,
7772
            null,
7773
            null,
7774
            $sessionId
7775
        );
7776
7777
        // Fixes default visibility for tests
7778
        switch ($original_tool_id) {
7779
            case TOOL_QUIZ:
7780
                if (empty($sessionId)) {
7781
                    $objExerciseTmp = new Exercise($courseId);
7782
                    $objExerciseTmp->read($item_id);
7783
                    if ($visibility == 'visible') {
7784
                        $objExerciseTmp->enable();
7785
                        $objExerciseTmp->save();
7786
                    } else {
7787
                        $objExerciseTmp->disable();
7788
                        $objExerciseTmp->save();
7789
                    }
7790
                }
7791
                break;
7792
        }
7793
    }
7794
}
7795
7796
/**
7797
 * @return string
7798
 */
7799
function api_get_security_key()
7800
{
7801
    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...
7802
}
7803
7804
/**
7805
 * @param int $user_id
7806
 * @param int $courseId
7807
 * @param int $session_id
7808
 *
7809
 * @return array
7810
 */
7811
function api_detect_user_roles($user_id, $courseId, $session_id = 0)
7812
{
7813
    $user_roles = [];
7814
    $courseInfo = api_get_course_info_by_id($courseId);
7815
    $course_code = $courseInfo['code'];
7816
7817
    $url_id = api_get_current_access_url_id();
7818
    if (api_is_platform_admin_by_id($user_id, $url_id)) {
7819
        $user_roles[] = PLATFORM_ADMIN;
7820
    }
7821
7822
    /*if (api_is_drh()) {
7823
        $user_roles[] = DRH;
7824
    }*/
7825
7826
    if (!empty($session_id)) {
7827
        if (SessionManager::user_is_general_coach($user_id, $session_id)) {
7828
            $user_roles[] = SESSION_GENERAL_COACH;
7829
        }
7830
    }
7831
7832
    if (!empty($course_code)) {
7833
        if (empty($session_id)) {
7834
            if (CourseManager::is_course_teacher($user_id, $course_code)) {
7835
                $user_roles[] = COURSEMANAGER;
7836
            }
7837
            if (CourseManager::get_tutor_in_course_status($user_id, $courseInfo['real_id'])) {
7838
                $user_roles[] = COURSE_TUTOR;
7839
            }
7840
7841
            if (CourseManager::is_user_subscribed_in_course($user_id, $course_code)) {
7842
                $user_roles[] = COURSE_STUDENT;
7843
            }
7844
        } else {
7845
            $user_status_in_session = SessionManager::get_user_status_in_course_session(
7846
                $user_id,
7847
                $courseId,
7848
                $session_id
7849
            );
7850
7851
            if (!empty($user_status_in_session)) {
7852
                if ($user_status_in_session == 0) {
7853
                    $user_roles[] = SESSION_STUDENT;
7854
                }
7855
                if ($user_status_in_session == 2) {
7856
                    $user_roles[] = SESSION_COURSE_COACH;
7857
                }
7858
            }
7859
7860
            /*if (api_is_course_session_coach($user_id, $course_code, $session_id)) {
7861
               $user_roles[] = SESSION_COURSE_COACH;
7862
            }*/
7863
        }
7864
    }
7865
7866
    return $user_roles;
7867
}
7868
7869
/**
7870
 * @param int $courseId
7871
 * @param int $session_id
7872
 *
7873
 * @return bool
7874
 */
7875
function api_coach_can_edit_view_results($courseId = null, $session_id = null)
7876
{
7877
    if (api_is_platform_admin()) {
7878
        return true;
7879
    }
7880
7881
    $user_id = api_get_user_id();
7882
7883
    if (empty($courseId)) {
7884
        $courseId = api_get_course_int_id();
7885
    }
7886
7887
    if (empty($session_id)) {
7888
        $session_id = api_get_session_id();
7889
    }
7890
7891
    $roles = api_detect_user_roles($user_id, $courseId, $session_id);
7892
7893
    if (in_array(SESSION_COURSE_COACH, $roles)) {
7894
        //return api_get_setting('session_tutor_reports_visibility') == 'true';
7895
        return true;
7896
    } else {
7897
        if (in_array(COURSEMANAGER, $roles)) {
7898
            return true;
7899
        }
7900
7901
        return false;
7902
    }
7903
}
7904
7905
/**
7906
 * @param string $file
7907
 *
7908
 * @return string
7909
 */
7910
function api_get_js_simple($file)
7911
{
7912
    return '<script type="text/javascript" src="'.$file.'"></script>'."\n";
7913
}
7914
7915
function api_set_settings_and_plugins()
7916
{
7917
    global $_configuration;
7918
    $_setting = [];
7919
    $_plugins = [];
7920
7921
    // access_url == 1 is the default chamilo location
7922
    $settings_by_access_list = [];
7923
    $access_url_id = api_get_current_access_url_id();
7924
    if ($access_url_id != 1) {
7925
        $url_info = api_get_access_url($_configuration['access_url']);
7926
        if ($url_info['active'] == 1) {
7927
            $settings_by_access = &api_get_settings(null, 'list', $_configuration['access_url'], 1);
7928
            foreach ($settings_by_access as &$row) {
7929
                if (empty($row['variable'])) {
7930
                    $row['variable'] = 0;
7931
                }
7932
                if (empty($row['subkey'])) {
7933
                    $row['subkey'] = 0;
7934
                }
7935
                if (empty($row['category'])) {
7936
                    $row['category'] = 0;
7937
                }
7938
                $settings_by_access_list[$row['variable']][$row['subkey']][$row['category']] = $row;
7939
            }
7940
        }
7941
    }
7942
7943
    $result = api_get_settings(null, 'list', 1);
7944
7945
    foreach ($result as &$row) {
7946
        if ($access_url_id != 1) {
7947
            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...
7948
                $var = empty($row['variable']) ? 0 : $row['variable'];
7949
                $subkey = empty($row['subkey']) ? 0 : $row['subkey'];
7950
                $category = empty($row['category']) ? 0 : $row['category'];
7951
            }
7952
7953
            if ($row['access_url_changeable'] == 1 && $url_info['active'] == 1) {
7954
                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...
7955
                    $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...
7956
                    if ($row['subkey'] == null) {
7957
                        $_setting[$row['variable']] = $settings_by_access_list[$var][$subkey][$category]['selected_value'];
7958
                    } else {
7959
                        $_setting[$row['variable']][$row['subkey']] = $settings_by_access_list[$var][$subkey][$category]['selected_value'];
7960
                    }
7961
                } else {
7962
                    if ($row['subkey'] == null) {
7963
                        $_setting[$row['variable']] = $row['selected_value'];
7964
                    } else {
7965
                        $_setting[$row['variable']][$row['subkey']] = $row['selected_value'];
7966
                    }
7967
                }
7968
            } else {
7969
                if ($row['subkey'] == null) {
7970
                    $_setting[$row['variable']] = $row['selected_value'];
7971
                } else {
7972
                    $_setting[$row['variable']][$row['subkey']] = $row['selected_value'];
7973
                }
7974
            }
7975
        } else {
7976
            if ($row['subkey'] == null) {
7977
                $_setting[$row['variable']] = $row['selected_value'];
7978
            } else {
7979
                $_setting[$row['variable']][$row['subkey']] = $row['selected_value'];
7980
            }
7981
        }
7982
    }
7983
7984
    $result = api_get_settings('Plugins', 'list', $access_url_id);
7985
    $_plugins = [];
7986
    foreach ($result as &$row) {
7987
        $key = &$row['variable'];
7988
        if (is_string($_setting[$key])) {
7989
            $_setting[$key] = [];
7990
        }
7991
        $_setting[$key][] = $row['selected_value'];
7992
        $_plugins[$key][] = $row['selected_value'];
7993
    }
7994
7995
    $_SESSION['_setting'] = $_setting;
7996
    $_SESSION['_plugins'] = $_plugins;
7997
}
7998
7999
/**
8000
 * Modify default memory_limit and max_execution_time limits
8001
 * Needed when processing long tasks.
8002
 */
8003
function api_set_more_memory_and_time_limits()
8004
{
8005
    if (function_exists('ini_set')) {
8006
        api_set_memory_limit('256M');
8007
        ini_set('max_execution_time', 1800);
8008
    }
8009
}
8010
8011
/**
8012
 * Tries to set memory limit, if authorized and new limit is higher than current.
8013
 *
8014
 * @param string $mem New memory limit
8015
 *
8016
 * @return bool True on success, false on failure or current is higher than suggested
8017
 * @assert (null) === false
8018
 * @assert (-1) === false
8019
 * @assert (0) === true
8020
 * @assert ('1G') === true
8021
 */
8022
function api_set_memory_limit($mem)
8023
{
8024
    //if ini_set() not available, this function is useless
8025
    if (!function_exists('ini_set') || is_null($mem) || $mem == -1) {
8026
        return false;
8027
    }
8028
8029
    $memory_limit = ini_get('memory_limit');
8030
    if (api_get_bytes_memory_limit($mem) > api_get_bytes_memory_limit($memory_limit)) {
8031
        ini_set('memory_limit', $mem);
8032
8033
        return true;
8034
    }
8035
8036
    return false;
8037
}
8038
8039
/**
8040
 * Gets memory limit in bytes.
8041
 *
8042
 * @param string The memory size (128M, 1G, 1000K, etc)
8043
 *
8044
 * @return int
8045
 * @assert (null) === false
8046
 * @assert ('1t')  === 1099511627776
8047
 * @assert ('1g')  === 1073741824
8048
 * @assert ('1m')  === 1048576
8049
 * @assert ('100k') === 102400
8050
 */
8051
function api_get_bytes_memory_limit($mem)
8052
{
8053
    $size = strtolower(substr($mem, -1));
8054
8055
    switch ($size) {
8056
        case 't':
8057
            $mem = intval(substr($mem, -1)) * 1024 * 1024 * 1024 * 1024;
8058
            break;
8059
        case 'g':
8060
            $mem = intval(substr($mem, 0, -1)) * 1024 * 1024 * 1024;
8061
            break;
8062
        case 'm':
8063
            $mem = intval(substr($mem, 0, -1)) * 1024 * 1024;
8064
            break;
8065
        case 'k':
8066
            $mem = intval(substr($mem, 0, -1)) * 1024;
8067
            break;
8068
        default:
8069
            // we assume it's integer only
8070
            $mem = intval($mem);
8071
            break;
8072
    }
8073
8074
    return $mem;
8075
}
8076
8077
/**
8078
 * Finds all the information about a user from username instead of user id.
8079
 *
8080
 * @param string $officialCode
8081
 *
8082
 * @return array $user_info user_id, lastname, firstname, username, email, ...
8083
 *
8084
 * @author Yannick Warnier <[email protected]>
8085
 */
8086
function api_get_user_info_from_official_code($officialCode)
8087
{
8088
    if (empty($officialCode)) {
8089
        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...
8090
    }
8091
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
8092
            WHERE official_code ='".Database::escape_string($officialCode)."'";
8093
    $result = Database::query($sql);
8094
    if (Database::num_rows($result) > 0) {
8095
        $result_array = Database::fetch_array($result);
8096
8097
        return _api_format_user($result_array);
8098
    }
8099
8100
    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...
8101
}
8102
8103
/**
8104
 * @param string $usernameInputId
8105
 * @param string $passwordInputId
8106
 *
8107
 * @return string|null
8108
 */
8109
function api_get_password_checker_js($usernameInputId, $passwordInputId)
8110
{
8111
    $checkPass = api_get_setting('allow_strength_pass_checker');
8112
    $useStrengthPassChecker = $checkPass === 'true';
8113
8114
    if ($useStrengthPassChecker === false) {
8115
        return null;
8116
    }
8117
8118
    $translations = [
8119
        'wordLength' => get_lang('PasswordIsTooShort'),
8120
        'wordNotEmail' => get_lang('YourPasswordCannotBeTheSameAsYourEmail'),
8121
        'wordSimilarToUsername' => get_lang('YourPasswordCannotContainYourUsername'),
8122
        'wordTwoCharacterClasses' => get_lang('WordTwoCharacterClasses'),
8123
        'wordRepetitions' => get_lang('TooManyRepetitions'),
8124
        'wordSequences' => get_lang('YourPasswordContainsSequences'),
8125
        'errorList' => get_lang('ErrorsFound'),
8126
        'veryWeak' => get_lang('PasswordVeryWeak'),
8127
        'weak' => get_lang('PasswordWeak'),
8128
        'normal' => get_lang('PasswordNormal'),
8129
        'medium' => get_lang('PasswordMedium'),
8130
        'strong' => get_lang('PasswordStrong'),
8131
        'veryStrong' => get_lang('PasswordVeryStrong'),
8132
    ];
8133
8134
    $js = api_get_asset('pwstrength-bootstrap/dist/pwstrength-bootstrap.min.js');
8135
    $js .= "<script>
8136
    var errorMessages = {
8137
        password_to_short : \"".get_lang('PasswordIsTooShort')."\",
8138
        same_as_username : \"".get_lang('YourPasswordCannotBeTheSameAsYourUsername')."\"
8139
    };
8140
8141
    $(function() {
8142
        var lang = ".json_encode($translations).";     
8143
        var options = {        
8144
            onLoad : function () {
8145
                //$('#messages').text('Start typing password');
8146
            },
8147
            onKeyUp: function (evt) {
8148
                $(evt.target).pwstrength('outputErrorList');
8149
            },
8150
            errorMessages : errorMessages,
8151
            viewports: {
8152
                progress: '#password_progress',
8153
                verdict: '#password-verdict',
8154
                errors: '#password-errors'
8155
            },
8156
            usernameField: '$usernameInputId'
8157
        };
8158
        options.i18n = {
8159
            t: function (key) {
8160
                var result = lang[key];
8161
                return result === key ? '' : result; // This assumes you return the                
8162
            }
8163
        };
8164
        $('".$passwordInputId."').pwstrength(options);
8165
    });
8166
    </script>";
8167
8168
    return $js;
8169
}
8170
8171
/**
8172
 * create an user extra field called 'captcha_blocked_until_date'.
8173
 *
8174
 * @param string $username
8175
 *
8176
 * @return bool
8177
 */
8178
function api_block_account_captcha($username)
8179
{
8180
    $userInfo = api_get_user_info_from_username($username);
8181
    if (empty($userInfo)) {
8182
        return false;
8183
    }
8184
    $minutesToBlock = api_get_setting('captcha_time_to_block');
8185
    $time = time() + $minutesToBlock * 60;
8186
    UserManager::update_extra_field_value(
8187
        $userInfo['user_id'],
8188
        'captcha_blocked_until_date',
8189
        api_get_utc_datetime($time)
8190
    );
8191
8192
    return true;
8193
}
8194
8195
/**
8196
 * @param string $username
8197
 *
8198
 * @return bool
8199
 */
8200
function api_clean_account_captcha($username)
8201
{
8202
    $userInfo = api_get_user_info_from_username($username);
8203
    if (empty($userInfo)) {
8204
        return false;
8205
    }
8206
    Session::erase('loginFailedCount');
8207
    UserManager::update_extra_field_value(
8208
        $userInfo['user_id'],
8209
        'captcha_blocked_until_date',
8210
        null
8211
    );
8212
8213
    return true;
8214
}
8215
8216
/**
8217
 * @param string $username
8218
 *
8219
 * @return bool
8220
 */
8221
function api_get_user_blocked_by_captcha($username)
8222
{
8223
    $userInfo = api_get_user_info_from_username($username);
8224
    if (empty($userInfo)) {
8225
        return false;
8226
    }
8227
    $data = UserManager::get_extra_user_data_by_field(
8228
        $userInfo['user_id'],
8229
        'captcha_blocked_until_date'
8230
    );
8231
    if (isset($data) && isset($data['captcha_blocked_until_date'])) {
8232
        return $data['captcha_blocked_until_date'];
8233
    }
8234
8235
    return false;
8236
}
8237
8238
/**
8239
 * Remove tags from HTML anf return the $in_number_char first non-HTML char
8240
 * Postfix the text with "..." if it has been truncated.
8241
 *
8242
 * @param string $text
8243
 * @param int    $number
8244
 *
8245
 * @return string
8246
 *
8247
 * @author hubert borderiou
8248
 */
8249
function api_get_short_text_from_html($text, $number)
8250
{
8251
    // Delete script and style tags
8252
    $text = preg_replace('/(<(script|style)\b[^>]*>).*?(<\/\2>)/is', "$1$3", $text);
8253
    $text = api_html_entity_decode($text);
8254
    $out_res = api_remove_tags_with_space($text, false);
8255
    $postfix = "...";
8256
    if (strlen($out_res) > $number) {
8257
        $out_res = substr($out_res, 0, $number).$postfix;
8258
    }
8259
8260
    return $out_res;
8261
}
8262
8263
/**
8264
 * Replace tags with a space in a text.
8265
 * If $in_double_quote_replace, replace " with '' (for HTML attribute purpose, for exemple).
8266
 *
8267
 * @return string
8268
 *
8269
 * @author hubert borderiou
8270
 */
8271
function api_remove_tags_with_space($in_html, $in_double_quote_replace = true)
8272
{
8273
    $out_res = $in_html;
8274
    if ($in_double_quote_replace) {
8275
        $out_res = str_replace('"', "''", $out_res);
8276
    }
8277
    // avoid text stuck together when tags are removed, adding a space after >
8278
    $out_res = str_replace(">", "> ", $out_res);
8279
    $out_res = strip_tags($out_res);
8280
8281
    return $out_res;
8282
}
8283
8284
/**
8285
 * If true, the drh can access all content (courses, users) inside a session.
8286
 *
8287
 * @return bool
8288
 */
8289
function api_drh_can_access_all_session_content()
8290
{
8291
    $value = api_get_setting('drh_can_access_all_session_content');
8292
8293
    return $value === 'true';
8294
}
8295
8296
/**
8297
 * @param string $tool
8298
 * @param string $setting
8299
 * @param int    $defaultValue
8300
 *
8301
 * @return string
8302
 */
8303
function api_get_default_tool_setting($tool, $setting, $defaultValue)
8304
{
8305
    global $_configuration;
8306
    if (isset($_configuration[$tool]) &&
8307
        isset($_configuration[$tool]['default_settings']) &&
8308
        isset($_configuration[$tool]['default_settings'][$setting])
8309
    ) {
8310
        return $_configuration[$tool]['default_settings'][$setting];
8311
    }
8312
8313
    return $defaultValue;
8314
}
8315
8316
/**
8317
 * Checks if user can login as another user.
8318
 *
8319
 * @param int $loginAsUserId the user id to log in
8320
 * @param int $userId        my user id
8321
 *
8322
 * @return bool
8323
 */
8324
function api_can_login_as($loginAsUserId, $userId = null)
8325
{
8326
    if (empty($userId)) {
8327
        $userId = api_get_user_id();
8328
    }
8329
    if ($loginAsUserId == $userId) {
8330
        return false;
8331
    }
8332
8333
    if (empty($loginAsUserId)) {
8334
        return false;
8335
    }
8336
8337
    if ($loginAsUserId != strval(intval($loginAsUserId))) {
8338
        return false;
8339
    }
8340
8341
    // Check if the user to login is an admin
8342
    if (api_is_platform_admin_by_id($loginAsUserId)) {
8343
        // Only super admins can login to admin accounts
8344
        if (!api_global_admin_can_edit_admin($loginAsUserId)) {
8345
            return false;
8346
        }
8347
    }
8348
8349
    $userInfo = api_get_user_info($loginAsUserId);
8350
    $isDrh = function () use ($loginAsUserId) {
8351
        if (api_is_drh()) {
8352
            if (api_drh_can_access_all_session_content()) {
8353
                $users = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus(
8354
                    'drh_all',
8355
                    api_get_user_id()
8356
                );
8357
                $userList = [];
8358
                if (is_array($users)) {
8359
                    foreach ($users as $user) {
8360
                        $userList[] = $user['user_id'];
8361
                    }
8362
                }
8363
                if (in_array($loginAsUserId, $userList)) {
8364
                    return true;
8365
                }
8366
            } else {
8367
                if (api_is_drh() &&
8368
                    UserManager::is_user_followed_by_drh($loginAsUserId, api_get_user_id())
8369
                ) {
8370
                    return true;
8371
                }
8372
            }
8373
        }
8374
8375
        return false;
8376
    };
8377
8378
    $loginAsStatusForSessionAdmins = [STUDENT];
8379
8380
    if (api_get_setting('session.allow_session_admin_login_as_teacher')) {
8381
        $loginAsStatusForSessionAdmins[] = COURSEMANAGER;
8382
    }
8383
8384
    return api_is_platform_admin() ||
8385
        (api_is_session_admin() && in_array($userInfo['status'], $loginAsStatusForSessionAdmins)) ||
8386
        $isDrh();
8387
}
8388
8389
/**
8390
 * @return bool
8391
 */
8392
function api_is_allowed_in_course()
8393
{
8394
    if (api_is_platform_admin()) {
8395
        return true;
8396
    }
8397
8398
    $user = api_get_current_user();
8399
    if ($user instanceof User) {
8400
        if ($user->hasRole('ROLE_CURRENT_SESSION_COURSE_STUDENT') ||
8401
            $user->hasRole('ROLE_CURRENT_SESSION_COURSE_TEACHER') ||
8402
            $user->hasRole('ROLE_CURRENT_COURSE_STUDENT') ||
8403
            $user->hasRole('ROLE_CURRENT_COURSE_TEACHER')
8404
        ) {
8405
            return true;
8406
        }
8407
    }
8408
8409
    return false;
8410
}
8411
8412
/**
8413
 * Set the cookie to go directly to the course code $in_firstpage
8414
 * after login.
8415
 *
8416
 * @param string $value is the course code of the course to go
8417
 */
8418
function api_set_firstpage_parameter($value)
8419
{
8420
    setcookie('GotoCourse', $value);
8421
}
8422
8423
/**
8424
 * Delete the cookie to go directly to the course code $in_firstpage
8425
 * after login.
8426
 */
8427
function api_delete_firstpage_parameter()
8428
{
8429
    setcookie('GotoCourse', '', time() - 3600);
8430
}
8431
8432
/**
8433
 * @return bool if course_code for direct course access after login is set
8434
 */
8435
function exist_firstpage_parameter()
8436
{
8437
    return isset($_COOKIE['GotoCourse']) && $_COOKIE['GotoCourse'] != '';
8438
}
8439
8440
/**
8441
 * @return return the course_code of the course where user login
8442
 */
8443
function api_get_firstpage_parameter()
8444
{
8445
    return $_COOKIE['GotoCourse'];
8446
}
8447
8448
/**
8449
 * Return true on https install.
8450
 *
8451
 * @return bool
8452
 */
8453
function api_is_https()
8454
{
8455
    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...
8456
        $_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...
8457
    ) {
8458
        $isSecured = true;
8459
    } else {
8460
        if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') {
8461
            $isSecured = true;
8462
        } else {
8463
            $isSecured = false;
8464
            // last chance
8465
            if (!empty($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443) {
8466
                $isSecured = true;
8467
            }
8468
        }
8469
    }
8470
8471
    return $isSecured;
8472
}
8473
8474
/**
8475
 * Return protocol (http or https).
8476
 *
8477
 * @return string
8478
 */
8479
function api_get_protocol()
8480
{
8481
    return api_is_https() ? 'https' : 'http';
8482
}
8483
8484
/**
8485
 * Return a string where " are replaced with 2 '
8486
 * It is useful when you pass a PHP variable in a Javascript browser dialog
8487
 * e.g. : alert("<?php get_lang('Message') ?>");
8488
 * and message contains character ".
8489
 *
8490
 * @param string $in_text
8491
 *
8492
 * @return string
8493
 */
8494
function convert_double_quote_to_single($in_text)
8495
{
8496
    return api_preg_replace('/"/', "''", $in_text);
8497
}
8498
8499
/**
8500
 * Get origin.
8501
 *
8502
 * @param string
8503
 *
8504
 * @return string
8505
 */
8506
function api_get_origin()
8507
{
8508
    $origin = isset($_REQUEST['origin']) ? Security::remove_XSS($_REQUEST['origin']) : '';
8509
8510
    return $origin;
8511
}
8512
8513
/**
8514
 * Warns an user that the portal reach certain limit.
8515
 *
8516
 * @param string $limitName
8517
 */
8518
function api_warn_hosting_contact($limitName)
8519
{
8520
    $hostingParams = api_get_configuration_value(1);
8521
    $email = null;
8522
8523
    if (!empty($hostingParams)) {
8524
        if (isset($hostingParams['hosting_contact_mail'])) {
8525
            $email = $hostingParams['hosting_contact_mail'];
8526
        }
8527
    }
8528
8529
    if (!empty($email)) {
8530
        $subject = get_lang('HostingWarningReached');
8531
        $body = get_lang('PortalName').': '.api_get_path(WEB_PATH)." \n ";
8532
        $body .= get_lang('PortalLimitType').': '.$limitName." \n ";
8533
        if (isset($hostingParams[$limitName])) {
8534
            $body .= get_lang('Value').': '.$hostingParams[$limitName];
8535
        }
8536
        api_mail_html(null, $email, $subject, $body);
8537
    }
8538
}
8539
8540
/**
8541
 * Gets value of a variable from config/configuration.php
8542
 * Variables that are not set in the configuration.php file but set elsewhere:
8543
 * - virtual_css_theme_folder (vchamilo plugin)
8544
 * - access_url (global.inc.php)
8545
 * - apc/apc_prefix (global.inc.php).
8546
 *
8547
 * @param string $variable
8548
 *
8549
 * @return bool|mixed
8550
 */
8551
function api_get_configuration_value($variable)
8552
{
8553
    global $_configuration;
8554
    // Check the current url id, id = 1 by default
8555
    $urlId = isset($_configuration['access_url']) ? (int) $_configuration['access_url'] : 1;
8556
8557
    $variable = trim($variable);
8558
8559
    // Check if variable exists
8560
    if (isset($_configuration[$variable])) {
8561
        if (is_array($_configuration[$variable])) {
8562
            // Check if it exists for the sub portal
8563
            if (array_key_exists($urlId, $_configuration[$variable])) {
8564
                return $_configuration[$variable][$urlId];
8565
            } else {
8566
                // Try to found element with id = 1 (master portal)
8567
                if (array_key_exists(1, $_configuration[$variable])) {
8568
                    return $_configuration[$variable][1];
8569
                }
8570
            }
8571
        }
8572
8573
        return $_configuration[$variable];
8574
    }
8575
8576
    return false;
8577
}
8578
8579
/**
8580
 * Returns supported image extensions in the portal.
8581
 *
8582
 * @param bool $supportVectors Whether vector images should also be accepted or not
8583
 *
8584
 * @return array Supported image extensions in the portal
8585
 */
8586
function api_get_supported_image_extensions($supportVectors = true)
8587
{
8588
    // jpg can also be called jpeg, jpe, jfif and jif. See https://en.wikipedia.org/wiki/JPEG#JPEG_filename_extensions
8589
    $supportedImageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'jpe', 'jfif', 'jif'];
8590
    if ($supportVectors) {
8591
        array_push($supportedImageExtensions, 'svg');
8592
    }
8593
    if (version_compare(PHP_VERSION, '5.5.0', '>=')) {
8594
        array_push($supportedImageExtensions, 'webp');
8595
    }
8596
8597
    return $supportedImageExtensions;
8598
}
8599
8600
/**
8601
 * This setting changes the registration status for the campus.
8602
 *
8603
 * @author Patrick Cool <[email protected]>, Ghent University
8604
 *
8605
 * @version August 2006
8606
 *
8607
 * @param bool $listCampus Whether we authorize
8608
 *
8609
 * @todo the $_settings should be reloaded here. => write api function for this and use this in global.inc.php also.
8610
 */
8611
function api_register_campus($listCampus = true)
8612
{
8613
    $tbl_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
8614
8615
    $sql = "UPDATE $tbl_settings SET selected_value='true' WHERE variable='registered'";
8616
    Database::query($sql);
8617
8618
    if (!$listCampus) {
8619
        $sql = "UPDATE $tbl_settings SET selected_value='true' WHERE variable='donotlistcampus'";
8620
        Database::query($sql);
8621
    }
8622
}
8623
8624
/**
8625
 * Checks whether current user is a student boss.
8626
 *
8627
 * @global array $_user
8628
 *
8629
 * @return bool
8630
 */
8631
function api_is_student_boss()
8632
{
8633
    $_user = api_get_user_info();
8634
8635
    return isset($_user['status']) && $_user['status'] == STUDENT_BOSS;
8636
}
8637
8638
/**
8639
 * Check whether the user type should be exclude.
8640
 * Such as invited or anonymous users.
8641
 *
8642
 * @param bool $checkDB Optional. Whether check the user status
8643
 * @param int  $userId  Options. The user id
8644
 *
8645
 * @return bool
8646
 */
8647
function api_is_excluded_user_type($checkDB = false, $userId = 0)
8648
{
8649
    if ($checkDB) {
8650
        $userId = empty($userId) ? api_get_user_id() : (int) $userId;
8651
8652
        if ($userId == 0) {
8653
            return true;
8654
        }
8655
8656
        $userInfo = api_get_user_info($userId);
8657
8658
        switch ($userInfo['status']) {
8659
            case INVITEE:
8660
            case ANONYMOUS:
8661
                return true;
8662
            default:
8663
                return false;
8664
        }
8665
    }
8666
8667
    $isInvited = api_is_invitee();
8668
    $isAnonymous = api_is_anonymous();
8669
8670
    if ($isInvited || $isAnonymous) {
8671
        return true;
8672
    }
8673
8674
    return false;
8675
}
8676
8677
/**
8678
 * Get the user status to ignore in reports.
8679
 *
8680
 * @param string $format Optional. The result type (array or string)
8681
 *
8682
 * @return array|string
8683
 */
8684
function api_get_users_status_ignored_in_reports($format = 'array')
8685
{
8686
    $excludedTypes = [
8687
        INVITEE,
8688
        ANONYMOUS,
8689
    ];
8690
8691
    if ($format == 'string') {
8692
        return implode(', ', $excludedTypes);
8693
    }
8694
8695
    return $excludedTypes;
8696
}
8697
8698
/**
8699
 * Set the Site Use Cookie Warning for 1 year.
8700
 */
8701
function api_set_site_use_cookie_warning_cookie()
8702
{
8703
    setcookie('ChamiloUsesCookies', 'ok', time() + 31556926);
8704
}
8705
8706
/**
8707
 * Return true if the Site Use Cookie Warning Cookie warning exists.
8708
 *
8709
 * @return bool
8710
 */
8711
function api_site_use_cookie_warning_cookie_exist()
8712
{
8713
    return isset($_COOKIE['ChamiloUsesCookies']);
8714
}
8715
8716
/**
8717
 * Given a number of seconds, format the time to show hours, minutes and seconds.
8718
 *
8719
 * @param int    $time         The time in seconds
8720
 * @param string $originFormat Optional. PHP o JS
8721
 *
8722
 * @return string (00h00'00")
8723
 */
8724
function api_format_time($time, $originFormat = 'php')
8725
{
8726
    $h = get_lang('h');
8727
    $hours = $time / 3600;
8728
    $mins = ($time % 3600) / 60;
8729
    $secs = ($time % 60);
8730
8731
    if ($time < 0) {
8732
        $hours = 0;
8733
        $mins = 0;
8734
        $secs = 0;
8735
    }
8736
8737
    if ($originFormat == 'js') {
8738
        $formattedTime = trim(sprintf("%02d : %02d : %02d", $hours, $mins, $secs));
8739
    } else {
8740
        $formattedTime = trim(sprintf("%02d$h%02d'%02d\"", $hours, $mins, $secs));
8741
    }
8742
8743
    return $formattedTime;
8744
}
8745
8746
/**
8747
 * Create a new empty directory with index.html file.
8748
 *
8749
 * @param string $name            The new directory name
8750
 * @param string $parentDirectory Directory parent directory name
8751
 *
8752
 * @return bool Return true if the directory was create. Otherwise return false
8753
 */
8754
function api_create_protected_dir($name, $parentDirectory)
8755
{
8756
    $isCreated = false;
8757
8758
    if (!is_writable($parentDirectory)) {
8759
        return false;
8760
    }
8761
8762
    $fullPath = $parentDirectory.api_replace_dangerous_char($name);
8763
8764
    if (mkdir($fullPath, api_get_permissions_for_new_directories(), true)) {
8765
        $fp = fopen($fullPath.'/index.html', 'w');
8766
8767
        if ($fp) {
0 ignored issues
show
introduced by
$fp is of type false|resource, thus it always evaluated to false.
Loading history...
8768
            if (fwrite($fp, '<html><head></head><body></body></html>')) {
8769
                $isCreated = true;
8770
            }
8771
        }
8772
8773
        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

8773
        fclose(/** @scrutinizer ignore-type */ $fp);
Loading history...
8774
    }
8775
8776
    return $isCreated;
8777
}
8778
8779
/**
8780
 * Sends an email
8781
 * Sender name and email can be specified, if not specified
8782
 * name and email of the platform admin are used.
8783
 *
8784
 * @param string    name of recipient
8785
 * @param string    email of recipient
8786
 * @param string    email subject
8787
 * @param string    email body
8788
 * @param string    sender name
8789
 * @param string    sender e-mail
8790
 * @param array     extra headers in form $headers = array($name => $value) to allow parsing
8791
 * @param array     data file (path and filename)
8792
 * @param bool      True for attaching a embedded file inside content html (optional)
8793
 * @param array     Additional parameters
8794
 *
8795
 * @return bool true if mail was sent
8796
 */
8797
function api_mail_html(
8798
    $recipientName,
8799
    $recipientEmail,
8800
    $subject,
8801
    $body,
8802
    $senderName = '',
8803
    $senderEmail = '',
8804
    $extra_headers = [],
8805
    $data_file = [],
8806
    $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

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