Completed
Push — master ( 38e61c...cd9a17 )
by Julito
14:03
created

api_get_build_js()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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

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

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

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

// Bar.php
namespace OtherDir;

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

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

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

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

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
5
use Chamilo\CoreBundle\Entity\Session as SessionEntity;
6
use Chamilo\CoreBundle\Entity\SettingsCurrent;
7
use Chamilo\CoreBundle\Framework\Container;
8
use Chamilo\CourseBundle\Entity\CItemProperty;
9
use Chamilo\ThemeBundle\Controller\ExceptionController;
10
use Chamilo\UserBundle\Entity\User;
11
use ChamiloSession as Session;
12
use Symfony\Component\Debug\Exception\FlattenException;
13
use Symfony\Component\Finder\Finder;
14
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
15
16
/**
17
 * This is a code library for Chamilo.
18
 * It is included by default in every Chamilo file (through including the global.inc.php)
19
 * This library is in process of being transferred to src/Chamilo/CoreBundle/Component/Utils/ChamiloApi.
20
 * Whenever a function is transferred to the ChamiloApi class, the places where it is used should include
21
 * the "use Chamilo\CoreBundle\Component\Utils\ChamiloApi;" statement.
22
 *
23
 * @package chamilo.library
24
 */
25
26
// PHP version requirement.
27
define('REQUIRED_PHP_VERSION', '7.2');
28
define('REQUIRED_MIN_MEMORY_LIMIT', '128');
29
define('REQUIRED_MIN_UPLOAD_MAX_FILESIZE', '10');
30
define('REQUIRED_MIN_POST_MAX_SIZE', '10');
31
32
// USER STATUS CONSTANTS
33
/** global status of a user: student */
34
define('STUDENT', 5);
35
/** global status of a user: course manager */
36
define('COURSEMANAGER', 1);
37
/** global status of a user: session admin */
38
define('SESSIONADMIN', 3);
39
/** global status of a user: human ressource manager */
40
define('DRH', 4);
41
/** global status of a user: human ressource manager */
42
define('ANONYMOUS', 6);
43
/** global status of a user: low security, necessary for inserting data from
44
 * the teacher through HTMLPurifier */
45
define('COURSEMANAGERLOWSECURITY', 10);
46
// Soft user status
47
define('PLATFORM_ADMIN', 11);
48
define('SESSION_COURSE_COACH', 12);
49
define('SESSION_GENERAL_COACH', 13);
50
define('COURSE_STUDENT', 14); //student subscribed in a course
51
define('SESSION_STUDENT', 15); //student subscribed in a session course
52
define('COURSE_TUTOR', 16); // student is tutor of a course (NOT in session)
53
define('STUDENT_BOSS', 17); // student is boss
54
define('INVITEE', 20);
55
define('HRM_REQUEST', 21); //HRM has request for vinculation with user
56
57
// Table of status
58
$_status_list[COURSEMANAGER] = 'teacher'; // 1
59
$_status_list[SESSIONADMIN] = 'session_admin'; // 3
60
$_status_list[DRH] = 'drh'; // 4
61
$_status_list[STUDENT] = 'user'; // 5
62
$_status_list[ANONYMOUS] = 'anonymous'; // 6
63
$_status_list[INVITEE] = 'invited'; // 20
64
65
// COURSE VISIBILITY CONSTANTS
66
/** only visible for course admin */
67
define('COURSE_VISIBILITY_CLOSED', 0);
68
/** only visible for users registered in the course */
69
define('COURSE_VISIBILITY_REGISTERED', 1);
70
/** Open for all registered users on the platform */
71
define('COURSE_VISIBILITY_OPEN_PLATFORM', 2);
72
/** Open for the whole world */
73
define('COURSE_VISIBILITY_OPEN_WORLD', 3);
74
/** Invisible to all except admin */
75
define('COURSE_VISIBILITY_HIDDEN', 4);
76
77
define('COURSE_REQUEST_PENDING', 0);
78
define('COURSE_REQUEST_ACCEPTED', 1);
79
define('COURSE_REQUEST_REJECTED', 2);
80
define('DELETE_ACTION_ENABLED', false);
81
82
// EMAIL SENDING RECIPIENT CONSTANTS
83
define('SEND_EMAIL_EVERYONE', 1);
84
define('SEND_EMAIL_STUDENTS', 2);
85
define('SEND_EMAIL_TEACHERS', 3);
86
87
// SESSION VISIBILITY CONSTANTS
88
define('SESSION_VISIBLE_READ_ONLY', 1);
89
define('SESSION_VISIBLE', 2);
90
define('SESSION_INVISIBLE', 3); // not available
91
define('SESSION_AVAILABLE', 4);
92
93
define('SESSION_LINK_TARGET', '_self');
94
95
define('SUBSCRIBE_ALLOWED', 1);
96
define('SUBSCRIBE_NOT_ALLOWED', 0);
97
define('UNSUBSCRIBE_ALLOWED', 1);
98
define('UNSUBSCRIBE_NOT_ALLOWED', 0);
99
100
// SURVEY VISIBILITY CONSTANTS
101
define('SURVEY_VISIBLE_TUTOR', 0);
102
define('SURVEY_VISIBLE_TUTOR_STUDENT', 1);
103
define('SURVEY_VISIBLE_PUBLIC', 2);
104
105
// CONSTANTS defining all tools, using the english version
106
/* When you add a new tool you must add it into function api_get_tools_lists() too */
107
define('TOOL_DOCUMENT', 'document');
108
define('TOOL_LP_FINAL_ITEM', 'final_item');
109
define('TOOL_READOUT_TEXT', 'readout_text');
110
define('TOOL_THUMBNAIL', 'thumbnail');
111
define('TOOL_HOTPOTATOES', 'hotpotatoes');
112
define('TOOL_CALENDAR_EVENT', 'calendar_event');
113
define('TOOL_LINK', 'link');
114
define('TOOL_LINK_CATEGORY', 'link_category');
115
define('TOOL_COURSE_DESCRIPTION', 'course_description');
116
define('TOOL_SEARCH', 'search');
117
define('TOOL_LEARNPATH', 'learnpath');
118
define('TOOL_LEARNPATH_CATEGORY', 'learnpath_category');
119
define('TOOL_AGENDA', 'agenda');
120
define('TOOL_ANNOUNCEMENT', 'announcement');
121
define('TOOL_FORUM', 'forum');
122
define('TOOL_FORUM_CATEGORY', 'forum_category');
123
define('TOOL_FORUM_THREAD', 'forum_thread');
124
define('TOOL_FORUM_POST', 'forum_post');
125
define('TOOL_FORUM_ATTACH', 'forum_attachment');
126
define('TOOL_FORUM_THREAD_QUALIFY', 'forum_thread_qualify');
127
define('TOOL_THREAD', 'thread');
128
define('TOOL_POST', 'post');
129
define('TOOL_DROPBOX', 'dropbox');
130
define('TOOL_QUIZ', 'quiz');
131
define('TOOL_TEST_CATEGORY', 'test_category');
132
define('TOOL_USER', 'user');
133
define('TOOL_GROUP', 'group');
134
define('TOOL_BLOGS', 'blog_management');
135
define('TOOL_CHAT', 'chat');
136
define('TOOL_STUDENTPUBLICATION', 'student_publication');
137
define('TOOL_TRACKING', 'tracking');
138
define('TOOL_HOMEPAGE_LINK', 'homepage_link');
139
define('TOOL_COURSE_SETTING', 'course_setting');
140
define('TOOL_BACKUP', 'backup');
141
define('TOOL_COPY_COURSE_CONTENT', 'copy_course_content');
142
define('TOOL_RECYCLE_COURSE', 'recycle_course');
143
define('TOOL_COURSE_HOMEPAGE', 'course_homepage');
144
define('TOOL_COURSE_RIGHTS_OVERVIEW', 'course_rights');
145
define('TOOL_UPLOAD', 'file_upload');
146
define('TOOL_COURSE_MAINTENANCE', 'course_maintenance');
147
define('TOOL_SURVEY', 'survey');
148
define('TOOL_WIKI', 'wiki');
149
define('TOOL_GLOSSARY', 'glossary');
150
define('TOOL_GRADEBOOK', 'gradebook');
151
define('TOOL_NOTEBOOK', 'notebook');
152
define('TOOL_ATTENDANCE', 'attendance');
153
define('TOOL_COURSE_PROGRESS', 'course_progress');
154
define('TOOL_PORTFOLIO', 'portfolio');
155
define('TOOL_PLAGIARISM', 'compilatio');
156
157
// CONSTANTS defining Chamilo interface sections
158
define('SECTION_CAMPUS', 'mycampus');
159
define('SECTION_COURSES', 'mycourses');
160
define('SECTION_CATALOG', 'catalog');
161
define('SECTION_MYPROFILE', 'myprofile');
162
define('SECTION_MYAGENDA', 'myagenda');
163
define('SECTION_COURSE_ADMIN', 'course_admin');
164
define('SECTION_PLATFORM_ADMIN', 'platform_admin');
165
define('SECTION_MYGRADEBOOK', 'mygradebook');
166
define('SECTION_TRACKING', 'session_my_space');
167
define('SECTION_SOCIAL', 'social-network');
168
define('SECTION_DASHBOARD', 'dashboard');
169
define('SECTION_REPORTS', 'reports');
170
define('SECTION_GLOBAL', 'global');
171
define('SECTION_INCLUDE', 'include');
172
173
// CONSTANT name for local authentication source
174
define('PLATFORM_AUTH_SOURCE', 'platform');
175
define('CAS_AUTH_SOURCE', 'cas');
176
define('LDAP_AUTH_SOURCE', 'extldap');
177
178
// CONSTANT defining the default HotPotatoes files directory
179
define('DIR_HOTPOTATOES', '/HotPotatoes_files');
180
181
// event logs types
182
define('LOG_COURSE_DELETE', 'course_deleted');
183
define('LOG_COURSE_CREATE', 'course_created');
184
185
// @todo replace 'soc_gr' with social_group
186
define('LOG_GROUP_PORTAL_CREATED', 'soc_gr_created');
187
define('LOG_GROUP_PORTAL_UPDATED', 'soc_gr_updated');
188
define('LOG_GROUP_PORTAL_DELETED', 'soc_gr_deleted');
189
define('LOG_GROUP_PORTAL_USER_DELETE_ALL', 'soc_gr_delete_users');
190
191
define('LOG_GROUP_PORTAL_ID', 'soc_gr_portal_id');
192
define('LOG_GROUP_PORTAL_REL_USER_ARRAY', 'soc_gr_user_array');
193
194
define('LOG_GROUP_PORTAL_USER_SUBSCRIBED', 'soc_gr_u_subs');
195
define('LOG_GROUP_PORTAL_USER_UNSUBSCRIBED', 'soc_gr_u_unsubs');
196
define('LOG_GROUP_PORTAL_USER_UPDATE_ROLE', 'soc_gr_update_role');
197
198
define('LOG_USER_DELETE', 'user_deleted');
199
define('LOG_USER_CREATE', 'user_created');
200
define('LOG_USER_ENABLE', 'user_enable');
201
define('LOG_USER_DISABLE', 'user_disable');
202
define('LOG_USER_ANONYMIZE', 'user_anonymized');
203
define('LOG_USER_FIELD_CREATE', 'user_field_created');
204
define('LOG_USER_FIELD_DELETE', 'user_field_deleted');
205
define('LOG_SESSION_CREATE', 'session_created');
206
define('LOG_SESSION_DELETE', 'session_deleted');
207
define('LOG_SESSION_ADD_USER_COURSE', 'session_add_user_course');
208
define('LOG_SESSION_DELETE_USER_COURSE', 'session_delete_user_course');
209
define('LOG_SESSION_ADD_USER', 'session_add_user');
210
define('LOG_SESSION_DELETE_USER', 'session_delete_user');
211
define('LOG_SESSION_ADD_COURSE', 'session_add_course');
212
define('LOG_SESSION_DELETE_COURSE', 'session_delete_course');
213
214
define('LOG_SESSION_CATEGORY_CREATE', 'session_cat_created'); //changed in 1.9.8
215
define('LOG_SESSION_CATEGORY_DELETE', 'session_cat_deleted'); //changed in 1.9.8
216
define('LOG_CONFIGURATION_SETTINGS_CHANGE', 'settings_changed');
217
define('LOG_PLATFORM_LANGUAGE_CHANGE', 'platform_lng_changed'); //changed in 1.9.8
218
define('LOG_SUBSCRIBE_USER_TO_COURSE', 'user_subscribed');
219
define('LOG_UNSUBSCRIBE_USER_FROM_COURSE', 'user_unsubscribed');
220
define('LOG_ATTEMPTED_FORCED_LOGIN', 'attempted_forced_login');
221
222
define('LOG_HOMEPAGE_CHANGED', 'homepage_changed');
223
224
define('LOG_PROMOTION_CREATE', 'promotion_created');
225
define('LOG_PROMOTION_DELETE', 'promotion_deleted');
226
define('LOG_CAREER_CREATE', 'career_created');
227
define('LOG_CAREER_DELETE', 'career_deleted');
228
229
define('LOG_USER_PERSONAL_DOC_DELETED', 'user_doc_deleted');
230
define('LOG_WIKI_ACCESS', 'wiki_page_view');
231
232
// All results from an exercise
233
define('LOG_EXERCISE_RESULT_DELETE', 'exe_result_deleted');
234
235
// Logs only the one attempt
236
define('LOG_EXERCISE_ATTEMPT_DELETE', 'exe_attempt_deleted');
237
define('LOG_LP_ATTEMPT_DELETE', 'lp_attempt_deleted');
238
define('LOG_QUESTION_RESULT_DELETE', 'qst_attempt_deleted');
239
240
define('LOG_MY_FOLDER_CREATE', 'my_folder_created');
241
define('LOG_MY_FOLDER_CHANGE', 'my_folder_changed');
242
define('LOG_MY_FOLDER_DELETE', 'my_folder_deleted');
243
define('LOG_MY_FOLDER_COPY', 'my_folder_copied');
244
define('LOG_MY_FOLDER_CUT', 'my_folder_cut');
245
define('LOG_MY_FOLDER_PASTE', 'my_folder_pasted');
246
define('LOG_MY_FOLDER_UPLOAD', 'my_folder_uploaded');
247
248
// Event logs data types (max 20 chars)
249
define('LOG_COURSE_CODE', 'course_code');
250
define('LOG_COURSE_ID', 'course_id');
251
define('LOG_USER_ID', 'user_id');
252
define('LOG_USER_OBJECT', 'user_object');
253
define('LOG_USER_FIELD_VARIABLE', 'user_field_variable');
254
define('LOG_SESSION_ID', 'session_id');
255
256
define('LOG_QUESTION_ID', 'question_id');
257
define('LOG_SESSION_CATEGORY_ID', 'session_category_id');
258
define('LOG_CONFIGURATION_SETTINGS_CATEGORY', 'settings_category');
259
define('LOG_CONFIGURATION_SETTINGS_VARIABLE', 'settings_variable');
260
define('LOG_PLATFORM_LANGUAGE', 'default_platform_language');
261
define('LOG_CAREER_ID', 'career_id');
262
define('LOG_PROMOTION_ID', 'promotion_id');
263
define('LOG_GRADEBOOK_LOCKED', 'gradebook_locked');
264
define('LOG_GRADEBOOK_UNLOCKED', 'gradebook_unlocked');
265
define('LOG_GRADEBOOK_ID', 'gradebook_id');
266
define('LOG_WIKI_PAGE_ID', 'wiki_page_id');
267
define('LOG_EXERCISE_ID', 'exercise_id');
268
define('LOG_EXERCISE_AND_USER_ID', 'exercise_and_user_id');
269
define('LOG_LP_ID', 'lp_id');
270
define('LOG_EXERCISE_ATTEMPT_QUESTION_ID', 'exercise_a_q_id');
271
define('LOG_EXERCISE_ATTEMPT', 'exe_id');
272
273
define('LOG_WORK_DIR_DELETE', 'work_dir_delete');
274
define('LOG_WORK_FILE_DELETE', 'work_file_delete');
275
define('LOG_WORK_DATA', 'work_data_array');
276
277
define('LOG_MY_FOLDER_PATH', 'path');
278
define('LOG_MY_FOLDER_NEW_PATH', 'new_path');
279
280
define('LOG_TERM_CONDITION_ACCEPTED', 'term_condition_accepted');
281
define('LOG_USER_CONFIRMED_EMAIL', 'user_confirmed_email');
282
define('LOG_USER_REMOVED_LEGAL_ACCEPT', 'user_removed_legal_accept');
283
284
define('LOG_USER_DELETE_ACCOUNT_REQUEST', 'user_delete_account_request');
285
286
define('LOG_QUESTION_CREATED', 'question_created');
287
define('LOG_QUESTION_UPDATED', 'question_updated');
288
289
define('USERNAME_PURIFIER', '/[^0-9A-Za-z_\.-]/');
290
291
//used when login_is_email setting is true
292
define('USERNAME_PURIFIER_MAIL', '/[^0-9A-Za-z_\.@]/');
293
define('USERNAME_PURIFIER_SHALLOW', '/\s/');
294
295
// This constant is a result of Windows OS detection, it has a boolean value:
296
// true whether the server runs on Windows OS, false otherwise.
297
define('IS_WINDOWS_OS', api_is_windows_os());
298
299
// iconv extension, for PHP5 on Windows it is installed by default.
300
define('ICONV_INSTALLED', function_exists('iconv'));
301
define('MBSTRING_INSTALLED', function_exists('mb_strlen')); // mbstring extension.
302
303
// Patterns for processing paths. Examples.
304
define('REPEATED_SLASHES_PURIFIER', '/\/{2,}/'); // $path = preg_replace(REPEATED_SLASHES_PURIFIER, '/', $path);
305
define('VALID_WEB_PATH', '/https?:\/\/[^\/]*(\/.*)?/i'); // $is_valid_path = preg_match(VALID_WEB_PATH, $path);
306
// $new_path = preg_replace(VALID_WEB_SERVER_BASE, $new_base, $path);
307
define('VALID_WEB_SERVER_BASE', '/https?:\/\/[^\/]*/i');
308
// Constants for api_get_path() and api_get_path_type(), etc. - registered path types.
309
// basic (leaf elements)
310
define('REL_CODE_PATH', 'REL_CODE_PATH');
311
define('REL_COURSE_PATH', 'REL_COURSE_PATH');
312
define('REL_HOME_PATH', 'REL_HOME_PATH');
313
314
// Constants for api_get_path() and api_get_path_type(), etc. - registered path types.
315
define('WEB_PATH', 'WEB_PATH');
316
define('SYS_PATH', 'SYS_PATH');
317
define('SYS_APP_PATH', 'SYS_APP_PATH');
318
define('SYS_UPLOAD_PATH', 'SYS_UPLOAD_PATH');
319
define('WEB_UPLOAD_PATH', 'WEB_UPLOAD_PATH');
320
321
define('REL_PATH', 'REL_PATH');
322
define('WEB_COURSE_PATH', 'WEB_COURSE_PATH');
323
define('SYS_COURSE_PATH', 'SYS_COURSE_PATH');
324
define('WEB_CODE_PATH', 'WEB_CODE_PATH');
325
define('SYS_CODE_PATH', 'SYS_CODE_PATH');
326
define('SYS_LANG_PATH', 'SYS_LANG_PATH');
327
define('WEB_IMG_PATH', 'WEB_IMG_PATH');
328
define('WEB_CSS_PATH', 'WEB_CSS_PATH');
329
define('WEB_PUBLIC_PATH', 'WEB_PUBLIC_PATH');
330
define('SYS_CSS_PATH', 'SYS_CSS_PATH');
331
define('SYS_PLUGIN_PATH', 'SYS_PLUGIN_PATH');
332
define('WEB_PLUGIN_PATH', 'WEB_PLUGIN_PATH');
333
define('WEB_PLUGIN_ASSET_PATH', 'WEB_PLUGIN_ASSET_PATH');
334
define('SYS_ARCHIVE_PATH', 'SYS_ARCHIVE_PATH');
335
define('WEB_ARCHIVE_PATH', 'WEB_ARCHIVE_PATH');
336
define('SYS_INC_PATH', 'SYS_INC_PATH');
337
define('LIBRARY_PATH', 'LIBRARY_PATH');
338
define('CONFIGURATION_PATH', 'CONFIGURATION_PATH');
339
define('WEB_LIBRARY_PATH', 'WEB_LIBRARY_PATH');
340
define('WEB_LIBRARY_JS_PATH', 'WEB_LIBRARY_JS_PATH');
341
define('WEB_AJAX_PATH', 'WEB_AJAX_PATH');
342
define('SYS_TEST_PATH', 'SYS_TEST_PATH');
343
define('WEB_TEMPLATE_PATH', 'WEB_TEMPLATE_PATH');
344
define('SYS_TEMPLATE_PATH', 'SYS_TEMPLATE_PATH');
345
define('SYS_PUBLIC_PATH', 'SYS_PUBLIC_PATH');
346
define('SYS_HOME_PATH', 'SYS_HOME_PATH');
347
define('WEB_HOME_PATH', 'WEB_HOME_PATH');
348
define('WEB_FONTS_PATH', 'WEB_FONTS_PATH');
349
define('SYS_FONTS_PATH', 'SYS_FONTS_PATH');
350
351
// Relations type with Course manager
352
define('COURSE_RELATION_TYPE_COURSE_MANAGER', 1);
353
define('SESSION_RELATION_TYPE_COURSE_MANAGER', 1);
354
355
// Relations type with Human resources manager
356
define('COURSE_RELATION_TYPE_RRHH', 1);
357
define('SESSION_RELATION_TYPE_RRHH', 1);
358
359
//User image sizes
360
define('USER_IMAGE_SIZE_ORIGINAL', 1);
361
define('USER_IMAGE_SIZE_BIG', 2);
362
define('USER_IMAGE_SIZE_MEDIUM', 3);
363
define('USER_IMAGE_SIZE_SMALL', 4);
364
365
// Relation type between users
366
define('USER_UNKNOWN', 0);
367
define('USER_RELATION_TYPE_UNKNOWN', 1);
368
define('USER_RELATION_TYPE_PARENT', 2); // should be deprecated is useless
369
define('USER_RELATION_TYPE_FRIEND', 3);
370
define('USER_RELATION_TYPE_GOODFRIEND', 4); // should be deprecated is useless
371
define('USER_RELATION_TYPE_ENEMY', 5); // should be deprecated is useless
372
define('USER_RELATION_TYPE_DELETED', 6);
373
define('USER_RELATION_TYPE_RRHH', 7);
374
define('USER_RELATION_TYPE_BOSS', 8);
375
define('USER_RELATION_TYPE_HRM_REQUEST', 9);
376
377
// Gradebook link constants
378
// Please do not change existing values, they are used in the database !
379
define('GRADEBOOK_ITEM_LIMIT', 1000);
380
381
define('LINK_EXERCISE', 1);
382
define('LINK_DROPBOX', 2);
383
define('LINK_STUDENTPUBLICATION', 3);
384
define('LINK_LEARNPATH', 4);
385
define('LINK_FORUM_THREAD', 5);
386
//define('LINK_WORK',6);
387
define('LINK_ATTENDANCE', 7);
388
define('LINK_SURVEY', 8);
389
define('LINK_HOTPOTATOES', 9);
390
391
// Score display types constants
392
define('SCORE_DIV', 1); // X / Y
393
define('SCORE_PERCENT', 2); // XX %
394
define('SCORE_DIV_PERCENT', 3); // X / Y (XX %)
395
define('SCORE_AVERAGE', 4); // XX %
396
define('SCORE_DECIMAL', 5); // 0.50  (X/Y)
397
define('SCORE_BAR', 6); // Uses the Display::bar_progress function
398
define('SCORE_SIMPLE', 7); // X
399
define('SCORE_IGNORE_SPLIT', 8); //  ??
400
define('SCORE_DIV_PERCENT_WITH_CUSTOM', 9); // X / Y (XX %) - Good!
401
define('SCORE_CUSTOM', 10); // Good!
402
define('SCORE_DIV_SIMPLE_WITH_CUSTOM', 11); // X - Good!
403
define('SCORE_DIV_SIMPLE_WITH_CUSTOM_LETTERS', 12); // X - Good!
404
define('SCORE_ONLY_SCORE', 13); // X - Good!
405
define('SCORE_NUMERIC', 14);
406
407
define('SCORE_BOTH', 1);
408
define('SCORE_ONLY_DEFAULT', 2);
409
define('SCORE_ONLY_CUSTOM', 3);
410
411
// From display.lib.php
412
413
define('MAX_LENGTH_BREADCRUMB', 100);
414
define('ICON_SIZE_ATOM', 8);
415
define('ICON_SIZE_TINY', 16);
416
define('ICON_SIZE_SMALL', 22);
417
define('ICON_SIZE_MEDIUM', 32);
418
define('ICON_SIZE_LARGE', 48);
419
define('ICON_SIZE_BIG', 64);
420
define('ICON_SIZE_HUGE', 128);
421
define('SHOW_TEXT_NEAR_ICONS', false);
422
423
// Session catalog
424
define('CATALOG_COURSES', 0);
425
define('CATALOG_SESSIONS', 1);
426
define('CATALOG_COURSES_SESSIONS', 2);
427
428
// Hook type events, pre-process and post-process.
429
// All means to be executed for both hook event types
430
define('HOOK_EVENT_TYPE_PRE', 0);
431
define('HOOK_EVENT_TYPE_POST', 1);
432
define('HOOK_EVENT_TYPE_ALL', 10);
433
434
define('CAREER_STATUS_ACTIVE', 1);
435
define('CAREER_STATUS_INACTIVE', 0);
436
437
define('PROMOTION_STATUS_ACTIVE', 1);
438
define('PROMOTION_STATUS_INACTIVE', 0);
439
440
// Group permissions
441
define('GROUP_PERMISSION_OPEN', '1');
442
define('GROUP_PERMISSION_CLOSED', '2');
443
444
// Group user permissions
445
define('GROUP_USER_PERMISSION_ADMIN', '1'); // the admin of a group
446
define('GROUP_USER_PERMISSION_READER', '2'); // a normal user
447
define('GROUP_USER_PERMISSION_PENDING_INVITATION', '3'); // When an admin/moderator invites a user
448
define('GROUP_USER_PERMISSION_PENDING_INVITATION_SENT_BY_USER', '4'); // an user joins a group
449
define('GROUP_USER_PERMISSION_MODERATOR', '5'); // a moderator
450
define('GROUP_USER_PERMISSION_ANONYMOUS', '6'); // an anonymous user
451
define('GROUP_USER_PERMISSION_HRM', '7'); // a human resources manager
452
453
define('GROUP_IMAGE_SIZE_ORIGINAL', 1);
454
define('GROUP_IMAGE_SIZE_BIG', 2);
455
define('GROUP_IMAGE_SIZE_MEDIUM', 3);
456
define('GROUP_IMAGE_SIZE_SMALL', 4);
457
define('GROUP_TITLE_LENGTH', 50);
458
459
// Exercise
460
// @todo move into a class
461
define('ALL_ON_ONE_PAGE', 1);
462
define('ONE_PER_PAGE', 2);
463
464
define('EXERCISE_FEEDBACK_TYPE_END', 0); //Feedback 		 - show score and expected answers
465
define('EXERCISE_FEEDBACK_TYPE_DIRECT', 1); //DirectFeedback - Do not show score nor answers
466
define('EXERCISE_FEEDBACK_TYPE_EXAM', 2); // NoFeedback 	 - Show score only
467
define('EXERCISE_FEEDBACK_TYPE_POPUP', 3); // Popup BT#15827
468
469
define('RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS', 0); //show score and expected answers
470
define('RESULT_DISABLE_NO_SCORE_AND_EXPECTED_ANSWERS', 1); //Do not show score nor answers
471
define('RESULT_DISABLE_SHOW_SCORE_ONLY', 2); //Show score only
472
define('RESULT_DISABLE_SHOW_FINAL_SCORE_ONLY_WITH_CATEGORIES', 3); //Show final score only with categories
473
define('RESULT_DISABLE_SHOW_SCORE_ATTEMPT_SHOW_ANSWERS_LAST_ATTEMPT', 4);
474
define('RESULT_DISABLE_DONT_SHOW_SCORE_ONLY_IF_USER_FINISHES_ATTEMPTS_SHOW_ALWAYS_FEEDBACK', 5);
475
define('RESULT_DISABLE_RANKING', 6);
476
define('RESULT_DISABLE_SHOW_ONLY_IN_CORRECT_ANSWER', 7);
477
define('RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS_AND_RANKING', 8);
478
479
define('EXERCISE_MAX_NAME_SIZE', 80);
480
481
// Question types (edit next array as well when adding values)
482
// @todo move into a class
483
define('UNIQUE_ANSWER', 1);
484
define('MULTIPLE_ANSWER', 2);
485
define('FILL_IN_BLANKS', 3);
486
define('MATCHING', 4);
487
define('FREE_ANSWER', 5);
488
define('HOT_SPOT', 6);
489
define('HOT_SPOT_ORDER', 7);
490
define('HOT_SPOT_DELINEATION', 8);
491
define('MULTIPLE_ANSWER_COMBINATION', 9);
492
define('UNIQUE_ANSWER_NO_OPTION', 10);
493
define('MULTIPLE_ANSWER_TRUE_FALSE', 11);
494
define('MULTIPLE_ANSWER_COMBINATION_TRUE_FALSE', 12);
495
define('ORAL_EXPRESSION', 13);
496
define('GLOBAL_MULTIPLE_ANSWER', 14);
497
define('MEDIA_QUESTION', 15);
498
define('CALCULATED_ANSWER', 16);
499
define('UNIQUE_ANSWER_IMAGE', 17);
500
define('DRAGGABLE', 18);
501
define('MATCHING_DRAGGABLE', 19);
502
define('ANNOTATION', 20);
503
define('READING_COMPREHENSION', 21);
504
define('MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY', 22);
505
506
define('EXERCISE_CATEGORY_RANDOM_SHUFFLED', 1);
507
define('EXERCISE_CATEGORY_RANDOM_ORDERED', 2);
508
define('EXERCISE_CATEGORY_RANDOM_DISABLED', 0);
509
510
// Question selection type
511
define('EX_Q_SELECTION_ORDERED', 1);
512
define('EX_Q_SELECTION_RANDOM', 2);
513
define('EX_Q_SELECTION_CATEGORIES_ORDERED_QUESTIONS_ORDERED', 3);
514
define('EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_ORDERED', 4);
515
define('EX_Q_SELECTION_CATEGORIES_ORDERED_QUESTIONS_RANDOM', 5);
516
define('EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_RANDOM', 6);
517
define('EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_ORDERED_NO_GROUPED', 7);
518
define('EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_RANDOM_NO_GROUPED', 8);
519
define('EX_Q_SELECTION_CATEGORIES_ORDERED_BY_PARENT_QUESTIONS_ORDERED', 9);
520
define('EX_Q_SELECTION_CATEGORIES_ORDERED_BY_PARENT_QUESTIONS_RANDOM', 10);
521
522
// Used to save the skill_rel_item table
523
define('ITEM_TYPE_EXERCISE', 1);
524
define('ITEM_TYPE_HOTPOTATOES', 2);
525
define('ITEM_TYPE_LINK', 3);
526
define('ITEM_TYPE_LEARNPATH', 4);
527
define('ITEM_TYPE_GRADEBOOK', 5);
528
define('ITEM_TYPE_STUDENT_PUBLICATION', 6);
529
//define('ITEM_TYPE_FORUM', 7);
530
define('ITEM_TYPE_ATTENDANCE', 8);
531
define('ITEM_TYPE_SURVEY', 9);
532
define('ITEM_TYPE_FORUM_THREAD', 10);
533
534
// one big string with all question types, for the validator in pear/HTML/QuickForm/Rule/QuestionType
535
define(
536
    'QUESTION_TYPES',
537
    UNIQUE_ANSWER.':'.
538
    MULTIPLE_ANSWER.':'.
539
    FILL_IN_BLANKS.':'.
540
    MATCHING.':'.
541
    FREE_ANSWER.':'.
542
    HOT_SPOT.':'.
543
    HOT_SPOT_ORDER.':'.
544
    HOT_SPOT_DELINEATION.':'.
545
    MULTIPLE_ANSWER_COMBINATION.':'.
546
    UNIQUE_ANSWER_NO_OPTION.':'.
547
    MULTIPLE_ANSWER_TRUE_FALSE.':'.
548
    MULTIPLE_ANSWER_COMBINATION_TRUE_FALSE.':'.
549
    ORAL_EXPRESSION.':'.
550
    GLOBAL_MULTIPLE_ANSWER.':'.
551
    MEDIA_QUESTION.':'.
552
    CALCULATED_ANSWER.':'.
553
    UNIQUE_ANSWER_IMAGE.':'.
554
    DRAGGABLE.':'.
555
    MATCHING_DRAGGABLE.':'.
556
    MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY.':'.
557
    ANNOTATION
558
);
559
560
//Some alias used in the QTI exports
561
define('MCUA', 1);
562
define('TF', 1);
563
define('MCMA', 2);
564
define('FIB', 3);
565
566
// Skills
567
define('SKILL_TYPE_REQUIREMENT', 'required');
568
define('SKILL_TYPE_ACQUIRED', 'acquired');
569
define('SKILL_TYPE_BOTH', 'both');
570
571
// Message
572
define('MESSAGE_STATUS_NEW', '0');
573
define('MESSAGE_STATUS_UNREAD', '1');
574
//2 ??
575
define('MESSAGE_STATUS_DELETED', '3');
576
define('MESSAGE_STATUS_OUTBOX', '4');
577
define('MESSAGE_STATUS_INVITATION_PENDING', '5');
578
define('MESSAGE_STATUS_INVITATION_ACCEPTED', '6');
579
define('MESSAGE_STATUS_INVITATION_DENIED', '7');
580
define('MESSAGE_STATUS_WALL', '8');
581
define('MESSAGE_STATUS_WALL_DELETE', '9');
582
define('MESSAGE_STATUS_WALL_POST', '10');
583
define('MESSAGE_STATUS_CONVERSATION', '11');
584
define('MESSAGE_STATUS_FORUM', '12');
585
define('MESSAGE_STATUS_PROMOTED', '13');
586
587
// Images
588
define('IMAGE_WALL_SMALL_SIZE', 200);
589
define('IMAGE_WALL_MEDIUM_SIZE', 500);
590
define('IMAGE_WALL_BIG_SIZE', 2000);
591
define('IMAGE_WALL_SMALL', 'small');
592
define('IMAGE_WALL_MEDIUM', 'medium');
593
define('IMAGE_WALL_BIG', 'big');
594
595
// Social PLUGIN PLACES
596
define('SOCIAL_LEFT_PLUGIN', 1);
597
define('SOCIAL_CENTER_PLUGIN', 2);
598
define('SOCIAL_RIGHT_PLUGIN', 3);
599
define('CUT_GROUP_NAME', 50);
600
601
/**
602
 * FormValidator Filter.
603
 */
604
define('NO_HTML', 1);
605
define('STUDENT_HTML', 2);
606
define('TEACHER_HTML', 3);
607
define('STUDENT_HTML_FULLPAGE', 4);
608
define('TEACHER_HTML_FULLPAGE', 5);
609
610
// Timeline
611
define('TIMELINE_STATUS_ACTIVE', '1');
612
define('TIMELINE_STATUS_INACTIVE', '2');
613
614
// Event email template class
615
define('EVENT_EMAIL_TEMPLATE_ACTIVE', 1);
616
define('EVENT_EMAIL_TEMPLATE_INACTIVE', 0);
617
618
// Course home
619
define('SHORTCUTS_HORIZONTAL', 0);
620
define('SHORTCUTS_VERTICAL', 1);
621
622
// Image class
623
define('IMAGE_PROCESSOR', 'gd'); // 'imagick' or 'gd' strings
624
625
// Course copy
626
define('FILE_SKIP', 1);
627
define('FILE_RENAME', 2);
628
define('FILE_OVERWRITE', 3);
629
define('UTF8_CONVERT', false); //false by default
630
631
define('DOCUMENT', 'file');
632
define('FOLDER', 'folder');
633
634
define('RESOURCE_ASSET', 'asset');
635
define('RESOURCE_DOCUMENT', 'document');
636
define('RESOURCE_GLOSSARY', 'glossary');
637
define('RESOURCE_EVENT', 'calendar_event');
638
define('RESOURCE_LINK', 'link');
639
define('RESOURCE_COURSEDESCRIPTION', 'course_description');
640
define('RESOURCE_LEARNPATH', 'learnpath');
641
define('RESOURCE_LEARNPATH_CATEGORY', 'learnpath_category');
642
define('RESOURCE_ANNOUNCEMENT', 'announcement');
643
define('RESOURCE_FORUM', 'forum');
644
define('RESOURCE_FORUMTOPIC', 'thread');
645
define('RESOURCE_FORUMPOST', 'post');
646
define('RESOURCE_QUIZ', 'quiz');
647
define('RESOURCE_TEST_CATEGORY', 'test_category');
648
define('RESOURCE_QUIZQUESTION', 'Exercise_Question');
649
define('RESOURCE_TOOL_INTRO', 'Tool introduction');
650
define('RESOURCE_LINKCATEGORY', 'Link_Category');
651
define('RESOURCE_FORUMCATEGORY', 'Forum_Category');
652
define('RESOURCE_SCORM', 'Scorm');
653
define('RESOURCE_SURVEY', 'survey');
654
define('RESOURCE_SURVEYQUESTION', 'survey_question');
655
define('RESOURCE_SURVEYINVITATION', 'survey_invitation');
656
define('RESOURCE_WIKI', 'wiki');
657
define('RESOURCE_THEMATIC', 'thematic');
658
define('RESOURCE_ATTENDANCE', 'attendance');
659
define('RESOURCE_WORK', 'work');
660
define('RESOURCE_SESSION_COURSE', 'session_course');
661
define('RESOURCE_GRADEBOOK', 'gradebook');
662
define('ADD_THEMATIC_PLAN', 6);
663
664
// Max online users to show per page (whoisonline)
665
define('MAX_ONLINE_USERS', 12);
666
667
// Number of characters maximum to show in preview of course blog posts
668
define('BLOG_MAX_PREVIEW_CHARS', 800);
669
// HTML string to replace with a 'Read more...' link
670
define('BLOG_PAGE_BREAK', '<div style="page-break-after: always"><span style="display: none;">&nbsp;</span></div>');
671
672
// Make sure the CHAMILO_LOAD_WYSIWYG constant is defined
673
// To remove CKeditor libs from HTML, set this constant to true before loading
674
if (!defined('CHAMILO_LOAD_WYSIWYG')) {
675
    define('CHAMILO_LOAD_WYSIWYG', true);
676
}
677
678
/* Constants for course home */
679
define('TOOL_PUBLIC', 'Public');
680
define('TOOL_PUBLIC_BUT_HIDDEN', 'PublicButHide');
681
define('TOOL_COURSE_ADMIN', 'courseAdmin');
682
define('TOOL_PLATFORM_ADMIN', 'platformAdmin');
683
define('TOOL_AUTHORING', 'toolauthoring');
684
define('TOOL_INTERACTION', 'toolinteraction');
685
define('TOOL_COURSE_PLUGIN', 'toolcourseplugin'); //all plugins that can be enabled in courses
686
define('TOOL_ADMIN', 'tooladmin');
687
define('TOOL_ADMIN_PLATFORM', 'tooladminplatform');
688
define('TOOL_DRH', 'tool_drh');
689
define('TOOL_STUDENT_VIEW', 'toolstudentview');
690
define('TOOL_ADMIN_VISIBLE', 'tooladminvisible');
691
692
/**
693
 * Returns a path to a certain resource within the Chamilo area, specifyed through a parameter.
694
 * Also, this function provides conversion between path types, in this case the input path points inside the Chamilo area too.
695
 *
696
 * See $_configuration['course_folder'] in the configuration.php to alter the WEB_COURSE_PATH and SYS_COURSE_PATH parameters.
697
698
 *
699
 * @param string $path (optional)   A path which type is to be converted. Also, it may be a defined constant for a path.
700
 *                     This parameter has meaning when $type parameter has one of the following values: TO_WEB, TO_SYS, TO_REL. Otherwise it is ignored.
701
 *
702
 * @return string the requested path or the converted path
703
 *
704
 *
705
 * Notes about the current behaviour model:
706
 * 1. Windows back-slashes are converted to slashes in the result.
707
 * 2. A semi-absolute web-path is detected by its leading slash. On Linux systems, absolute system paths start with
708
 * a slash too, so an additional check about presence of leading system server base is implemented. For example, the function is
709
 * able to distinguish type difference between /var/www/chamilo/courses/ (SYS) and /chamilo/courses/ (REL).
710
 * 3. The function api_get_path() returns only these three types of paths, which in some sense are absolute. The function has
711
 * no a mechanism for processing relative web/system paths, such as: lesson01.html, ./lesson01.html, ../css/my_styles.css.
712
 * It has not been identified as needed yet.
713
 * 4. Also, resolving the meta-symbols "." and ".." within paths has not been implemented, it is to be identified as needed.
714
 *
715
 * For examples go to: *
716
 * See main/admin/system_status.php?section=paths
717
 *
718
 * Vchamilo changes : allow using an alternate configuration
719
 * to get vchamilo  instance paths
720
 */
721
function api_get_path($path = '', $configuration = [])
722
{
723
    global $paths;
724
725
    // get proper configuration data if exists
726
    global $_configuration;
727
728
    $emptyConfigurationParam = false;
729
    if (empty($configuration)) {
730
        $configuration = (array) $_configuration;
731
        $emptyConfigurationParam = true;
732
    }
733
734
    $course_folder = 'courses/';
735
    $code_folder = 'main/';
736
    $root_sys = Container::getRootDir();
737
    $root_web = '';
738
    // If no $root_web has been set so far *and* no custom config has been passed to the function
739
    // then re-use the previously-calculated (run-specific) $root_web and skip this complex calculation
740
    if (empty($root_web) || $emptyConfigurationParam === false || empty($configuration)) {
741
        // Resolve master hostname.
742
        if (!empty($configuration) && array_key_exists('root_web', $configuration)) {
743
            $root_web = $configuration['root_web'];
744
        } else {
745
            $root_web = '';
746
            // Try guess it from server.
747
            if (defined('SYSTEM_INSTALLATION') && SYSTEM_INSTALLATION) {
748
                if (($pos = strpos(($requested_page_rel = api_get_self()), 'main/install')) !== false) {
749
                    $root_rel = substr($requested_page_rel, 0, $pos);
750
                    // See http://www.mediawiki.org/wiki/Manual:$wgServer
751
                    $server_protocol = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https' : 'http';
752
                    $server_name =
753
                        isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME']
754
                            : (isset($_SERVER['HOSTNAME']) ? $_SERVER['HOSTNAME']
755
                            : (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST']
756
                                : (isset($_SERVER['SERVER_ADDR']) ? $_SERVER['SERVER_ADDR']
757
                                    : 'localhost')));
758
                    if (isset($_SERVER['SERVER_PORT']) && !strpos($server_name, ':')
759
                        && (($server_protocol == 'http'
760
                                && $_SERVER['SERVER_PORT'] != 80) || ($server_protocol == 'https' && $_SERVER['SERVER_PORT'] != 443))
761
                    ) {
762
                        $server_name .= ":".$_SERVER['SERVER_PORT'];
763
                    }
764
                    $root_web = $server_protocol.'://'.$server_name.$root_rel;
765
                    $root_sys = str_replace('\\', '/', realpath(__DIR__.'/../../../')).'/';
766
                }
767
                // Here we give up, so we don't touch anything.
768
            }
769
        }
770
    }
771
772
    if (isset(Container::$container)) {
773
        $root_web = Container::$container->get('router')->generate(
774
            'legacy_index',
775
            [],
776
            UrlGeneratorInterface::ABSOLUTE_URL
777
        );
778
779
        // Fix for php files inside main
780
        if (strpos($root_web, 'main') !== false) {
781
            $pos = (int) strpos($root_web, 'main');
782
            $root_web = substr($root_web, 0, $pos);
783
        }
784
785
        // Fix for php files inside courses
786
        if (strpos($root_web, '/courses/') !== false) {
787
            $pos = (int) strpos($root_web, '/courses/');
788
            $root_web = substr($root_web, 0, $pos);
789
        }
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
 * Gets a modified version of the path for the CDN, if defined in
965
 * configuration.php.
966
 *
967
 * @param string $web_path The path of the resource without CDN
968
 *
969
 * @return string The path of the resource converted to CDN
970
 *
971
 * @author Yannick Warnier <[email protected]>
972
 */
973
function api_get_cdn_path($web_path)
974
{
975
    global $_configuration;
976
    $web_root = api_get_path(WEB_PATH);
977
    $ext = substr($web_path, strrpos($web_path, '.'));
978
    if (isset($ext[2])) { // faster version of strlen to check if len>2
979
        // Check for CDN definitions
980
        if (!empty($_configuration['cdn_enable']) && !empty($ext)) {
981
            foreach ($_configuration['cdn'] as $host => $exts) {
982
                if (in_array($ext, $exts)) {
983
                    //Use host as defined in $_configuration['cdn'], without
984
                    // trailing slash
985
                    return str_replace($web_root, $host.'/', $web_path);
986
                }
987
            }
988
        }
989
    }
990
991
    return $web_path;
992
}
993
994
/**
995
 * @return bool Return true if LDAP authentification is activated
996
 */
997
function api_is_ldap_activated()
998
{
999
    global $extAuthSource;
1000
1001
    return is_array($extAuthSource[LDAP_AUTH_SOURCE]);
1002
}
1003
1004
/**
1005
 * @return bool Return true if Facebook authentification is activated
1006
 */
1007
function api_is_facebook_auth_activated()
1008
{
1009
    global $_configuration;
1010
1011
    return isset($_configuration['facebook_auth']) && $_configuration['facebook_auth'] == 1;
1012
}
1013
1014
/**
1015
 * Adds to a given path a trailing slash if it is necessary (adds "/" character at the end of the string).
1016
 *
1017
 * @param string $path the input path
1018
 *
1019
 * @return string returns the modified path
1020
 */
1021
function api_add_trailing_slash($path)
1022
{
1023
    return substr($path, -1) == '/' ? $path : $path.'/';
1024
}
1025
1026
/**
1027
 * Removes from a given path the trailing slash if it is necessary (removes "/" character from the end of the string).
1028
 *
1029
 * @param string $path the input path
1030
 *
1031
 * @return string returns the modified path
1032
 */
1033
function api_remove_trailing_slash($path)
1034
{
1035
    return substr($path, -1) == '/' ? substr($path, 0, -1) : $path;
1036
}
1037
1038
/**
1039
 * Checks the RFC 3986 syntax of a given URL.
1040
 *
1041
 * @param string $url      the URL to be checked
1042
 * @param bool   $absolute whether the URL is absolute (beginning with a scheme such as "http:")
1043
 *
1044
 * @return string|false Returns the URL if it is valid, FALSE otherwise.
1045
 *                      This function is an adaptation from the function valid_url(), Drupal CMS.
1046
 *
1047
 * @see http://drupal.org
1048
 * Note: The built-in function filter_var($urs, FILTER_VALIDATE_URL) has a bug for some versions of PHP.
1049
 * @see http://bugs.php.net/51192
1050
 */
1051
function api_valid_url($url, $absolute = false)
1052
{
1053
    if ($absolute) {
1054
        if (preg_match("
1055
            /^                                                      # Start at the beginning of the text
1056
            (?:ftp|https?|feed):\/\/                                # Look for ftp, http, https or feed schemes
1057
            (?:                                                     # Userinfo (optional) which is typically
1058
                (?:(?:[\w\.\-\+!$&'\(\)*\+,;=]|%[0-9a-f]{2})+:)*    # a username or a username and password
1059
                (?:[\w\.\-\+%!$&'\(\)*\+,;=]|%[0-9a-f]{2})+@        # combination
1060
            )?
1061
            (?:
1062
                (?:[a-z0-9\-\.]|%[0-9a-f]{2})+                      # A domain name or a IPv4 address
1063
                |(?:\[(?:[0-9a-f]{0,4}:)*(?:[0-9a-f]{0,4})\])       # or a well formed IPv6 address
1064
            )
1065
            (?::[0-9]+)?                                            # Server port number (optional)
1066
            (?:[\/|\?]
1067
                (?:[\w#!:\.\?\+=&@$'~*,;\/\(\)\[\]\-]|%[0-9a-f]{2}) # The path and query (optional)
1068
            *)?
1069
            $/xi", $url)) {
1070
            return $url;
1071
        }
1072
1073
        return false;
1074
    } else {
1075
        return preg_match("/^(?:[\w#!:\.\?\+=&@$'~*,;\/\(\)\[\]\-]|%[0-9a-f]{2})+$/i", $url) ? $url : false;
1076
    }
1077
}
1078
1079
/**
1080
 * Checks whether a given string looks roughly like an email address.
1081
 *
1082
 * @param string $address the e-mail address to be checked
1083
 *
1084
 * @return mixed returns the e-mail if it is valid, FALSE otherwise
1085
 */
1086
function api_valid_email($address)
1087
{
1088
    return filter_var($address, FILTER_VALIDATE_EMAIL);
1089
}
1090
1091
/* PROTECTION FUNCTIONS
1092
   Use these functions to protect your scripts. */
1093
1094
/**
1095
 * Function used to protect a course script.
1096
 * The function blocks access when
1097
 * - there is no $_SESSION["_course"] defined; or
1098
 * - $is_allowed_in_course is set to false (this depends on the course
1099
 * visibility and user status).
1100
 *
1101
 * This is only the first proposal, test and improve!
1102
 *
1103
 * @param bool Option to print headers when displaying error message. Default: false
1104
 * @param bool whether session admins should be allowed or not
1105
 * @param bool $checkTool check if tool is available for users (user, group)
1106
 *
1107
 * @return bool True if the user has access to the current course or is out of a course context, false otherwise
1108
 *
1109
 * @todo replace global variable
1110
 *
1111
 * @author Roan Embrechts
1112
 */
1113
function api_protect_course_script($print_headers = false, $allow_session_admins = false, $checkTool = '')
1114
{
1115
    $course_info = api_get_course_info();
1116
    if (empty($course_info)) {
1117
        api_not_allowed($print_headers);
1118
1119
        return false;
1120
    }
1121
1122
    if (api_is_drh()) {
1123
        return true;
1124
    }
1125
1126
    // Session admin has access to course
1127
    $sessionAccess = api_get_configuration_value('session_admins_access_all_content');
1128
    if ($sessionAccess) {
1129
        $allow_session_admins = true;
1130
    }
1131
1132
    if (api_is_platform_admin($allow_session_admins)) {
1133
        return true;
1134
    }
1135
1136
    $isAllowedInCourse = api_is_allowed_in_course();
1137
    $is_visible = false;
1138
    if (isset($course_info) && isset($course_info['visibility'])) {
1139
        switch ($course_info['visibility']) {
1140
            default:
1141
            case COURSE_VISIBILITY_CLOSED:
1142
                // Completely closed: the course is only accessible to the teachers. - 0
1143
                if (api_get_user_id() && !api_is_anonymous() && $isAllowedInCourse) {
1144
                    $is_visible = true;
1145
                }
1146
                break;
1147
            case COURSE_VISIBILITY_REGISTERED:
1148
                // Private - access authorized to course members only - 1
1149
                if (api_get_user_id() && !api_is_anonymous() && $isAllowedInCourse) {
1150
                    $is_visible = true;
1151
                }
1152
                break;
1153
            case COURSE_VISIBILITY_OPEN_PLATFORM:
1154
                // Open - access allowed for users registered on the platform - 2
1155
                if (api_get_user_id() && !api_is_anonymous() && $isAllowedInCourse) {
1156
                    $is_visible = true;
1157
                }
1158
                break;
1159
            case COURSE_VISIBILITY_OPEN_WORLD:
1160
                //Open - access allowed for the whole world - 3
1161
                $is_visible = true;
1162
                break;
1163
            case COURSE_VISIBILITY_HIDDEN:
1164
                //Completely closed: the course is only accessible to the teachers. - 0
1165
                if (api_is_platform_admin()) {
1166
                    $is_visible = true;
1167
                }
1168
                break;
1169
        }
1170
1171
        //If password is set and user is not registered to the course then the course is not visible
1172
        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...
1173
            isset($course_info['registration_code']) &&
1174
            !empty($course_info['registration_code'])
1175
        ) {
1176
            $is_visible = false;
1177
        }
1178
    }
1179
1180
    if (!empty($checkTool)) {
1181
        if (!api_is_allowed_to_edit(true, true, true)) {
1182
            $toolInfo = api_get_tool_information_by_name($checkTool);
1183
            if (!empty($toolInfo) && isset($toolInfo['visibility']) && $toolInfo['visibility'] == 0) {
1184
                api_not_allowed(true);
1185
1186
                return false;
1187
            }
1188
        }
1189
    }
1190
1191
    // Check session visibility
1192
    $session_id = api_get_session_id();
1193
1194
    if (!empty($session_id)) {
1195
        // $isAllowedInCourse was set in local.inc.php
1196
        if (!$isAllowedInCourse) {
1197
            $is_visible = false;
1198
        }
1199
    }
1200
1201
    if (!$is_visible) {
1202
        api_not_allowed($print_headers);
1203
1204
        return false;
1205
    }
1206
1207
    return true;
1208
}
1209
1210
/**
1211
 * Function used to protect an admin script.
1212
 *
1213
 * The function blocks access when the user has no platform admin rights
1214
 * with an error message printed on default output
1215
 *
1216
 * @param bool Whether to allow session admins as well
1217
 * @param bool Whether to allow HR directors as well
1218
 * @param string An optional message (already passed through get_lang)
1219
 *
1220
 * @return bool True if user is allowed, false otherwise.
1221
 *              The function also outputs an error message in case not allowed
1222
 *
1223
 * @author Roan Embrechts (original author)
1224
 */
1225
function api_protect_admin_script($allow_sessions_admins = false, $allow_drh = false, $message = null)
1226
{
1227
    if (!api_is_platform_admin($allow_sessions_admins, $allow_drh)) {
1228
        api_not_allowed(true, $message);
1229
1230
        return false;
1231
    }
1232
1233
    return true;
1234
}
1235
1236
/**
1237
 * Function used to protect a teacher script.
1238
 * The function blocks access when the user has no teacher rights.
1239
 *
1240
 * @return bool True if the current user can access the script, false otherwise
1241
 *
1242
 * @author Yoselyn Castillo
1243
 */
1244
function api_protect_teacher_script()
1245
{
1246
    if (!api_is_allowed_to_edit()) {
1247
        api_not_allowed(true);
1248
1249
        return false;
1250
    }
1251
1252
    return true;
1253
}
1254
1255
/**
1256
 * Function used to prevent anonymous users from accessing a script.
1257
 *
1258
 * @param bool|true $printHeaders
1259
 *
1260
 * @author Roan Embrechts
1261
 *
1262
 * @return bool
1263
 */
1264
function api_block_anonymous_users($printHeaders = true)
1265
{
1266
    $user = api_get_user_info();
1267
    if (!(isset($user['user_id']) && $user['user_id']) || api_is_anonymous($user['user_id'], true)) {
1268
        api_not_allowed($printHeaders);
1269
1270
        return false;
1271
    }
1272
1273
    return true;
1274
}
1275
1276
/**
1277
 * Returns a rough evaluation of the browser's name and version based on very
1278
 * simple regexp.
1279
 *
1280
 * @return array with the navigator name and version ['name' => '...', 'version' => '...']
1281
 */
1282
function api_get_navigator()
1283
{
1284
    $navigator = 'Unknown';
1285
    $version = 0;
1286
1287
    if (!isset($_SERVER['HTTP_USER_AGENT'])) {
1288
        return ['name' => 'Unknown', 'version' => '0.0.0'];
1289
    }
1290
1291
    if (strpos($_SERVER['HTTP_USER_AGENT'], 'Opera') !== false) {
1292
        $navigator = 'Opera';
1293
        list(, $version) = explode('Opera', $_SERVER['HTTP_USER_AGENT']);
1294
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Edge') !== false) {
1295
        $navigator = 'Edge';
1296
        list(, $version) = explode('Edge', $_SERVER['HTTP_USER_AGENT']);
1297
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== false) {
1298
        $navigator = 'Internet Explorer';
1299
        list(, $version) = explode('MSIE ', $_SERVER['HTTP_USER_AGENT']);
1300
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Chrome') !== false) {
1301
        $navigator = 'Chrome';
1302
        list(, $version) = explode('Chrome', $_SERVER['HTTP_USER_AGENT']);
1303
    } elseif (stripos($_SERVER['HTTP_USER_AGENT'], 'Safari') !== false) {
1304
        $navigator = 'Safari';
1305
        if (stripos($_SERVER['HTTP_USER_AGENT'], 'Version/') !== false) {
1306
            // If this Safari does have the "Version/" string in its user agent
1307
            // then use that as a version indicator rather than what's after
1308
            // "Safari/" which is rather a "build number" or something
1309
            list(, $version) = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1310
        } else {
1311
            list(, $version) = explode('Safari/', $_SERVER['HTTP_USER_AGENT']);
1312
        }
1313
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Firefox') !== false) {
1314
        $navigator = 'Firefox';
1315
        list(, $version) = explode('Firefox', $_SERVER['HTTP_USER_AGENT']);
1316
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Netscape') !== false) {
1317
        $navigator = 'Netscape';
1318
        if (stripos($_SERVER['HTTP_USER_AGENT'], 'Netscape/') !== false) {
1319
            list(, $version) = explode('Netscape', $_SERVER['HTTP_USER_AGENT']);
1320
        } else {
1321
            list(, $version) = explode('Navigator', $_SERVER['HTTP_USER_AGENT']);
1322
        }
1323
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Konqueror') !== false) {
1324
        $navigator = 'Konqueror';
1325
        list(, $version) = explode('Konqueror', $_SERVER['HTTP_USER_AGENT']);
1326
    } elseif (stripos($_SERVER['HTTP_USER_AGENT'], 'applewebkit') !== false) {
1327
        $navigator = 'AppleWebKit';
1328
        list(, $version) = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1329
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Gecko') !== false) {
1330
        $navigator = 'Mozilla';
1331
        list(, $version) = explode('; rv:', $_SERVER['HTTP_USER_AGENT']);
1332
    }
1333
1334
    // Now cut extra stuff around (mostly *after*) the version number
1335
    $version = preg_replace('/^([\/\s])?([\d\.]+)?.*/', '\2', $version);
1336
1337
    if (strpos($version, '.') === false) {
1338
        $version = number_format(doubleval($version), 1);
1339
    }
1340
    $return = ['name' => $navigator, 'version' => $version];
1341
1342
    return $return;
1343
}
1344
1345
/**
1346
 * @return true if user self registration is allowed, false otherwise
1347
 */
1348
function api_is_self_registration_allowed()
1349
{
1350
    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...
1351
}
1352
1353
/**
1354
 * This function returns the id of the user which is stored in the $_user array.
1355
 *
1356
 * example: The function can be used to check if a user is logged in
1357
 *          if (api_get_user_id())
1358
 *
1359
 * @return int the id of the current user, 0 if is empty
1360
 */
1361
function api_get_user_id()
1362
{
1363
    $userInfo = Session::read('_user');
1364
    if ($userInfo && isset($userInfo['user_id'])) {
1365
        return (int) $userInfo['user_id'];
1366
    }
1367
1368
    return 0;
1369
}
1370
1371
/**
1372
 * Gets the list of courses a specific user is subscribed to.
1373
 *
1374
 * @param int       User ID
1375
 * @param bool $fetch_session Whether to get session courses or not - NOT YET IMPLEMENTED
1376
 *
1377
 * @return array Array of courses in the form [0]=>('code'=>xxx,'db'=>xxx,'dir'=>xxx,'status'=>d)
1378
 *
1379
 * @deprecated use CourseManager::get_courses_list_by_user_id()
1380
 */
1381
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

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

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

2086
function api_get_course_info($course_code = null, /** @scrutinizer ignore-unused */ $strict = false)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

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

3755
    /** @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...
3756
    $message = null,
3757
    $responseCode = 0
3758
) {
3759
    $debug = api_get_setting('server_type') === 'test';
3760
3761
    // Default code is 403 forbidden
3762
    $responseCode = empty($responseCode) ? 403 : $responseCode;
3763
    $message = empty($message) ? get_lang('NotAuthorized') : $message;
3764
3765
    // Create new exception rendered by template:
3766
    // src/ThemeBundle/Resources/views/Exception/error.html.twig
3767
3768
    // if error is 404 then the template is:
3769
    // src/ThemeBundle/Resources/views/Exception/error404.html.twig
3770
    $exception = new Exception($message);
3771
    $request = Container::getRequest();
3772
    $exception = FlattenException::create($exception, $responseCode);
3773
    $controller = new ExceptionController(Container::getTwig(), $debug);
3774
    $response = $controller->showAction($request, $exception);
3775
    $response->send();
3776
    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...
3777
3778
    $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...
3779
    $user_id = api_get_user_id();
3780
    $course = api_get_course_id();
3781
3782
    global $this_section;
3783
3784
    if (CustomPages::enabled() && !isset($user_id)) {
3785
        if (empty($user_id)) {
3786
            // Why the CustomPages::enabled() need to be to set the request_uri
3787
            $_SESSION['request_uri'] = $_SERVER['REQUEST_URI'];
3788
        }
3789
        CustomPages::display(CustomPages::INDEX_UNLOGGED);
3790
    }
3791
3792
    $origin = api_get_origin();
3793
3794
    $msg = null;
3795
    if (isset($message)) {
3796
        $msg = $message;
3797
    } else {
3798
        $msg = Display::return_message(
3799
            get_lang('NotAllowedClickBack').'
3800
            <script>function goBack(){window.history.back();}</script>',
3801
            'error',
3802
            false
3803
        );
3804
        $msg .= '<p class="text-center">
3805
             <a onclick="goBack();" class="btn btn-default" href="'.$home_url.'">'.get_lang('GoBack').'</a>
3806
             </p>';
3807
    }
3808
3809
    $msg = Display::div($msg, ['align' => 'center']);
3810
3811
    $show_headers = 0;
3812
    if ($print_headers && $origin != 'learnpath') {
3813
        $show_headers = 1;
3814
    }
3815
3816
    $tpl = new Template(null, $show_headers, $show_headers, false, true, false, true, $responseCode);
3817
    $tpl->assign('hide_login_link', 1);
3818
    $tpl->assign('content', $msg);
3819
3820
    if (($user_id != 0 && !api_is_anonymous()) &&
3821
        (!isset($course) || $course == -1) &&
3822
        empty($_GET['cidReq'])
3823
    ) {
3824
        // if the access is not authorized and there is some login information
3825
        // but the cidReq is not found, assume we are missing course data and send the user
3826
        // to the user_portal
3827
        $tpl->display_one_col_template();
3828
        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...
3829
    }
3830
3831
    if (!empty($_SERVER['REQUEST_URI']) &&
3832
        (
3833
            !empty($_GET['cidReq']) ||
3834
            $this_section == SECTION_MYPROFILE ||
3835
            $this_section == SECTION_PLATFORM_ADMIN
3836
        )
3837
    ) {
3838
        $courseCode = api_get_course_id();
3839
        // Only display form and return to the previous URL if there was a course ID included
3840
        if ($user_id != 0 && !api_is_anonymous()) {
3841
            //if there is a user ID, then the user is not allowed but the session is still there. Say so and exit
3842
            $tpl->assign('content', $msg);
3843
            $tpl->display_one_col_template();
3844
            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...
3845
        }
3846
3847
        if (!is_null($courseCode)) {
3848
            api_set_firstpage_parameter($courseCode);
3849
        }
3850
3851
        // If the user has no user ID, then his session has expired
3852
        $form = api_get_not_allowed_login_form();
3853
3854
        // see same text in auth/gotocourse.php and main_api.lib.php function api_not_allowed (above)
3855
        $content = Display::return_message(get_lang('NotAllowed'), 'error', false);
3856
3857
        if (!empty($courseCode)) {
3858
            $content .= '<h4>'.get_lang('LoginToGoToThisCourse').'</h4>';
3859
        }
3860
3861
        $content .= '<div class="well">';
3862
        $content .= $form->returnForm();
3863
        $content .= '</div>';
3864
        if (!empty($courseCode)) {
3865
            $content .= '<hr/><p style="text-align:center"><a href="'.$home_url.'">'.
3866
                get_lang('ReturnToCourseHomepage').'</a></p>';
3867
        } else {
3868
            $content .= '<hr/><p style="text-align:center"><a href="'.$home_url.'">'.
3869
                get_lang('BackHome').'</a></p>';
3870
        }
3871
3872
        $tpl->setLoginBodyClass();
3873
        $tpl->assign('content', $content);
3874
        $tpl->display_one_col_template();
3875
        exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

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

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

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

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

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

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

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

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