Completed
Push — master ( a3ace3...0ae69c )
by Julito
11:10
created

api_is_facebook_auth_activated()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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

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

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

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

// Bar.php
namespace OtherDir;

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

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

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

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

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
5
use Chamilo\CoreBundle\Entity\Session as SessionEntity;
6
use Chamilo\CoreBundle\Entity\SettingsCurrent;
7
use Chamilo\CoreBundle\Framework\Container;
8
use Chamilo\CourseBundle\Entity\CItemProperty;
9
use Chamilo\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
        $root_web = urldecode($root_web);
792
    }
793
794
    $root_web = str_replace('public/../', '', $root_web);
795
796
    if (isset($configuration['multiple_access_urls']) &&
797
        $configuration['multiple_access_urls']
798
    ) {
799
        // To avoid that the api_get_access_url() function fails since global.inc.php also calls the main_api.lib.php
800
        if (isset($configuration['access_url']) && !empty($configuration['access_url'])) {
801
            // We look into the DB the function api_get_access_url
802
            $urlInfo = api_get_access_url($configuration['access_url']);
803
            // Avoid default value
804
            $defaultValues = ['http://localhost/', 'https://localhost/'];
805
            if (!empty($urlInfo['url']) && !in_array($urlInfo['url'], $defaultValues)) {
806
                $root_web = $urlInfo['active'] == 1 ? $urlInfo['url'] : $configuration['root_web'];
807
            }
808
        }
809
    }
810
811
    $paths = [];
812
    // Initialise cache with default values.
813
    if (!array_key_exists($root_web, $paths)) {
814
        $paths[$root_web] = [
815
            WEB_PATH => '',
816
            SYS_PATH => '',
817
            REL_PATH => '',
818
            WEB_COURSE_PATH => '',
819
            SYS_COURSE_PATH => '',
820
            REL_COURSE_PATH => '',
821
            WEB_CODE_PATH => 'main/',
822
            SYS_CODE_PATH => 'main/',
823
            REL_CODE_PATH => '/main/',
824
            SYS_LANG_PATH => 'lang/',
825
            WEB_IMG_PATH => 'public/img/',
826
            WEB_CSS_PATH => 'public/build/css/',
827
            SYS_CSS_PATH => 'public/build/css/',
828
            SYS_PLUGIN_PATH => 'plugin/',
829
            WEB_PLUGIN_PATH => 'plugin/',
830
            WEB_PLUGIN_ASSET_PATH => 'public/plugins/',
831
            SYS_ARCHIVE_PATH => 'var/cache/',
832
            WEB_ARCHIVE_PATH => 'var/cache/',
833
            SYS_HOME_PATH => 'app/home/',
834
            WEB_HOME_PATH => 'app/home/',
835
            REL_HOME_PATH => 'app/home/',
836
            SYS_APP_PATH => 'var/',
837
            SYS_UPLOAD_PATH => 'var/upload/',
838
            SYS_INC_PATH => 'inc/',
839
            CONFIGURATION_PATH => 'app/config/',
840
            LIBRARY_PATH => 'inc/lib/',
841
            WEB_LIBRARY_PATH => 'inc/lib/',
842
            WEB_LIBRARY_JS_PATH => 'inc/lib/javascript/',
843
            WEB_AJAX_PATH => 'inc/ajax/',
844
            SYS_TEST_PATH => 'tests/',
845
            WEB_TEMPLATE_PATH => 'template/',
846
            SYS_TEMPLATE_PATH => 'template/',
847
            WEB_UPLOAD_PATH => 'var/upload/',
848
            WEB_PUBLIC_PATH => 'public/',
849
            SYS_PUBLIC_PATH => 'public/',
850
            WEB_FONTS_PATH => 'fonts/',
851
            SYS_FONTS_PATH => 'fonts/',
852
        ];
853
    }
854
855
    $isInitialized = [];
856
    $root_rel = $_SERVER['APP_URL_APPEND'] ?? '';
857
858
    if (!empty($root_rel)) {
859
        // Adds "/" to the root_rel
860
        $hasSlash = substr($root_rel, 0, 1);
861
        if ($hasSlash !== '/') {
862
            $root_rel = '/'.$root_rel;
863
        }
864
    }
865
866
    // Web server base and system server base.
867
    if (!array_key_exists($root_web, $isInitialized)) {
868
        // Dealing with trailing slashes.
869
        $rootWebWithSlash = api_add_trailing_slash($root_web);
870
        $root_sys = api_add_trailing_slash($root_sys);
871
        $root_rel = api_add_trailing_slash($root_rel);
872
873
        // Initialization of a table that contains common-purpose paths.
874
        $paths[$root_web][REL_PATH] = $root_rel;
875
        $paths[$root_web][REL_COURSE_PATH] = $root_rel.$course_folder;
876
        $paths[$root_web][REL_CODE_PATH] = $root_rel.$code_folder;
877
        $paths[$root_web][WEB_PATH] = $rootWebWithSlash;
878
        $paths[$root_web][WEB_CODE_PATH] = $rootWebWithSlash.$code_folder;
879
        $paths[$root_web][WEB_COURSE_PATH] = $rootWebWithSlash.$course_folder;
880
        $paths[$root_web][WEB_PLUGIN_PATH] = $rootWebWithSlash.$paths[$root_web][WEB_PLUGIN_PATH];
881
        $paths[$root_web][WEB_PLUGIN_ASSET_PATH] = $rootWebWithSlash.$paths[$root_web][WEB_PLUGIN_ASSET_PATH];
882
        $paths[$root_web][WEB_ARCHIVE_PATH] = $rootWebWithSlash.$paths[$root_web][WEB_ARCHIVE_PATH];
883
        $paths[$root_web][WEB_CSS_PATH] = $rootWebWithSlash.$paths[$root_web][WEB_CSS_PATH];
884
        $paths[$root_web][WEB_UPLOAD_PATH] = $rootWebWithSlash.$paths[$root_web][WEB_UPLOAD_PATH];
885
        $paths[$root_web][WEB_PUBLIC_PATH] = $rootWebWithSlash.$paths[$root_web][WEB_PUBLIC_PATH];
886
        $paths[$root_web][WEB_HOME_PATH] = $rootWebWithSlash.$paths[$root_web][REL_HOME_PATH];
887
888
        $paths[$root_web][WEB_IMG_PATH] = $rootWebWithSlash.$paths[$root_web][WEB_IMG_PATH];
889
        $paths[$root_web][WEB_LIBRARY_PATH] = $paths[$root_web][WEB_CODE_PATH].$paths[$root_web][WEB_LIBRARY_PATH];
890
        $paths[$root_web][WEB_LIBRARY_JS_PATH] = $paths[$root_web][WEB_CODE_PATH].$paths[$root_web][WEB_LIBRARY_JS_PATH];
891
        $paths[$root_web][WEB_AJAX_PATH] = $paths[$root_web][WEB_CODE_PATH].$paths[$root_web][WEB_AJAX_PATH];
892
        $paths[$root_web][WEB_FONTS_PATH] = $paths[$root_web][WEB_CODE_PATH].$paths[$root_web][WEB_FONTS_PATH];
893
        $paths[$root_web][WEB_TEMPLATE_PATH] = $paths[$root_web][WEB_CODE_PATH].$paths[$root_web][WEB_TEMPLATE_PATH];
894
895
        $paths[$root_web][SYS_PATH] = $root_sys;
896
        $paths[$root_web][SYS_CODE_PATH] = $root_sys.$code_folder;
897
        $paths[$root_web][SYS_TEST_PATH] = $paths[$root_web][SYS_PATH].$paths[$root_web][SYS_TEST_PATH];
898
        $paths[$root_web][SYS_TEMPLATE_PATH] = $paths[$root_web][SYS_CODE_PATH].$paths[$root_web][SYS_TEMPLATE_PATH];
899
        $paths[$root_web][SYS_PUBLIC_PATH] = $paths[$root_web][SYS_PATH].$paths[$root_web][SYS_PUBLIC_PATH];
900
        $paths[$root_web][SYS_CSS_PATH] = $paths[$root_web][SYS_PATH].$paths[$root_web][SYS_CSS_PATH];
901
        $paths[$root_web][SYS_FONTS_PATH] = $paths[$root_web][SYS_CODE_PATH].$paths[$root_web][SYS_FONTS_PATH];
902
        $paths[$root_web][SYS_ARCHIVE_PATH] = $paths[$root_web][SYS_PATH].$paths[$root_web][SYS_ARCHIVE_PATH];
903
        $paths[$root_web][SYS_APP_PATH] = $paths[$root_web][SYS_PATH].$paths[$root_web][SYS_APP_PATH];
904
        $paths[$root_web][SYS_COURSE_PATH] = $paths[$root_web][SYS_APP_PATH].$course_folder;
905
        $paths[$root_web][SYS_UPLOAD_PATH] = $paths[$root_web][SYS_PATH].$paths[$root_web][SYS_UPLOAD_PATH];
906
        $paths[$root_web][SYS_LANG_PATH] = $paths[$root_web][SYS_CODE_PATH].$paths[$root_web][SYS_LANG_PATH];
907
        $paths[$root_web][SYS_HOME_PATH] = $paths[$root_web][SYS_PATH].$paths[$root_web][SYS_HOME_PATH];
908
        $paths[$root_web][SYS_PLUGIN_PATH] = $paths[$root_web][SYS_PATH].$paths[$root_web][SYS_PLUGIN_PATH];
909
        $paths[$root_web][SYS_INC_PATH] = $paths[$root_web][SYS_CODE_PATH].$paths[$root_web][SYS_INC_PATH];
910
911
        $paths[$root_web][LIBRARY_PATH] = $paths[$root_web][SYS_CODE_PATH].$paths[$root_web][LIBRARY_PATH];
912
        $paths[$root_web][CONFIGURATION_PATH] = $paths[$root_web][SYS_PATH].$paths[$root_web][CONFIGURATION_PATH];
913
914
        global $virtualChamilo;
915
        if (!empty($virtualChamilo)) {
916
            $paths[$root_web][SYS_ARCHIVE_PATH] = api_add_trailing_slash($virtualChamilo[SYS_ARCHIVE_PATH]);
917
            $paths[$root_web][SYS_HOME_PATH] = api_add_trailing_slash($virtualChamilo[SYS_HOME_PATH]);
918
            $paths[$root_web][SYS_COURSE_PATH] = api_add_trailing_slash($virtualChamilo[SYS_COURSE_PATH]);
919
            $paths[$root_web][SYS_UPLOAD_PATH] = api_add_trailing_slash($virtualChamilo[SYS_UPLOAD_PATH]);
920
921
            $paths[$root_web][WEB_HOME_PATH] = api_add_trailing_slash($virtualChamilo[WEB_HOME_PATH]);
922
            $paths[$root_web][WEB_UPLOAD_PATH] = api_add_trailing_slash($virtualChamilo[WEB_UPLOAD_PATH]);
923
            $paths[$root_web][WEB_ARCHIVE_PATH] = api_add_trailing_slash($virtualChamilo[WEB_ARCHIVE_PATH]);
924
            //$paths[$root_web][WEB_COURSE_PATH] = api_add_trailing_slash($virtualChamilo[WEB_COURSE_PATH]);
925
926
            // WEB_UPLOAD_PATH should be handle by apache htaccess in the vhost
927
928
            // RewriteEngine On
929
            // RewriteRule /app/upload/(.*)$ http://localhost/other/upload/my-chamilo111-net/$1 [QSA,L]
930
931
            //$paths[$root_web][WEB_UPLOAD_PATH] = api_add_trailing_slash($virtualChamilo[WEB_UPLOAD_PATH]);
932
            //$paths[$root_web][REL_PATH] = $virtualChamilo[REL_PATH];
933
            //$paths[$root_web][REL_COURSE_PATH] = $virtualChamilo[REL_COURSE_PATH];
934
        }
935
936
        $isInitialized[$root_web] = true;
937
    }
938
939
    $path = trim($path);
940
941
    // Retrieving a common-purpose path.
942
    if (isset($paths[$root_web][$path])) {
943
        return $paths[$root_web][$path];
944
    }
945
946
    // Second purification.
947
948
    // Replacing Windows back slashes.
949
    $path = str_replace('\\', '/', $path);
950
    // Query strings sometimes mighth wrongly appear in non-URLs.
951
    // Let us check remove them from all types of paths.
952
    if (($pos = strpos($path, '?')) !== false) {
953
        $path = substr($path, 0, $pos);
954
    }
955
956
    // Path now is semi-absolute. It is convenient at this moment repeated slashes to be removed.
957
    $path = preg_replace(REPEATED_SLASHES_PURIFIER, '/', $path);
958
959
    return $path;
960
}
961
962
/**
963
 * Gets a modified version of the path for the CDN, if defined in
964
 * configuration.php.
965
 *
966
 * @param string $web_path The path of the resource without CDN
967
 *
968
 * @return string The path of the resource converted to CDN
969
 *
970
 * @author Yannick Warnier <[email protected]>
971
 */
972
function api_get_cdn_path($web_path)
973
{
974
    global $_configuration;
975
    $web_root = api_get_path(WEB_PATH);
976
    $ext = substr($web_path, strrpos($web_path, '.'));
977
    if (isset($ext[2])) { // faster version of strlen to check if len>2
978
        // Check for CDN definitions
979
        if (!empty($_configuration['cdn_enable']) && !empty($ext)) {
980
            foreach ($_configuration['cdn'] as $host => $exts) {
981
                if (in_array($ext, $exts)) {
982
                    //Use host as defined in $_configuration['cdn'], without
983
                    // trailing slash
984
                    return str_replace($web_root, $host.'/', $web_path);
985
                }
986
            }
987
        }
988
    }
989
990
    return $web_path;
991
}
992
993
/**
994
 * Adds to a given path a trailing slash if it is necessary (adds "/" character at the end of the string).
995
 *
996
 * @param string $path the input path
997
 *
998
 * @return string returns the modified path
999
 */
1000
function api_add_trailing_slash($path)
1001
{
1002
    return substr($path, -1) == '/' ? $path : $path.'/';
1003
}
1004
1005
/**
1006
 * Removes from a given path the trailing slash if it is necessary (removes "/" character from the end of the string).
1007
 *
1008
 * @param string $path the input path
1009
 *
1010
 * @return string returns the modified path
1011
 */
1012
function api_remove_trailing_slash($path)
1013
{
1014
    return substr($path, -1) == '/' ? substr($path, 0, -1) : $path;
1015
}
1016
1017
/**
1018
 * Checks the RFC 3986 syntax of a given URL.
1019
 *
1020
 * @param string $url      the URL to be checked
1021
 * @param bool   $absolute whether the URL is absolute (beginning with a scheme such as "http:")
1022
 *
1023
 * @return string|false Returns the URL if it is valid, FALSE otherwise.
1024
 *                      This function is an adaptation from the function valid_url(), Drupal CMS.
1025
 *
1026
 * @see http://drupal.org
1027
 * Note: The built-in function filter_var($urs, FILTER_VALIDATE_URL) has a bug for some versions of PHP.
1028
 * @see http://bugs.php.net/51192
1029
 */
1030
function api_valid_url($url, $absolute = false)
1031
{
1032
    if ($absolute) {
1033
        if (preg_match("
1034
            /^                                                      # Start at the beginning of the text
1035
            (?:ftp|https?|feed):\/\/                                # Look for ftp, http, https or feed schemes
1036
            (?:                                                     # Userinfo (optional) which is typically
1037
                (?:(?:[\w\.\-\+!$&'\(\)*\+,;=]|%[0-9a-f]{2})+:)*    # a username or a username and password
1038
                (?:[\w\.\-\+%!$&'\(\)*\+,;=]|%[0-9a-f]{2})+@        # combination
1039
            )?
1040
            (?:
1041
                (?:[a-z0-9\-\.]|%[0-9a-f]{2})+                      # A domain name or a IPv4 address
1042
                |(?:\[(?:[0-9a-f]{0,4}:)*(?:[0-9a-f]{0,4})\])       # or a well formed IPv6 address
1043
            )
1044
            (?::[0-9]+)?                                            # Server port number (optional)
1045
            (?:[\/|\?]
1046
                (?:[\w#!:\.\?\+=&@$'~*,;\/\(\)\[\]\-]|%[0-9a-f]{2}) # The path and query (optional)
1047
            *)?
1048
            $/xi", $url)) {
1049
            return $url;
1050
        }
1051
1052
        return false;
1053
    } else {
1054
        return preg_match("/^(?:[\w#!:\.\?\+=&@$'~*,;\/\(\)\[\]\-]|%[0-9a-f]{2})+$/i", $url) ? $url : false;
1055
    }
1056
}
1057
1058
/**
1059
 * Checks whether a given string looks roughly like an email address.
1060
 *
1061
 * @param string $address the e-mail address to be checked
1062
 *
1063
 * @return mixed returns the e-mail if it is valid, FALSE otherwise
1064
 */
1065
function api_valid_email($address)
1066
{
1067
    return filter_var($address, FILTER_VALIDATE_EMAIL);
1068
}
1069
1070
/* PROTECTION FUNCTIONS
1071
   Use these functions to protect your scripts. */
1072
1073
/**
1074
 * Function used to protect a course script.
1075
 * The function blocks access when
1076
 * - there is no $_SESSION["_course"] defined; or
1077
 * - $is_allowed_in_course is set to false (this depends on the course
1078
 * visibility and user status).
1079
 *
1080
 * This is only the first proposal, test and improve!
1081
 *
1082
 * @param bool Option to print headers when displaying error message. Default: false
1083
 * @param bool whether session admins should be allowed or not
1084
 * @param bool $checkTool check if tool is available for users (user, group)
1085
 *
1086
 * @return bool True if the user has access to the current course or is out of a course context, false otherwise
1087
 *
1088
 * @todo replace global variable
1089
 *
1090
 * @author Roan Embrechts
1091
 */
1092
function api_protect_course_script($print_headers = false, $allow_session_admins = false, $checkTool = '')
1093
{
1094
    $course_info = api_get_course_info();
1095
    if (empty($course_info)) {
1096
        api_not_allowed($print_headers);
1097
1098
        return false;
1099
    }
1100
1101
    if (api_is_drh()) {
1102
        return true;
1103
    }
1104
1105
    // Session admin has access to course
1106
    $sessionAccess = api_get_configuration_value('session_admins_access_all_content');
1107
    if ($sessionAccess) {
1108
        $allow_session_admins = true;
1109
    }
1110
1111
    if (api_is_platform_admin($allow_session_admins)) {
1112
        return true;
1113
    }
1114
1115
    $isAllowedInCourse = api_is_allowed_in_course();
1116
    $is_visible = false;
1117
    if (isset($course_info) && isset($course_info['visibility'])) {
1118
        switch ($course_info['visibility']) {
1119
            default:
1120
            case COURSE_VISIBILITY_CLOSED:
1121
                // Completely closed: the course is only accessible to the teachers. - 0
1122
                if (api_get_user_id() && !api_is_anonymous() && $isAllowedInCourse) {
1123
                    $is_visible = true;
1124
                }
1125
                break;
1126
            case COURSE_VISIBILITY_REGISTERED:
1127
                // Private - access authorized to course members only - 1
1128
                if (api_get_user_id() && !api_is_anonymous() && $isAllowedInCourse) {
1129
                    $is_visible = true;
1130
                }
1131
                break;
1132
            case COURSE_VISIBILITY_OPEN_PLATFORM:
1133
                // Open - access allowed for users registered on the platform - 2
1134
                if (api_get_user_id() && !api_is_anonymous() && $isAllowedInCourse) {
1135
                    $is_visible = true;
1136
                }
1137
                break;
1138
            case COURSE_VISIBILITY_OPEN_WORLD:
1139
                //Open - access allowed for the whole world - 3
1140
                $is_visible = true;
1141
                break;
1142
            case COURSE_VISIBILITY_HIDDEN:
1143
                //Completely closed: the course is only accessible to the teachers. - 0
1144
                if (api_is_platform_admin()) {
1145
                    $is_visible = true;
1146
                }
1147
                break;
1148
        }
1149
1150
        //If password is set and user is not registered to the course then the course is not visible
1151
        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...
1152
            isset($course_info['registration_code']) &&
1153
            !empty($course_info['registration_code'])
1154
        ) {
1155
            $is_visible = false;
1156
        }
1157
    }
1158
1159
    if (!empty($checkTool)) {
1160
        if (!api_is_allowed_to_edit(true, true, true)) {
1161
            $toolInfo = api_get_tool_information_by_name($checkTool);
1162
            if (!empty($toolInfo) && isset($toolInfo['visibility']) && $toolInfo['visibility'] == 0) {
1163
                api_not_allowed(true);
1164
1165
                return false;
1166
            }
1167
        }
1168
    }
1169
1170
    // Check session visibility
1171
    $session_id = api_get_session_id();
1172
1173
    if (!empty($session_id)) {
1174
        // $isAllowedInCourse was set in local.inc.php
1175
        if (!$isAllowedInCourse) {
1176
            $is_visible = false;
1177
        }
1178
    }
1179
1180
    if (!$is_visible) {
1181
        api_not_allowed($print_headers);
1182
1183
        return false;
1184
    }
1185
1186
    return true;
1187
}
1188
1189
/**
1190
 * Function used to protect an admin script.
1191
 *
1192
 * The function blocks access when the user has no platform admin rights
1193
 * with an error message printed on default output
1194
 *
1195
 * @param bool Whether to allow session admins as well
1196
 * @param bool Whether to allow HR directors as well
1197
 * @param string An optional message (already passed through get_lang)
1198
 *
1199
 * @return bool True if user is allowed, false otherwise.
1200
 *              The function also outputs an error message in case not allowed
1201
 *
1202
 * @author Roan Embrechts (original author)
1203
 */
1204
function api_protect_admin_script($allow_sessions_admins = false, $allow_drh = false, $message = null)
1205
{
1206
    if (!api_is_platform_admin($allow_sessions_admins, $allow_drh)) {
1207
        api_not_allowed(true, $message);
1208
1209
        return false;
1210
    }
1211
1212
    return true;
1213
}
1214
1215
/**
1216
 * Function used to protect a teacher script.
1217
 * The function blocks access when the user has no teacher rights.
1218
 *
1219
 * @return bool True if the current user can access the script, false otherwise
1220
 *
1221
 * @author Yoselyn Castillo
1222
 */
1223
function api_protect_teacher_script()
1224
{
1225
    if (!api_is_allowed_to_edit()) {
1226
        api_not_allowed(true);
1227
1228
        return false;
1229
    }
1230
1231
    return true;
1232
}
1233
1234
/**
1235
 * Function used to prevent anonymous users from accessing a script.
1236
 *
1237
 * @param bool|true $printHeaders
1238
 *
1239
 * @author Roan Embrechts
1240
 *
1241
 * @return bool
1242
 */
1243
function api_block_anonymous_users($printHeaders = true)
1244
{
1245
    $user = api_get_user_info();
1246
    if (!(isset($user['user_id']) && $user['user_id']) || api_is_anonymous($user['user_id'], true)) {
1247
        api_not_allowed($printHeaders);
1248
1249
        return false;
1250
    }
1251
1252
    return true;
1253
}
1254
1255
/**
1256
 * Returns a rough evaluation of the browser's name and version based on very
1257
 * simple regexp.
1258
 *
1259
 * @return array with the navigator name and version ['name' => '...', 'version' => '...']
1260
 */
1261
function api_get_navigator()
1262
{
1263
    $navigator = 'Unknown';
1264
    $version = 0;
1265
1266
    if (!isset($_SERVER['HTTP_USER_AGENT'])) {
1267
        return ['name' => 'Unknown', 'version' => '0.0.0'];
1268
    }
1269
1270
    if (strpos($_SERVER['HTTP_USER_AGENT'], 'Opera') !== false) {
1271
        $navigator = 'Opera';
1272
        list(, $version) = explode('Opera', $_SERVER['HTTP_USER_AGENT']);
1273
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Edge') !== false) {
1274
        $navigator = 'Edge';
1275
        list(, $version) = explode('Edge', $_SERVER['HTTP_USER_AGENT']);
1276
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== false) {
1277
        $navigator = 'Internet Explorer';
1278
        list(, $version) = explode('MSIE ', $_SERVER['HTTP_USER_AGENT']);
1279
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Chrome') !== false) {
1280
        $navigator = 'Chrome';
1281
        list(, $version) = explode('Chrome', $_SERVER['HTTP_USER_AGENT']);
1282
    } elseif (stripos($_SERVER['HTTP_USER_AGENT'], 'Safari') !== false) {
1283
        $navigator = 'Safari';
1284
        if (stripos($_SERVER['HTTP_USER_AGENT'], 'Version/') !== false) {
1285
            // If this Safari does have the "Version/" string in its user agent
1286
            // then use that as a version indicator rather than what's after
1287
            // "Safari/" which is rather a "build number" or something
1288
            list(, $version) = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1289
        } else {
1290
            list(, $version) = explode('Safari/', $_SERVER['HTTP_USER_AGENT']);
1291
        }
1292
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Firefox') !== false) {
1293
        $navigator = 'Firefox';
1294
        list(, $version) = explode('Firefox', $_SERVER['HTTP_USER_AGENT']);
1295
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Netscape') !== false) {
1296
        $navigator = 'Netscape';
1297
        if (stripos($_SERVER['HTTP_USER_AGENT'], 'Netscape/') !== false) {
1298
            list(, $version) = explode('Netscape', $_SERVER['HTTP_USER_AGENT']);
1299
        } else {
1300
            list(, $version) = explode('Navigator', $_SERVER['HTTP_USER_AGENT']);
1301
        }
1302
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Konqueror') !== false) {
1303
        $navigator = 'Konqueror';
1304
        list(, $version) = explode('Konqueror', $_SERVER['HTTP_USER_AGENT']);
1305
    } elseif (stripos($_SERVER['HTTP_USER_AGENT'], 'applewebkit') !== false) {
1306
        $navigator = 'AppleWebKit';
1307
        list(, $version) = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1308
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Gecko') !== false) {
1309
        $navigator = 'Mozilla';
1310
        list(, $version) = explode('; rv:', $_SERVER['HTTP_USER_AGENT']);
1311
    }
1312
1313
    // Now cut extra stuff around (mostly *after*) the version number
1314
    $version = preg_replace('/^([\/\s])?([\d\.]+)?.*/', '\2', $version);
1315
1316
    if (strpos($version, '.') === false) {
1317
        $version = number_format(doubleval($version), 1);
1318
    }
1319
    $return = ['name' => $navigator, 'version' => $version];
1320
1321
    return $return;
1322
}
1323
1324
/**
1325
 * @return true if user self registration is allowed, false otherwise
1326
 */
1327
function api_is_self_registration_allowed()
1328
{
1329
    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...
1330
}
1331
1332
/**
1333
 * This function returns the id of the user which is stored in the $_user array.
1334
 *
1335
 * example: The function can be used to check if a user is logged in
1336
 *          if (api_get_user_id())
1337
 *
1338
 * @return int the id of the current user, 0 if is empty
1339
 */
1340
function api_get_user_id()
1341
{
1342
    $userInfo = Session::read('_user');
1343
    if ($userInfo && isset($userInfo['user_id'])) {
1344
        return (int) $userInfo['user_id'];
1345
    }
1346
1347
    return 0;
1348
}
1349
1350
/**
1351
 * Gets the list of courses a specific user is subscribed to.
1352
 *
1353
 * @param int       User ID
1354
 * @param bool $fetch_session Whether to get session courses or not - NOT YET IMPLEMENTED
1355
 *
1356
 * @return array Array of courses in the form [0]=>('code'=>xxx,'db'=>xxx,'dir'=>xxx,'status'=>d)
1357
 *
1358
 * @deprecated use CourseManager::get_courses_list_by_user_id()
1359
 */
1360
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

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

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

3734
    /** @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...
3735
    $message = null,
3736
    $responseCode = 0
3737
) {
3738
    $debug = api_get_setting('server_type') === 'test';
3739
3740
    // Default code is 403 forbidden
3741
    $responseCode = empty($responseCode) ? 403 : $responseCode;
3742
    $message = empty($message) ? get_lang('NotAuthorized') : $message;
3743
3744
    // Create new exception rendered by template:
3745
    // src/ThemeBundle/Resources/views/Exception/error.html.twig
3746
3747
    // if error is 404 then the template is:
3748
    // src/ThemeBundle/Resources/views/Exception/error404.html.twig
3749
    $exception = new Exception($message);
3750
    $request = Container::getRequest();
3751
    $exception = FlattenException::create($exception, $responseCode);
3752
    $controller = new ExceptionController(Container::getTwig(), $debug);
3753
    $response = $controller->showAction($request, $exception);
3754
    $response->send();
3755
    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...
3756
3757
    $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...
3758
    $user_id = api_get_user_id();
3759
    $course = api_get_course_id();
3760
3761
    global $this_section;
3762
3763
    if (CustomPages::enabled() && !isset($user_id)) {
3764
        if (empty($user_id)) {
3765
            // Why the CustomPages::enabled() need to be to set the request_uri
3766
            $_SESSION['request_uri'] = $_SERVER['REQUEST_URI'];
3767
        }
3768
        CustomPages::display(CustomPages::INDEX_UNLOGGED);
3769
    }
3770
3771
    $origin = api_get_origin();
3772
3773
    $msg = null;
3774
    if (isset($message)) {
3775
        $msg = $message;
3776
    } else {
3777
        $msg = Display::return_message(
3778
            get_lang('NotAllowedClickBack').'
3779
            <script>function goBack(){window.history.back();}</script>',
3780
            'error',
3781
            false
3782
        );
3783
        $msg .= '<p class="text-center">
3784
             <a onclick="goBack();" class="btn btn-default" href="'.$home_url.'">'.get_lang('GoBack').'</a>
3785
             </p>';
3786
    }
3787
3788
    $msg = Display::div($msg, ['align' => 'center']);
3789
3790
    $show_headers = 0;
3791
    if ($print_headers && $origin != 'learnpath') {
3792
        $show_headers = 1;
3793
    }
3794
3795
    $tpl = new Template(null, $show_headers, $show_headers, false, true, false, true, $responseCode);
3796
    $tpl->assign('hide_login_link', 1);
3797
    $tpl->assign('content', $msg);
3798
3799
    if (($user_id != 0 && !api_is_anonymous()) &&
3800
        (!isset($course) || $course == -1) &&
3801
        empty($_GET['cidReq'])
3802
    ) {
3803
        // if the access is not authorized and there is some login information
3804
        // but the cidReq is not found, assume we are missing course data and send the user
3805
        // to the user_portal
3806
        $tpl->display_one_col_template();
3807
        exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

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

Loading history...
3808
    }
3809
3810
    if (!empty($_SERVER['REQUEST_URI']) &&
3811
        (
3812
            !empty($_GET['cidReq']) ||
3813
            $this_section == SECTION_MYPROFILE ||
3814
            $this_section == SECTION_PLATFORM_ADMIN
3815
        )
3816
    ) {
3817
        $courseCode = api_get_course_id();
3818
        // Only display form and return to the previous URL if there was a course ID included
3819
        if ($user_id != 0 && !api_is_anonymous()) {
3820
            //if there is a user ID, then the user is not allowed but the session is still there. Say so and exit
3821
            $tpl->assign('content', $msg);
3822
            $tpl->display_one_col_template();
3823
            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...
3824
        }
3825
3826
        if (!is_null($courseCode)) {
3827
            api_set_firstpage_parameter($courseCode);
3828
        }
3829
3830
        // If the user has no user ID, then his session has expired
3831
        $form = api_get_not_allowed_login_form();
3832
3833
        // see same text in auth/gotocourse.php and main_api.lib.php function api_not_allowed (above)
3834
        $content = Display::return_message(get_lang('NotAllowed'), 'error', false);
3835
3836
        if (!empty($courseCode)) {
3837
            $content .= '<h4>'.get_lang('LoginToGoToThisCourse').'</h4>';
3838
        }
3839
3840
        $content .= '<div class="well">';
3841
        $content .= $form->returnForm();
3842
        $content .= '</div>';
3843
        if (!empty($courseCode)) {
3844
            $content .= '<hr/><p style="text-align:center"><a href="'.$home_url.'">'.
3845
                get_lang('ReturnToCourseHomepage').'</a></p>';
3846
        } else {
3847
            $content .= '<hr/><p style="text-align:center"><a href="'.$home_url.'">'.
3848
                get_lang('BackHome').'</a></p>';
3849
        }
3850
3851
        $tpl->setLoginBodyClass();
3852
        $tpl->assign('content', $content);
3853
        $tpl->display_one_col_template();
3854
        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...
3855
    }
3856
3857
    if ($user_id != 0 && !api_is_anonymous()) {
3858
        $tpl->display_one_col_template();
3859
        exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

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

Loading history...
3860
    }
3861
3862
    $msg = null;
3863
    // The session is over and we were not in a course,
3864
    // or we try to get directly to a private course without being logged
3865
    $courseId = api_get_course_int_id();
3866
    if (!empty($courseId)) {
3867
        api_set_firstpage_parameter(api_get_course_id());
3868
        $tpl->setLoginBodyClass();
3869
3870
        // see same text in auth/gotocourse.php and main_api.lib.php function api_not_allowed (bellow)
3871
        $msg = Display::return_message(get_lang('NotAllowed'), 'error', false);
3872
        $msg .= '<h4>'.get_lang('LoginToGoToThisCourse').'</h4>';
3873
        $form = api_get_not_allowed_login_form();
3874
        $msg .= '<div class="well">';
3875
        $msg .= $form->returnForm();
3876
        $msg .= '</div>';
3877
        if ($casEnabled) {
3878
            $msg .= "</div>";
3879
        }
3880
    } else {
3881
        // we were not in a course, return to home page
3882
        $msg = Display::return_message(
3883
            get_lang('NotAllowed'),
3884
            'error',
3885
            false
3886
        );
3887
3888
        $msg .= '<p class="text-center">
3889
                 <a class="btn btn-default" href="'.$home_url.'">'.get_lang('BackHome').'</a>
3890
                 </p>';
3891
3892
        if (!empty($message)) {
3893
            $msg = $message;
3894
        }
3895
3896
        if (api_is_anonymous()) {
3897
            $form = api_get_not_allowed_login_form();
3898
            $msg .= '<div class="well">';
3899
            $msg .= $form->returnForm();
3900
            $msg .= '</div>';
3901
        }
3902
    }
3903
3904
    $tpl->assign('content', $msg);
3905
    $tpl->display_one_col_template();
3906
    exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

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

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

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

5448
    while ($file = readdir(/** @scrutinizer ignore-type */ $handler)) {
Loading history...
5449
        if ($file != '.' && $file != '..') {
5450
            $fullpath = "$path/$file";
5451
            if (!is_dir($fullpath)) {
5452
                if (!chmod($fullpath, $filemode)) {
5453
                    return false;
5454
                }
5455
            } else {
5456
                if (!api_chmod_R($fullpath, $filemode)) {
5457
                    return false;
5458
                }
5459
            }
5460
        }
5461
    }
5462
5463
    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

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

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

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

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

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