api_get_visual_theme()   F
last analyzed

Complexity

Conditions 25
Paths > 20000

Size

Total Lines 102
Code Lines 56

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 56
c 0
b 0
f 0
dl 0
loc 102
rs 0
cc 25
nc 43016
nop 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

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

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

1314
                        /** @scrutinizer ignore-call */ 
1315
                        $results = Event::getExerciseResultsByUser(

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
1315
                            api_get_user_id(),
1316
                            $initialData['exercise_id'],
1317
                            $course_info['real_id'],
1318
                            $session_id
1319
                        );
1320
                        if (empty($results)) {
1321
                            api_not_allowed($print_headers);
1322
1323
                            return false;
1324
                        }
1325
                    }
1326
                }
1327
            }
1328
        }
1329
    }
1330
1331
    api_block_inactive_user();
1332
1333
    return true;
1334
}
1335
1336
/**
1337
 * Function used to protect an admin script.
1338
 *
1339
 * The function blocks access when the user has no platform admin rights
1340
 * with an error message printed on default output
1341
 *
1342
 * @param bool Whether to allow session admins as well
1343
 * @param bool Whether to allow HR directors as well
1344
 * @param string An optional message (already passed through get_lang)
1345
 * @param bool Whether to allow session coach as well
1346
 *
1347
 * @return bool True if user is allowed, false otherwise.
1348
 *              The function also outputs an error message in case not allowed
1349
 *
1350
 * @author Roan Embrechts (original author)
1351
 */
1352
function api_protect_admin_script($allow_sessions_admins = false, $allow_drh = false, $message = null, $allow_session_coach = false)
1353
{
1354
    if (!api_is_platform_admin($allow_sessions_admins, $allow_drh)) {
1355
        if (!($allow_session_coach && api_is_coach())) {
1356
            api_not_allowed(true, $message);
1357
1358
            return false;
1359
        }
1360
    }
1361
    api_block_inactive_user();
1362
1363
    return true;
1364
}
1365
1366
/**
1367
 * Blocks inactive users with a currently active session from accessing more pages "live".
1368
 *
1369
 * @return bool Returns true if the feature is disabled or the user account is still enabled.
1370
 *              Returns false (and shows a message) if the feature is enabled *and* the user is disabled.
1371
 */
1372
function api_block_inactive_user()
1373
{
1374
    $data = true;
1375
    if (api_get_configuration_value('security_block_inactive_users_immediately') != 1) {
1376
        return $data;
1377
    }
1378
1379
    $userId = api_get_user_id();
1380
    $homeUrl = api_get_path(WEB_PATH);
1381
    if ($userId == 0) {
1382
        return $data;
1383
    }
1384
1385
    $sql = "SELECT active FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1386
            WHERE id = $userId";
1387
1388
    $result = Database::query($sql);
1389
    if (Database::num_rows($result) > 0) {
1390
        $result_array = Database::fetch_array($result);
1391
        $data = (bool) $result_array['active'];
1392
    }
1393
    if ($data == 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...
1394
        $tpl = new Template(null, true, true, false, true, false, true, 0);
1395
        $tpl->assign('hide_login_link', 1);
1396
1397
        //api_not_allowed(true, get_lang('AccountInactive'));
1398
        // we were not in a course, return to home page
1399
        $msg = Display::return_message(
1400
            get_lang('AccountInactive'),
1401
            'error',
1402
            false
1403
        );
1404
1405
        $msg .= '<p class="text-center">
1406
                 <a class="btn btn-default" href="'.$homeUrl.'">'.get_lang('BackHome').'</a></p>';
1407
1408
        if (api_is_anonymous()) {
1409
            $form = api_get_not_allowed_login_form();
1410
            $msg .= '<div class="well">';
1411
            $msg .= $form->returnForm();
1412
            $msg .= '</div>';
1413
        }
1414
1415
        $tpl->assign('content', $msg);
1416
        $tpl->display_one_col_template();
1417
        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...
1418
    }
1419
1420
    return $data;
1421
}
1422
1423
/**
1424
 * Function used to protect a teacher script.
1425
 * The function blocks access when the user has no teacher rights.
1426
 *
1427
 * @return bool True if the current user can access the script, false otherwise
1428
 *
1429
 * @author Yoselyn Castillo
1430
 */
1431
function api_protect_teacher_script()
1432
{
1433
    if (!api_is_allowed_to_edit()) {
1434
        api_not_allowed(true);
1435
1436
        return false;
1437
    }
1438
1439
    return true;
1440
}
1441
1442
/**
1443
 * Function used to prevent anonymous users from accessing a script.
1444
 *
1445
 * @param bool|true $printHeaders
1446
 *
1447
 * @author Roan Embrechts
1448
 *
1449
 * @return bool
1450
 */
1451
function api_block_anonymous_users($printHeaders = true)
1452
{
1453
    $user = api_get_user_info();
1454
    if (empty($user['user_id']) || api_is_anonymous($user['user_id'], true)) {
1455
        api_not_allowed($printHeaders);
1456
1457
        return false;
1458
    }
1459
    api_block_inactive_user();
1460
1461
    return true;
1462
}
1463
1464
/**
1465
 * Returns a rough evaluation of the browser's name and version based on very
1466
 * simple regexp.
1467
 *
1468
 * @return array with the navigator name and version ['name' => '...', 'version' => '...']
1469
 */
1470
function api_get_navigator()
1471
{
1472
    $navigator = 'Unknown';
1473
    $version = 0;
1474
1475
    if (!isset($_SERVER['HTTP_USER_AGENT'])) {
1476
        return ['name' => 'Unknown', 'version' => '0.0.0'];
1477
    }
1478
1479
    if (strpos($_SERVER['HTTP_USER_AGENT'], 'Opera') !== false) {
1480
        $navigator = 'Opera';
1481
        list(, $version) = explode('Opera', $_SERVER['HTTP_USER_AGENT']);
1482
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Edge') !== false) {
1483
        $navigator = 'Edge';
1484
        list(, $version) = explode('Edge', $_SERVER['HTTP_USER_AGENT']);
1485
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== false) {
1486
        $navigator = 'Internet Explorer';
1487
        list(, $version) = explode('MSIE ', $_SERVER['HTTP_USER_AGENT']);
1488
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Chrome') !== false) {
1489
        $navigator = 'Chrome';
1490
        list(, $version) = explode('Chrome', $_SERVER['HTTP_USER_AGENT']);
1491
    } elseif (stripos($_SERVER['HTTP_USER_AGENT'], 'Safari') !== false) {
1492
        $navigator = 'Safari';
1493
        if (stripos($_SERVER['HTTP_USER_AGENT'], 'Version/') !== false) {
1494
            // If this Safari does have the "Version/" string in its user agent
1495
            // then use that as a version indicator rather than what's after
1496
            // "Safari/" which is rather a "build number" or something
1497
            list(, $version) = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1498
        } else {
1499
            list(, $version) = explode('Safari/', $_SERVER['HTTP_USER_AGENT']);
1500
        }
1501
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Firefox') !== false) {
1502
        $navigator = 'Firefox';
1503
        list(, $version) = explode('Firefox', $_SERVER['HTTP_USER_AGENT']);
1504
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Netscape') !== false) {
1505
        $navigator = 'Netscape';
1506
        if (stripos($_SERVER['HTTP_USER_AGENT'], 'Netscape/') !== false) {
1507
            list(, $version) = explode('Netscape', $_SERVER['HTTP_USER_AGENT']);
1508
        } else {
1509
            list(, $version) = explode('Navigator', $_SERVER['HTTP_USER_AGENT']);
1510
        }
1511
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Konqueror') !== false) {
1512
        $navigator = 'Konqueror';
1513
        list(, $version) = explode('Konqueror', $_SERVER['HTTP_USER_AGENT']);
1514
    } elseif (stripos($_SERVER['HTTP_USER_AGENT'], 'applewebkit') !== false) {
1515
        $navigator = 'AppleWebKit';
1516
        list(, $version) = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1517
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Gecko') !== false) {
1518
        $navigator = 'Mozilla';
1519
        list(, $version) = explode('; rv:', $_SERVER['HTTP_USER_AGENT']);
1520
    }
1521
1522
    // Now cut extra stuff around (mostly *after*) the version number
1523
    $version = preg_replace('/^([\/\s])?([\d\.]+)?.*/', '\2', $version);
1524
1525
    if (strpos($version, '.') === false) {
1526
        $version = number_format(doubleval($version), 1);
1527
    }
1528
1529
    return ['name' => $navigator, 'version' => $version];
1530
}
1531
/**
1532
 * Check if it is a desktop or mobile browser.
1533
 */
1534
function api_is_browser_mobile(): bool
1535
{
1536
    if (empty($_SERVER['HTTP_USER_AGENT'])) {
1537
        static $isMobile = false;
1538
    } elseif (
1539
        strpos($_SERVER['HTTP_USER_AGENT'], 'Mobile') !== false
1540
        || strpos($_SERVER['HTTP_USER_AGENT'], 'Android') !== false
1541
        || strpos($_SERVER['HTTP_USER_AGENT'], 'Silk/') !== false
1542
        || strpos($_SERVER['HTTP_USER_AGENT'], 'Kindle') !== false
1543
        || strpos($_SERVER['HTTP_USER_AGENT'], 'BlackBerry') !== false
1544
        || strpos($_SERVER['HTTP_USER_AGENT'], 'Opera Mini') !== false
1545
        || strpos($_SERVER['HTTP_USER_AGENT'], 'Opera Mobi') !== false
1546
    ) {
1547
        $isMobile = true;
1548
    } else {
1549
        $isMobile = false;
1550
    }
1551
1552
    return $isMobile;
1553
}
1554
1555
/**
1556
 * @return true if user self registration is allowed, false otherwise
1557
 */
1558
function api_is_self_registration_allowed()
1559
{
1560
    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...
1561
}
1562
1563
/**
1564
 * This function returns the id of the user which is stored in the $_user array.
1565
 *
1566
 * example: The function can be used to check if a user is logged in
1567
 *          if (api_get_user_id())
1568
 *
1569
 * @return int the id of the current user, 0 if is empty
1570
 */
1571
function api_get_user_id()
1572
{
1573
    $userInfo = Session::read('_user');
1574
    if ($userInfo && isset($userInfo['user_id'])) {
1575
        return (int) $userInfo['user_id'];
1576
    }
1577
1578
    return 0;
1579
}
1580
1581
/**
1582
 * Gets the list of courses a specific user is subscribed to.
1583
 *
1584
 * @param int       User ID
1585
 * @param bool $fetch_session Whether to get session courses or not - NOT YET IMPLEMENTED
1586
 *
1587
 * @return array Array of courses in the form [0]=>('code'=>xxx,'db'=>xxx,'dir'=>xxx,'status'=>d)
1588
 *
1589
 * @deprecated use CourseManager::get_courses_list_by_user_id()
1590
 */
1591
function api_get_user_courses($userId, $fetch_session = true)
1592
{
1593
    // Get out if not integer
1594
    if ($userId != strval(intval($userId))) {
1595
        return [];
1596
    }
1597
1598
    $t_course = Database::get_main_table(TABLE_MAIN_COURSE);
1599
    $t_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
1600
1601
    $sql = "SELECT cc.id as real_id, cc.code code, cc.directory dir, cu.status status
1602
            FROM $t_course cc, $t_course_user cu
1603
            WHERE
1604
                cc.id = cu.c_id AND
1605
                cu.user_id = $userId AND
1606
                cu.relation_type <> ".COURSE_RELATION_TYPE_RRHH;
1607
    $result = Database::query($sql);
1608
    if ($result === false) {
1609
        return [];
1610
    }
1611
1612
    $courses = [];
1613
    while ($row = Database::fetch_array($result)) {
1614
        // we only need the database name of the course
1615
        $courses[] = $row;
1616
    }
1617
1618
    return $courses;
1619
}
1620
1621
/**
1622
 * Formats user information into a standard array
1623
 * This function should be only used inside api_get_user_info().
1624
 *
1625
 * @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...
1626
 * @param bool $add_password
1627
 * @param bool $loadAvatars  turn off to improve performance
1628
 *
1629
 * @return array Standard user array
1630
 */
1631
function _api_format_user($user, $add_password = false, $loadAvatars = true)
1632
{
1633
    $result = [];
1634
1635
    $result['firstname'] = null;
1636
    $result['lastname'] = null;
1637
1638
    if (isset($user['firstname']) && isset($user['lastname'])) { // with only lowercase
1639
        $result['firstname'] = $user['firstname'];
1640
        $result['lastname'] = $user['lastname'];
1641
    } elseif (isset($user['firstName']) && isset($user['lastName'])) { // with uppercase letters
1642
        $result['firstname'] = isset($user['firstName']) ? $user['firstName'] : null;
1643
        $result['lastname'] = isset($user['lastName']) ? $user['lastName'] : null;
1644
    }
1645
1646
    if (isset($user['email'])) {
1647
        $result['mail'] = isset($user['email']) ? $user['email'] : null;
1648
        $result['email'] = isset($user['email']) ? $user['email'] : null;
1649
    } else {
1650
        $result['mail'] = isset($user['mail']) ? $user['mail'] : null;
1651
        $result['email'] = isset($user['mail']) ? $user['mail'] : null;
1652
    }
1653
1654
    $result['complete_name'] = api_get_person_name($result['firstname'], $result['lastname']);
1655
    $result['complete_name_with_username'] = $result['complete_name'];
1656
1657
    if (!empty($user['username']) && !api_get_configuration_value('hide_username_with_complete_name')) {
1658
        $result['complete_name_with_username'] = $result['complete_name'].' ('.$user['username'].')';
1659
    }
1660
1661
    $showEmail = api_get_setting('show_email_addresses') === 'true';
1662
    if (!empty($user['email'])) {
1663
        $result['complete_name_with_email_forced'] = $result['complete_name'].' ('.$user['email'].')';
1664
        if ($showEmail) {
1665
            $result['complete_name_with_email'] = $result['complete_name'].' ('.$user['email'].')';
1666
        }
1667
    } else {
1668
        $result['complete_name_with_email'] = $result['complete_name'];
1669
        $result['complete_name_with_email_forced'] = $result['complete_name'];
1670
    }
1671
1672
    // Kept for historical reasons
1673
    $result['firstName'] = $result['firstname'];
1674
    $result['lastName'] = $result['lastname'];
1675
1676
    $attributes = [
1677
        'phone',
1678
        'address',
1679
        'picture_uri',
1680
        'official_code',
1681
        'status',
1682
        'active',
1683
        'auth_source',
1684
        'username',
1685
        'theme',
1686
        'language',
1687
        'creator_id',
1688
        'registration_date',
1689
        'hr_dept_id',
1690
        'expiration_date',
1691
        'last_login',
1692
        'user_is_online',
1693
    ];
1694
1695
    if (api_get_setting('extended_profile') === 'true') {
1696
        $attributes[] = 'competences';
1697
        $attributes[] = 'diplomas';
1698
        $attributes[] = 'teach';
1699
        $attributes[] = 'openarea';
1700
    }
1701
1702
    foreach ($attributes as $attribute) {
1703
        $result[$attribute] = isset($user[$attribute]) ? $user[$attribute] : null;
1704
    }
1705
1706
    $user_id = (int) $user['user_id'];
1707
    // Maintain the user_id index for backwards compatibility
1708
    $result['user_id'] = $result['id'] = $user_id;
1709
1710
    $hasCertificates = Certificate::getCertificateByUser($user_id);
1711
    $result['has_certificates'] = 0;
1712
    if (!empty($hasCertificates)) {
1713
        $result['has_certificates'] = 1;
1714
    }
1715
1716
    $result['icon_status'] = '';
1717
    $result['icon_status_medium'] = '';
1718
1719
    $result['is_admin'] = UserManager::is_admin($user_id);
1720
1721
    // Getting user avatar.
1722
    if ($loadAvatars) {
1723
        $result['avatar'] = '';
1724
        $result['avatar_no_query'] = '';
1725
        $result['avatar_small'] = '';
1726
        $result['avatar_medium'] = '';
1727
1728
        if (!isset($user['avatar'])) {
1729
            $originalFile = UserManager::getUserPicture(
1730
                $user_id,
1731
                USER_IMAGE_SIZE_ORIGINAL,
1732
                null,
1733
                $result
1734
            );
1735
            $result['avatar'] = $originalFile;
1736
            $avatarString = explode('?', $result['avatar']);
1737
            $result['avatar_no_query'] = reset($avatarString);
1738
        } else {
1739
            $result['avatar'] = $user['avatar'];
1740
            $avatarString = explode('?', $user['avatar']);
1741
            $result['avatar_no_query'] = reset($avatarString);
1742
        }
1743
1744
        if (!isset($user['avatar_small'])) {
1745
            $smallFile = UserManager::getUserPicture(
1746
                $user_id,
1747
                USER_IMAGE_SIZE_SMALL,
1748
                null,
1749
                $result
1750
            );
1751
            $result['avatar_small'] = $smallFile;
1752
        } else {
1753
            $result['avatar_small'] = $user['avatar_small'];
1754
        }
1755
1756
        if (!isset($user['avatar_medium'])) {
1757
            $mediumFile = UserManager::getUserPicture(
1758
                $user_id,
1759
                USER_IMAGE_SIZE_MEDIUM,
1760
                null,
1761
                $result
1762
            );
1763
            $result['avatar_medium'] = $mediumFile;
1764
        } else {
1765
            $result['avatar_medium'] = $user['avatar_medium'];
1766
        }
1767
1768
        $urlImg = api_get_path(WEB_IMG_PATH);
1769
        $iconStatus = '';
1770
        $iconStatusMedium = '';
1771
        $label = '';
1772
        switch ($result['status']) {
1773
            case STUDENT:
1774
                if ($result['has_certificates']) {
1775
                    $iconStatus = $urlImg.'icons/svg/identifier_graduated.svg';
1776
                    $label = get_lang('Graduated');
1777
                } else {
1778
                    $iconStatus = $urlImg.'icons/svg/identifier_student.svg';
1779
                    $label = get_lang('Student');
1780
                }
1781
                break;
1782
            case COURSEMANAGER:
1783
                if ($result['is_admin']) {
1784
                    $iconStatus = $urlImg.'icons/svg/identifier_admin.svg';
1785
                    $label = get_lang('Admin');
1786
                } else {
1787
                    $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1788
                    $label = get_lang('Teacher');
1789
                }
1790
                break;
1791
            case STUDENT_BOSS:
1792
                $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1793
                $label = get_lang('StudentBoss');
1794
                break;
1795
        }
1796
1797
        if (!empty($iconStatus)) {
1798
            $iconStatusMedium = '<img src="'.$iconStatus.'" width="32px" height="32px">';
1799
            $iconStatus = '<img src="'.$iconStatus.'" width="22px" height="22px">';
1800
        }
1801
1802
        $result['icon_status'] = $iconStatus;
1803
        $result['icon_status_label'] = $label;
1804
        $result['icon_status_medium'] = $iconStatusMedium;
1805
    }
1806
1807
    if (isset($user['user_is_online'])) {
1808
        $result['user_is_online'] = $user['user_is_online'] == true ? 1 : 0;
1809
    }
1810
    if (isset($user['user_is_online_in_chat'])) {
1811
        $result['user_is_online_in_chat'] = (int) $user['user_is_online_in_chat'];
1812
    }
1813
1814
    if ($add_password) {
1815
        $result['password'] = $user['password'];
1816
    }
1817
1818
    if (isset($result['profile_completed'])) {
1819
        $result['profile_completed'] = $user['profile_completed'];
1820
    }
1821
1822
    $result['profile_url'] = api_get_path(WEB_CODE_PATH).'social/profile.php?u='.$user_id;
1823
1824
    // Send message link
1825
    $userIdHash = UserManager::generateUserHash($user_id);
1826
    $sendMessage = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&hash='.$userIdHash;
1827
    $result['complete_name_with_message_link'] = Display::url(
1828
        $result['complete_name_with_username'],
1829
        $sendMessage,
1830
        ['class' => 'ajax']
1831
    );
1832
1833
    if (isset($user['extra'])) {
1834
        $result['extra'] = $user['extra'];
1835
    }
1836
1837
    return $result;
1838
}
1839
1840
/**
1841
 * Finds all the information about a user.
1842
 * If no parameter is passed you find all the information about the current user.
1843
 *
1844
 * @param int  $user_id
1845
 * @param bool $checkIfUserOnline
1846
 * @param bool $showPassword
1847
 * @param bool $loadExtraData
1848
 * @param bool $loadOnlyVisibleExtraData Get the user extra fields that are visible
1849
 * @param bool $loadAvatars              turn off to improve performance and if avatars are not needed
1850
 * @param bool $updateCache              update apc cache if exists
1851
 *
1852
 * @return mixed $user_info user_id, lastname, firstname, username, email, etc or false on error
1853
 *
1854
 * @author Patrick Cool <[email protected]>
1855
 * @author Julio Montoya
1856
 *
1857
 * @version 21 September 2004
1858
 */
1859
function api_get_user_info(
1860
    $user_id = 0,
1861
    $checkIfUserOnline = false,
1862
    $showPassword = false,
1863
    $loadExtraData = false,
1864
    $loadOnlyVisibleExtraData = false,
1865
    $loadAvatars = true,
1866
    $updateCache = false
1867
) {
1868
    $apcVar = null;
1869
    $user = false;
1870
    $cacheAvailable = api_get_configuration_value('apc');
1871
1872
    if (empty($user_id)) {
1873
        $userFromSession = Session::read('_user');
1874
1875
        if (isset($userFromSession)) {
1876
            if ($cacheAvailable === true &&
1877
                (
1878
                    empty($userFromSession['is_anonymous']) &&
1879
                    (isset($userFromSession['status']) && $userFromSession['status'] != ANONYMOUS)
1880
                )
1881
            ) {
1882
                $apcVar = api_get_configuration_value('apc_prefix').'userinfo_'.$userFromSession['user_id'];
1883
                if (apcu_exists($apcVar)) {
1884
                    if ($updateCache) {
1885
                        apcu_store($apcVar, $userFromSession, 60);
1886
                    }
1887
                    $user = apcu_fetch($apcVar);
1888
                } else {
1889
                    $user = _api_format_user(
1890
                        $userFromSession,
1891
                        $showPassword,
1892
                        $loadAvatars
1893
                    );
1894
                    apcu_store($apcVar, $user, 60);
1895
                }
1896
            } else {
1897
                $user = _api_format_user(
1898
                    $userFromSession,
1899
                    $showPassword,
1900
                    $loadAvatars
1901
                );
1902
            }
1903
1904
            return $user;
1905
        }
1906
1907
        return false;
1908
    }
1909
1910
    // Make sure user_id is safe
1911
    $user_id = (int) $user_id;
1912
1913
    // Re-use user information if not stale and already stored in APCu
1914
    if ($cacheAvailable === true) {
1915
        $apcVar = api_get_configuration_value('apc_prefix').'userinfo_'.$user_id;
1916
        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...
1917
            $user = apcu_fetch($apcVar);
1918
1919
            return $user;
1920
        }
1921
    }
1922
1923
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1924
            WHERE id = $user_id";
1925
    $result = Database::query($sql);
1926
    if (Database::num_rows($result) > 0) {
1927
        $result_array = Database::fetch_array($result);
1928
        $result_array['user_is_online_in_chat'] = 0;
1929
        if ($checkIfUserOnline) {
1930
            $use_status_in_platform = user_is_online($user_id);
1931
            $result_array['user_is_online'] = $use_status_in_platform;
1932
            $user_online_in_chat = 0;
1933
            if ($use_status_in_platform) {
1934
                $user_status = UserManager::get_extra_user_data_by_field(
1935
                    $user_id,
1936
                    'user_chat_status',
1937
                    false,
1938
                    true
1939
                );
1940
                if ((int) $user_status['user_chat_status'] == 1) {
1941
                    $user_online_in_chat = 1;
1942
                }
1943
            }
1944
            $result_array['user_is_online_in_chat'] = $user_online_in_chat;
1945
        }
1946
1947
        if ($loadExtraData) {
1948
            $fieldValue = new ExtraFieldValue('user');
1949
            $result_array['extra'] = $fieldValue->getAllValuesForAnItem(
1950
                $user_id,
1951
                $loadOnlyVisibleExtraData
1952
            );
1953
        }
1954
        $user = _api_format_user($result_array, $showPassword, $loadAvatars);
1955
    }
1956
1957
    if ($cacheAvailable === true) {
1958
        apcu_store($apcVar, $user, 60);
1959
    }
1960
1961
    return $user;
1962
}
1963
1964
/**
1965
 * @param int $userId
1966
 *
1967
 * @return User
1968
 */
1969
function api_get_user_entity($userId)
1970
{
1971
    $userId = (int) $userId;
1972
    $repo = UserManager::getRepository();
1973
1974
    /** @var User $user */
1975
    $user = $repo->find($userId);
1976
1977
    return $user;
1978
}
1979
1980
/**
1981
 * Finds all the information about a user from username instead of user id.
1982
 *
1983
 * @param string $username
1984
 *
1985
 * @return mixed $user_info array user_id, lastname, firstname, username, email or false on error
1986
 *
1987
 * @author Yannick Warnier <[email protected]>
1988
 */
1989
function api_get_user_info_from_username($username, $authSource = null)
1990
{
1991
    if (empty($username)) {
1992
        return false;
1993
    }
1994
    $username = trim($username);
1995
1996
    $andAuthSource = "";
1997
    if (isset($authSource)) {
1998
        $authSource = Database::escape_string($authSource);
1999
        $andAuthSource = " AND auth_source = '$authSource'";
2000
    }
2001
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
2002
            WHERE username='".Database::escape_string($username)."' $andAuthSource";
2003
    $result = Database::query($sql);
2004
    if (Database::num_rows($result) > 0) {
2005
        $resultArray = Database::fetch_array($result);
2006
2007
        return _api_format_user($resultArray);
2008
    }
2009
2010
    return false;
2011
}
2012
2013
/**
2014
 * Get first user with an email.
2015
 *
2016
 * @param string $email
2017
 *
2018
 * @return array|bool
2019
 */
2020
function api_get_user_info_from_email($email = '')
2021
{
2022
    if (empty($email)) {
2023
        return false;
2024
    }
2025
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
2026
            WHERE email ='".Database::escape_string($email)."' LIMIT 1";
2027
    $result = Database::query($sql);
2028
    if (Database::num_rows($result) > 0) {
2029
        $resultArray = Database::fetch_array($result);
2030
2031
        return _api_format_user($resultArray);
2032
    }
2033
2034
    return false;
2035
}
2036
2037
/**
2038
 * @return string
2039
 */
2040
function api_get_course_id()
2041
{
2042
    return Session::read('_cid', null);
2043
}
2044
2045
/**
2046
 * Returns the current course id (integer).
2047
 *
2048
 * @param string $code Optional course code
2049
 *
2050
 * @return int
2051
 */
2052
function api_get_course_int_id($code = null)
2053
{
2054
    if (!empty($code)) {
2055
        $code = Database::escape_string($code);
2056
        $row = Database::select(
2057
            'id',
2058
            Database::get_main_table(TABLE_MAIN_COURSE),
2059
            ['where' => ['code = ?' => [$code]]],
2060
            'first'
2061
        );
2062
2063
        if (is_array($row) && isset($row['id'])) {
2064
            return $row['id'];
2065
        } else {
2066
            return false;
2067
        }
2068
    }
2069
2070
    return Session::read('_real_cid', 0);
2071
}
2072
2073
/**
2074
 * Returns the current course directory.
2075
 *
2076
 * This function relies on api_get_course_info()
2077
 *
2078
 * @param string    The course code - optional (takes it from session if not given)
2079
 *
2080
 * @return string The directory where the course is located inside the Chamilo "courses" directory
2081
 *
2082
 * @author Yannick Warnier <[email protected]>
2083
 */
2084
function api_get_course_path($course_code = null)
2085
{
2086
    $info = !empty($course_code) ? api_get_course_info($course_code) : api_get_course_info();
2087
2088
    return $info['path'];
2089
}
2090
2091
/**
2092
 * Gets a course setting from the current course_setting table. Try always using integer values.
2093
 *
2094
 * @param string $settingName The name of the setting we want from the table
2095
 * @param array  $courseInfo
2096
 * @param bool   $force       force checking the value in the database
2097
 *
2098
 * @return mixed The value of that setting in that table. Return -1 if not found.
2099
 */
2100
function api_get_course_setting($settingName, $courseInfo = [], $force = false)
2101
{
2102
    if (empty($courseInfo)) {
2103
        $courseInfo = api_get_course_info();
2104
    }
2105
2106
    if (empty($courseInfo) || empty($settingName)) {
2107
        return -1;
2108
    }
2109
2110
    $courseId = isset($courseInfo['real_id']) && !empty($courseInfo['real_id']) ? $courseInfo['real_id'] : 0;
2111
2112
    if (empty($courseId)) {
2113
        return -1;
2114
    }
2115
2116
    static $courseSettingInfo = [];
2117
2118
    if ($force) {
2119
        $courseSettingInfo = [];
2120
    }
2121
2122
    if (!isset($courseSettingInfo[$courseId])) {
2123
        $table = Database::get_course_table(TABLE_COURSE_SETTING);
2124
        $settingName = Database::escape_string($settingName);
2125
2126
        $sql = "SELECT variable, value FROM $table
2127
                WHERE c_id = $courseId ";
2128
        $res = Database::query($sql);
2129
        if (Database::num_rows($res) > 0) {
2130
            $result = Database::store_result($res, 'ASSOC');
2131
            $courseSettingInfo[$courseId] = array_column($result, 'value', 'variable');
2132
2133
            if (isset($courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'])) {
2134
                $value = $courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'];
2135
                if (!is_null($value)) {
2136
                    $result = explode(',', $value);
2137
                    $courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'] = $result;
2138
                }
2139
            }
2140
        }
2141
    }
2142
2143
    if (isset($courseSettingInfo[$courseId]) && array_key_exists($settingName, $courseSettingInfo[$courseId])) {
2144
        return $courseSettingInfo[$courseId][$settingName];
2145
    }
2146
2147
    return -1;
2148
}
2149
2150
function api_get_course_plugin_setting($plugin, $settingName, $courseInfo = [])
2151
{
2152
    $value = api_get_course_setting($settingName, $courseInfo, true);
2153
2154
    if (-1 === $value) {
2155
        // Check global settings
2156
        $value = api_get_plugin_setting($plugin, $settingName);
2157
        if ($value === 'true') {
2158
            return 1;
2159
        }
2160
        if ($value === 'false') {
2161
            return 0;
2162
        }
2163
        if (null === $value) {
2164
            return -1;
2165
        }
2166
    }
2167
2168
    return $value;
2169
}
2170
2171
/**
2172
 * Gets an anonymous user ID.
2173
 *
2174
 * For some tools that need tracking, like the learnpath tool, it is necessary
2175
 * to have a usable user-id to enable some kind of tracking, even if not
2176
 * perfect. An anonymous ID is taken from the users table by looking for a
2177
 * status of "6" (anonymous).
2178
 *
2179
 * @return int User ID of the anonymous user, or O if no anonymous user found
2180
 */
2181
function api_get_anonymous_id()
2182
{
2183
    // Find if another anon is connected now
2184
    $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
2185
    $tableU = Database::get_main_table(TABLE_MAIN_USER);
2186
    $ip = Database::escape_string(api_get_real_ip());
2187
    $max = (int) api_get_configuration_value('max_anonymous_users');
2188
    if ($max >= 2) {
2189
        $sql = "SELECT * FROM $table as TEL
2190
                JOIN $tableU as U
2191
                ON U.user_id = TEL.login_user_id
2192
                WHERE TEL.user_ip = '$ip'
2193
                    AND U.status = ".ANONYMOUS."
2194
                    AND U.user_id != 2 ";
2195
2196
        $result = Database::query($sql);
2197
        if (empty(Database::num_rows($result))) {
2198
            $login = uniqid('anon_');
2199
            $email = ' [email protected]';
2200
            if (api_get_setting('login_is_email') == 'true') {
2201
                $login = $login."@localhost.local";
2202
                $email = $login;
2203
            }
2204
            $anonList = UserManager::get_user_list(['status' => ANONYMOUS], ['registration_date ASC']);
2205
            if (count($anonList) >= $max) {
2206
                foreach ($anonList as $userToDelete) {
2207
                    UserManager::delete_user($userToDelete['user_id']);
2208
                    break;
2209
                }
2210
            }
2211
            // Return the user ID
2212
            return UserManager::create_user(
0 ignored issues
show
Bug Best Practice introduced by
The expression return UserManager::crea...$email, $login, $login) could also return false which is incompatible with the documented return type integer. Did you maybe forget to handle an error condition?

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

Loading history...
2213
                $login,
2214
                'anon',
2215
                ANONYMOUS,
2216
                $email,
2217
                $login,
2218
                $login
2219
            );
2220
        } else {
2221
            $row = Database::fetch_array($result, 'ASSOC');
2222
2223
            return $row['user_id'];
2224
        }
2225
    }
2226
2227
    $table = Database::get_main_table(TABLE_MAIN_USER);
2228
    $sql = "SELECT user_id
2229
            FROM $table
2230
            WHERE status = ".ANONYMOUS." ";
2231
    $res = Database::query($sql);
2232
    if (Database::num_rows($res) > 0) {
2233
        $row = Database::fetch_array($res, 'ASSOC');
2234
2235
        return $row['user_id'];
2236
    }
2237
2238
    // No anonymous user was found.
2239
    return 0;
2240
}
2241
2242
/**
2243
 * @param string $courseCode
2244
 * @param int    $sessionId
2245
 * @param int    $groupId
2246
 *
2247
 * @return string
2248
 */
2249
function api_get_cidreq_params($courseCode, $sessionId = 0, $groupId = 0)
2250
{
2251
    $courseCode = !empty($courseCode) ? htmlspecialchars($courseCode) : '';
2252
    $sessionId = !empty($sessionId) ? (int) $sessionId : 0;
2253
    $groupId = !empty($groupId) ? (int) $groupId : 0;
2254
2255
    $url = 'cidReq='.$courseCode;
2256
    $url .= '&id_session='.$sessionId;
2257
    $url .= '&gidReq='.$groupId;
2258
2259
    return $url;
2260
}
2261
2262
/**
2263
 * Returns the current course url part including session, group, and gradebook params.
2264
 *
2265
 * @param bool   $addSessionId
2266
 * @param bool   $addGroupId
2267
 * @param string $origin
2268
 *
2269
 * @return string Course & session references to add to a URL
2270
 */
2271
function api_get_cidreq($addSessionId = true, $addGroupId = true, $origin = '')
2272
{
2273
    $courseCode = api_get_course_id();
2274
    $url = empty($courseCode) ? '' : 'cidReq='.urlencode(htmlspecialchars($courseCode));
2275
    $origin = empty($origin) ? api_get_origin() : urlencode(Security::remove_XSS($origin));
2276
2277
    if ($addSessionId) {
2278
        if (!empty($url)) {
2279
            $url .= api_get_session_id() == 0 ? '&id_session=0' : '&id_session='.api_get_session_id();
2280
        }
2281
    }
2282
2283
    if ($addGroupId) {
2284
        if (!empty($url)) {
2285
            $url .= api_get_group_id() == 0 ? '&gidReq=0' : '&gidReq='.api_get_group_id();
2286
        }
2287
    }
2288
2289
    if (!empty($url)) {
2290
        $url .= '&gradebook='.intval(api_is_in_gradebook());
2291
        $url .= '&origin='.$origin;
2292
    }
2293
2294
    return $url;
2295
}
2296
2297
/**
2298
 * Get if we visited a gradebook page.
2299
 *
2300
 * @return bool
2301
 */
2302
function api_is_in_gradebook()
2303
{
2304
    return Session::read('in_gradebook', false);
2305
}
2306
2307
/**
2308
 * Set that we are in a page inside a gradebook.
2309
 */
2310
function api_set_in_gradebook()
2311
{
2312
    Session::write('in_gradebook', true);
2313
}
2314
2315
/**
2316
 * Remove gradebook session.
2317
 */
2318
function api_remove_in_gradebook()
2319
{
2320
    Session::erase('in_gradebook');
2321
}
2322
2323
/**
2324
 * Returns the current course info array see api_format_course_array()
2325
 * If the course_code is given, the returned array gives info about that
2326
 * particular course, if none given it gets the course info from the session.
2327
 *
2328
 * @param string $course_code
2329
 *
2330
 * @return array
2331
 */
2332
function api_get_course_info($course_code = null)
2333
{
2334
    if (!empty($course_code)) {
2335
        $course_code = Database::escape_string($course_code);
2336
        $courseId = api_get_course_int_id($course_code);
2337
2338
        if (empty($courseId)) {
2339
            return [];
2340
        }
2341
2342
        $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
2343
        $course_cat_table = Database::get_main_table(TABLE_MAIN_CATEGORY);
2344
        $sql = "SELECT
2345
                    course.*,
2346
                    course_category.code faCode,
2347
                    course_category.name faName
2348
                FROM $course_table
2349
                LEFT JOIN $course_cat_table
2350
                ON course.category_code = course_category.code
2351
                WHERE course.id = $courseId";
2352
        $result = Database::query($sql);
2353
        $courseInfo = [];
2354
        if (Database::num_rows($result) > 0) {
2355
            $data = Database::fetch_array($result);
2356
            $courseInfo = api_format_course_array($data);
2357
        }
2358
2359
        return $courseInfo;
2360
    }
2361
2362
    global $_course;
2363
    if ($_course == '-1') {
2364
        $_course = [];
2365
    }
2366
2367
    return $_course;
2368
}
2369
2370
/**
2371
 * @param int $courseId
2372
 *
2373
 * @return \Chamilo\CoreBundle\Entity\Course
2374
 */
2375
function api_get_course_entity($courseId = 0)
2376
{
2377
    if (empty($courseId)) {
2378
        $courseId = api_get_course_int_id();
2379
    }
2380
2381
    return Database::getManager()->getRepository('ChamiloCoreBundle:Course')->find($courseId);
2382
}
2383
2384
function api_get_group_entity($id = 0)
2385
{
2386
    if (empty($id)) {
2387
        $id = api_get_group_id();
2388
    }
2389
2390
    return Database::getManager()->getRepository('ChamiloCourseBundle:CGroupInfo')->find($id);
2391
}
2392
2393
/**
2394
 * @param int $id
2395
 *
2396
 * @return \Chamilo\CoreBundle\Entity\Session
2397
 */
2398
function api_get_session_entity($id = 0)
2399
{
2400
    if (empty($id)) {
2401
        $id = api_get_session_id();
2402
    }
2403
2404
    return Database::getManager()->getRepository('ChamiloCoreBundle:Session')->find($id);
2405
}
2406
2407
/**
2408
 * Returns the current course info array.
2409
2410
 * Now if the course_code is given, the returned array gives info about that
2411
 * particular course, not specially the current one.
2412
 *
2413
 * @param int $id Numeric ID of the course
2414
 *
2415
 * @return array The course info as an array formatted by api_format_course_array, including category.name
2416
 */
2417
function api_get_course_info_by_id($id = null)
2418
{
2419
    if (!empty($id)) {
2420
        $id = (int) $id;
2421
        $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
2422
        $course_cat_table = Database::get_main_table(TABLE_MAIN_CATEGORY);
2423
        $sql = "SELECT
2424
                    course.*,
2425
                    course_category.code faCode,
2426
                    course_category.name faName
2427
                FROM $course_table
2428
                LEFT JOIN $course_cat_table
2429
                ON course.category_code = course_category.code
2430
                WHERE course.id = $id";
2431
        $result = Database::query($sql);
2432
        $_course = [];
2433
        if (Database::num_rows($result) > 0) {
2434
            $row = Database::fetch_array($result);
2435
            $_course = api_format_course_array($row);
2436
        }
2437
2438
        return $_course;
2439
    }
2440
2441
    global $_course;
2442
    if ($_course == '-1') {
2443
        $_course = [];
2444
    }
2445
2446
    return $_course;
2447
}
2448
2449
/**
2450
 * Reformat the course array (output by api_get_course_info()) in order, mostly,
2451
 * to switch from 'code' to 'id' in the array. This is a legacy feature and is
2452
 * now possibly causing massive confusion as a new "id" field has been added to
2453
 * the course table in 1.9.0.
2454
 *
2455
 * @param $course_data
2456
 *
2457
 * @return array
2458
 *
2459
 * @todo eradicate the false "id"=code field of the $_course array and use the int id
2460
 */
2461
function api_format_course_array($course_data)
2462
{
2463
    if (empty($course_data)) {
2464
        return [];
2465
    }
2466
2467
    $_course = [];
2468
    $_course['id'] = $course_data['code'];
2469
    $_course['real_id'] = $course_data['id'];
2470
2471
    // Added
2472
    $_course['code'] = $course_data['code'];
2473
    $_course['name'] = $course_data['title'];
2474
    $_course['title'] = $course_data['title'];
2475
    $_course['official_code'] = $course_data['visual_code'];
2476
    $_course['visual_code'] = $course_data['visual_code'];
2477
    $_course['sysCode'] = $course_data['code'];
2478
    $_course['path'] = $course_data['directory']; // Use as key in path.
2479
    $_course['directory'] = $course_data['directory'];
2480
    $_course['creation_date'] = $course_data['creation_date'];
2481
    $_course['titular'] = $course_data['tutor_name'];
2482
    $_course['tutor_name'] = $course_data['tutor_name'];
2483
    $_course['language'] = $course_data['course_language'];
2484
    $_course['extLink']['url'] = $course_data['department_url'];
2485
    $_course['extLink']['name'] = $course_data['department_name'];
2486
    $_course['categoryCode'] = $course_data['faCode'];
2487
    $_course['category_code'] = $course_data['faCode'];
2488
    $_course['categoryName'] = $course_data['faName'];
2489
    $_course['visibility'] = $course_data['visibility'];
2490
    $_course['subscribe_allowed'] = $course_data['subscribe'];
2491
    $_course['subscribe'] = $course_data['subscribe'];
2492
    $_course['unsubscribe'] = $course_data['unsubscribe'];
2493
    $_course['course_language'] = $course_data['course_language'];
2494
    $_course['activate_legal'] = isset($course_data['activate_legal']) ? $course_data['activate_legal'] : false;
2495
    $_course['legal'] = $course_data['legal'];
2496
    $_course['show_score'] = $course_data['show_score']; //used in the work tool
2497
    $_course['department_name'] = $course_data['department_name'];
2498
    $_course['department_url'] = $course_data['department_url'];
2499
2500
    $courseSys = api_get_path(SYS_COURSE_PATH).$course_data['directory'];
2501
    $webCourseHome = api_get_path(WEB_COURSE_PATH).$course_data['directory'];
2502
2503
    // Course password
2504
    $_course['registration_code'] = !empty($course_data['registration_code']) ? sha1($course_data['registration_code']) : null;
2505
    $_course['disk_quota'] = $course_data['disk_quota'];
2506
    $_course['course_public_url'] = $webCourseHome.'/index.php';
2507
    $_course['course_sys_path'] = $courseSys.'/';
2508
2509
    if (array_key_exists('add_teachers_to_sessions_courses', $course_data)) {
2510
        $_course['add_teachers_to_sessions_courses'] = $course_data['add_teachers_to_sessions_courses'];
2511
    }
2512
2513
    // Course image
2514
    $_course['course_image_source'] = '';
2515
    if (file_exists($courseSys.'/course-pic85x85.png')) {
2516
        $url_image = $webCourseHome.'/course-pic85x85.png';
2517
        $_course['course_image_source'] = $courseSys.'/course-pic85x85.png';
2518
    } else {
2519
        $url_image = Display::return_icon(
2520
            'course.png',
2521
            null,
2522
            null,
2523
            ICON_SIZE_LARGE,
2524
            null,
2525
            true,
2526
            true
2527
        );
2528
    }
2529
    $_course['course_image'] = $url_image;
2530
2531
    // Course large image
2532
    $_course['course_image_large_source'] = '';
2533
    if (file_exists($courseSys.'/course-pic.png')) {
2534
        $url_image = $webCourseHome.'/course-pic.png';
2535
        $_course['course_image_large_source'] = $courseSys.'/course-pic.png';
2536
    } else {
2537
        $url_image = Display::return_icon(
2538
            'session_default.png',
2539
            null,
2540
            null,
2541
            null,
2542
            null,
2543
            true,
2544
            true
2545
        );
2546
    }
2547
2548
    $_course['course_image_large'] = $url_image;
2549
2550
    // email pictures
2551
    // Course image
2552
    $url_image = null;
2553
    $_course['course_email_image_source'] = '';
2554
    $mailPicture = $courseSys.'/course-email-pic-cropped.png';
2555
    if (file_exists($mailPicture)) {
2556
        $url_image = $webCourseHome.'/course-email-pic-cropped.png';
2557
        $_course['course_email_image_source'] = $mailPicture;
2558
    }
2559
    $_course['course_email_image'] = $url_image;
2560
2561
    // Course large image
2562
    $url_image = null;
2563
    $_course['course_email_image_large_source'] = '';
2564
    $mailPicture = $courseSys.'/course-email-pic.png';
2565
    if (file_exists($mailPicture)) {
2566
        $url_image = $webCourseHome.'/course-email-pic.png';
2567
        $_course['course_email_image_large_source'] = $mailPicture;
2568
    }
2569
2570
    $_course['course_email_image_large'] = $url_image;
2571
2572
    return $_course;
2573
}
2574
2575
/**
2576
 * Returns a difficult to guess password.
2577
 *
2578
 * @param int $length the length of the password
2579
 *
2580
 * @return string the generated password
2581
 */
2582
function api_generate_password($length = 8)
2583
{
2584
    if ($length < 2) {
2585
        $length = 2;
2586
    }
2587
2588
    $charactersLowerCase = Security::CHAR_LOWER;
2589
    $charactersUpperCase = Security::CHAR_UPPER;
2590
2591
    $minNumbers = 2;
2592
    $length = $length - $minNumbers;
2593
    $minLowerCase = round($length / 2);
2594
    $minUpperCase = $length - $minLowerCase;
2595
2596
    $password = '';
2597
    $passwordRequirements = api_get_configuration_value('password_requirements');
2598
2599
    $factory = new RandomLib\Factory();
2600
    $generator = $factory->getMediumStrengthGenerator();
2601
2602
    if (!empty($passwordRequirements)) {
2603
        $length = $passwordRequirements['min']['length'];
2604
        $minNumbers = $passwordRequirements['min']['numeric'];
2605
        $minLowerCase = $passwordRequirements['min']['lowercase'];
2606
        $minUpperCase = $passwordRequirements['min']['uppercase'];
2607
        $minSpecials = $passwordRequirements['min']['specials'];
2608
2609
        $rest = $length - $minNumbers - $minLowerCase - $minUpperCase - $minSpecials;
2610
        // Add the rest to fill the length requirement
2611
        if ($rest > 0) {
2612
            $password .= $generator->generateString(
2613
                $rest,
2614
                $charactersLowerCase.$charactersUpperCase
2615
            );
2616
        }
2617
2618
        $password .= $generator->generateString($minSpecials, Security::CHAR_SYMBOLS);
2619
    }
2620
2621
    // Min digits default 2
2622
    for ($i = 0; $i < $minNumbers; $i++) {
2623
        $password .= $generator->generateInt(2, 9);
2624
    }
2625
2626
    // Min lowercase
2627
    $password .= $generator->generateString($minLowerCase, $charactersLowerCase);
2628
2629
    // Min uppercase
2630
    $password .= $generator->generateString($minUpperCase, $charactersUpperCase);
2631
    $password = str_shuffle($password);
2632
2633
    return $password;
2634
}
2635
2636
/**
2637
 * Checks a password to see wether it is OK to use.
2638
 *
2639
 * @param string $password
2640
 *
2641
 * @return bool if the password is acceptable, false otherwise
2642
 *              Notes about what a password "OK to use" is:
2643
 *              1. The password should be at least 5 characters long.
2644
 *              2. Only English letters (uppercase or lowercase, it doesn't matter) and digits are allowed.
2645
 *              3. The password should contain at least 3 letters.
2646
 *              4. It should contain at least 2 digits.
2647
 *              Settings will change if the configuration value is set: password_requirements
2648
 */
2649
function api_check_password($password)
2650
{
2651
    $passwordRequirements = Security::getPasswordRequirements();
2652
2653
    $minLength = $passwordRequirements['min']['length'];
2654
    $minNumbers = $passwordRequirements['min']['numeric'];
2655
    // Optional
2656
    $minLowerCase = $passwordRequirements['min']['lowercase'];
2657
    $minUpperCase = $passwordRequirements['min']['uppercase'];
2658
    $minSpecials = $passwordRequirements['min']['specials'];
2659
2660
    $minLetters = $minLowerCase + $minUpperCase;
2661
    $passwordLength = api_strlen($password);
2662
2663
    $conditions = [
2664
        'min_length' => $passwordLength >= $minLength,
2665
    ];
2666
2667
    $digits = 0;
2668
    $lowerCase = 0;
2669
    $upperCase = 0;
2670
    $specials = 0;
2671
2672
    for ($i = 0; $i < $passwordLength; $i++) {
2673
        $currentCharacter = api_substr($password, $i, 1);
2674
        $currentCharacterCode = api_ord($currentCharacter);
2675
        if ($currentCharacterCode >= 65 && $currentCharacterCode <= 90) {
2676
            $upperCase++;
2677
        }
2678
2679
        if ($currentCharacterCode >= 97 && $currentCharacterCode <= 122) {
2680
            $lowerCase++;
2681
        }
2682
        if ($currentCharacterCode >= 48 && $currentCharacterCode <= 57) {
2683
            $digits++;
2684
        }
2685
2686
        if (false !== strpos(Security::CHAR_SYMBOLS, $currentCharacter)) {
2687
            $specials++;
2688
        }
2689
    }
2690
2691
    // Min number of digits
2692
    $conditions['min_numeric'] = $digits >= $minNumbers;
2693
2694
    if (!empty($minUpperCase)) {
2695
        // Uppercase
2696
        $conditions['min_uppercase'] = $upperCase >= $minUpperCase;
2697
    }
2698
2699
    if (!empty($minLowerCase)) {
2700
        // Lowercase
2701
        $conditions['min_lowercase'] = $lowerCase >= $minLowerCase;
2702
    }
2703
2704
    if (!empty($minSpecials)) {
2705
        $conditions['min_specials'] = $specials >= $minSpecials;
2706
    }
2707
2708
    // Min letters
2709
    $letters = $upperCase + $lowerCase;
2710
    $conditions['min_letters'] = $letters >= $minLetters;
2711
2712
    $isPasswordOk = true;
2713
    foreach ($conditions as $condition) {
2714
        if ($condition === false) {
2715
            $isPasswordOk = false;
2716
            break;
2717
        }
2718
    }
2719
2720
    if ($isPasswordOk === false) {
2721
        $output = get_lang('NewPasswordRequirementsNotMatched').'<br />';
2722
        $output .= Security::getPasswordRequirementsToString($conditions);
2723
2724
        Display::addFlash(Display::return_message($output, 'warning', false));
2725
    }
2726
2727
    return $isPasswordOk;
2728
}
2729
2730
/**
2731
 * Clears the user ID from the session if it was the anonymous user. Generally
2732
 * used on out-of-tools pages to remove a user ID that could otherwise be used
2733
 * in the wrong context.
2734
 * This function is to be used in conjunction with the api_set_anonymous()
2735
 * function to simulate the user existence in case of an anonymous visit.
2736
 *
2737
 * @param bool      database check switch - passed to api_is_anonymous()
2738
 *
2739
 * @return bool true if succesfully unregistered, false if not anonymous
2740
 */
2741
function api_clear_anonymous($db_check = false)
2742
{
2743
    global $_user;
2744
    if (isset($_user['user_id']) && api_is_anonymous($_user['user_id'], $db_check)) {
2745
        unset($_user['user_id']);
2746
        Session::erase('_uid');
2747
2748
        return true;
2749
    }
2750
2751
    return false;
2752
}
2753
2754
/**
2755
 * Returns the status string corresponding to the status code.
2756
 *
2757
 * @author Noel Dieschburg
2758
 *
2759
 * @param int $status_code The integer status code (usually in the form of a constant)
2760
 *
2761
 * @return string
2762
 */
2763
function get_status_from_code($status_code)
2764
{
2765
    switch ($status_code) {
2766
        case STUDENT:
2767
            return get_lang('Student', '');
2768
        case COURSEMANAGER:
2769
            return get_lang('Teacher', '');
2770
        case SESSIONADMIN:
2771
            return get_lang('SessionsAdmin', '');
2772
        case DRH:
2773
            return get_lang('Drh', '');
2774
        case ANONYMOUS:
2775
            return get_lang('Anonymous', '');
2776
        case PLATFORM_ADMIN:
2777
            return get_lang('Administrator', '');
2778
        case SESSION_COURSE_COACH:
2779
            return get_lang('SessionCourseCoach', '');
2780
        case SESSION_GENERAL_COACH:
2781
            return get_lang('SessionGeneralCoach', '');
2782
        case COURSE_TUTOR:
2783
            return get_lang('CourseAssistant', '');
2784
        case STUDENT_BOSS:
2785
            return get_lang('StudentBoss', '');
2786
        case INVITEE:
2787
            return get_lang('Invitee', '');
2788
    }
2789
2790
    return '';
2791
}
2792
2793
/**
2794
 * Sets the current user as anonymous if it hasn't been identified yet. This
2795
 * function should be used inside a tool only. The function api_clear_anonymous()
2796
 * acts in the opposite direction by clearing the anonymous user's data every
2797
 * time we get on a course homepage or on a neutral page (index, admin, my space).
2798
 *
2799
 * @return bool true if set user as anonymous, false if user was already logged in or anonymous id could not be found
2800
 */
2801
function api_set_anonymous()
2802
{
2803
    global $_user;
2804
2805
    if (!empty($_user['user_id'])) {
2806
        return false;
2807
    }
2808
2809
    $user_id = api_get_anonymous_id();
2810
    if ($user_id == 0) {
2811
        return false;
2812
    }
2813
2814
    if (isset($_user['is_anonymous'])) {
2815
        return false;
2816
    }
2817
2818
    Session::erase('_user');
2819
    $_user['user_id'] = $user_id;
2820
    $_user['is_anonymous'] = true;
2821
    $GLOBALS['_user'] = $_user;
2822
    Session::write('_user', $_user);
2823
2824
    return true;
2825
}
2826
2827
/**
2828
 * Gets the current Chamilo (not PHP/cookie) session ID.
2829
 *
2830
 * @return int O if no active session, the session ID otherwise
2831
 */
2832
function api_get_session_id()
2833
{
2834
    return (int) Session::read('id_session', 0);
2835
}
2836
2837
/**
2838
 * Gets the current Chamilo (not social network) group ID.
2839
 *
2840
 * @return int O if no active group, the group id otherwise
2841
 */
2842
function api_get_group_id()
2843
{
2844
    return (int) Session::read('_gid', 0);
2845
}
2846
2847
/**
2848
 * Gets the current or given session name.
2849
 *
2850
 * @param   int     Session ID (optional)
2851
 *
2852
 * @return string The session name, or null if not found
2853
 */
2854
function api_get_session_name($session_id = 0)
2855
{
2856
    if (empty($session_id)) {
2857
        $session_id = api_get_session_id();
2858
        if (empty($session_id)) {
2859
            return null;
2860
        }
2861
    }
2862
    $t = Database::get_main_table(TABLE_MAIN_SESSION);
2863
    $s = "SELECT name FROM $t WHERE id = ".(int) $session_id;
2864
    $r = Database::query($s);
2865
    $c = Database::num_rows($r);
2866
    if ($c > 0) {
2867
        //technically, there can be only one, but anyway we take the first
2868
        $rec = Database::fetch_array($r);
2869
2870
        return $rec['name'];
2871
    }
2872
2873
    return null;
2874
}
2875
2876
/**
2877
 * Gets the session info by id.
2878
 *
2879
 * @param int $id Session ID
2880
 *
2881
 * @return array information of the session
2882
 */
2883
function api_get_session_info($id)
2884
{
2885
    return SessionManager::fetch($id);
2886
}
2887
2888
/**
2889
 * Gets the session visibility by session id.
2890
 *
2891
 * @param int  $session_id
2892
 * @param int  $courseId
2893
 * @param bool $ignore_visibility_for_admins
2894
 * @param int  $userId
2895
 *
2896
 * @return int
2897
 *             0 = session still available,
2898
 *             SESSION_VISIBLE_READ_ONLY = 1,
2899
 *             SESSION_VISIBLE = 2,
2900
 *             SESSION_INVISIBLE = 3
2901
 */
2902
function api_get_session_visibility(
2903
    $session_id,
2904
    $courseId = null,
2905
    $ignore_visibility_for_admins = true,
2906
    $userId = 0
2907
) {
2908
    if (api_is_platform_admin()) {
2909
        if ($ignore_visibility_for_admins) {
2910
            return SESSION_AVAILABLE;
2911
        }
2912
    }
2913
2914
    $userId = empty($userId) ? api_get_user_id() : (int) $userId;
2915
2916
    $now = time();
2917
    if (empty($session_id)) {
2918
        return 0; // Means that the session is still available.
2919
    }
2920
2921
    $session_id = (int) $session_id;
2922
    $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
2923
2924
    $result = Database::query("SELECT * FROM $tbl_session WHERE id = $session_id");
2925
2926
    if (Database::num_rows($result) <= 0) {
2927
        return SESSION_INVISIBLE;
2928
    }
2929
2930
    $row = Database::fetch_array($result, 'ASSOC');
2931
    $visibility = $row['visibility'];
2932
2933
    // I don't care the session visibility.
2934
    if (empty($row['access_start_date']) && empty($row['access_end_date'])) {
2935
2936
        // Session duration per student.
2937
        if (isset($row['duration']) && !empty($row['duration'])) {
2938
            if (api_get_configuration_value('session_coach_access_after_duration_end') == true && api_is_teacher()) {
2939
                return SESSION_AVAILABLE;
2940
            }
2941
2942
            $duration = $row['duration'] * 24 * 60 * 60;
2943
            $courseAccess = CourseManager::getFirstCourseAccessPerSessionAndUser($session_id, $userId);
2944
2945
            // If there is a session duration but there is no previous
2946
            // access by the user, then the session is still available
2947
            if (0 == count($courseAccess)) {
2948
                return SESSION_AVAILABLE;
2949
            }
2950
2951
            $currentTime = time();
2952
            $firstAccess = isset($courseAccess['login_course_date'])
2953
                ? api_strtotime($courseAccess['login_course_date'], 'UTC')
2954
                : 0;
2955
            $userDurationData = SessionManager::getUserSession($userId, $session_id);
2956
            $userDuration = isset($userDurationData['duration'])
2957
                ? (intval($userDurationData['duration']) * 24 * 60 * 60)
2958
                : 0;
2959
2960
            $totalDuration = $firstAccess + $duration + $userDuration;
2961
2962
            return $totalDuration > $currentTime ? SESSION_AVAILABLE : $visibility;
2963
        }
2964
2965
        return SESSION_AVAILABLE;
2966
    }
2967
2968
    // If start date was set.
2969
    if (!empty($row['access_start_date'])) {
2970
        $visibility = $now > api_strtotime($row['access_start_date'], 'UTC') ? SESSION_AVAILABLE : SESSION_INVISIBLE;
2971
    }
2972
2973
    // If the end date was set.
2974
    if (!empty($row['access_end_date'])) {
2975
        // Only if date_start said that it was ok
2976
        if ($visibility === SESSION_AVAILABLE) {
2977
            $visibility = $now < api_strtotime($row['access_end_date'], 'UTC')
2978
                ? SESSION_AVAILABLE // Date still available
2979
                : $row['visibility']; // Session ends
2980
        }
2981
    }
2982
2983
    // If I'm a coach the visibility can change in my favor depending in the coach dates.
2984
    $isCoach = api_is_coach($session_id, $courseId, $userId);
2985
2986
    if ($isCoach) {
2987
        // Test start date.
2988
        if (!empty($row['coach_access_start_date'])) {
2989
            $start = api_strtotime($row['coach_access_start_date'], 'UTC');
2990
            $visibility = $start < $now ? SESSION_AVAILABLE : SESSION_INVISIBLE;
2991
        }
2992
2993
        // Test end date.
2994
        if (!empty($row['coach_access_end_date'])) {
2995
            if ($visibility === SESSION_AVAILABLE) {
2996
                $endDateCoach = api_strtotime($row['coach_access_end_date'], 'UTC');
2997
                $visibility = $endDateCoach >= $now ? SESSION_AVAILABLE : $row['visibility'];
2998
            }
2999
        }
3000
    }
3001
3002
    return $visibility;
3003
}
3004
3005
/**
3006
 * This function returns a (star) session icon if the session is not null and
3007
 * the user is not a student.
3008
 *
3009
 * @param int $sessionId
3010
 * @param int $statusId  User status id - if 5 (student) or in student view, will return empty
3011
 *
3012
 * @return string Session icon
3013
 */
3014
function api_get_session_image($sessionId, $statusId)
3015
{
3016
    $sessionId = (int) $sessionId;
3017
    $image = '';
3018
    $studentView = !empty($_SESSION['studentview']) && $_SESSION['studentview'] == 'studentview';
3019
    if ($statusId != STUDENT && !$studentView) {
3020
        // Check whether is not a student
3021
        if ($sessionId > 0) {
3022
            $image = '&nbsp;&nbsp;'.Display::return_icon(
3023
                'star.png',
3024
                get_lang('SessionSpecificResource'),
3025
                ['align' => 'absmiddle'],
3026
                ICON_SIZE_SMALL
3027
            );
3028
        }
3029
    }
3030
3031
    return $image;
3032
}
3033
3034
/**
3035
 * This function add an additional condition according to the session of the course.
3036
 *
3037
 * @param int    $session_id        session id
3038
 * @param bool   $and               optional, true if more than one condition false if the only condition in the query
3039
 * @param bool   $with_base_content optional, true to accept content with session=0 as well,
3040
 *                                  false for strict session condition
3041
 * @param string $session_field
3042
 *
3043
 * @return string condition of the session
3044
 */
3045
function api_get_session_condition(
3046
    $session_id,
3047
    $and = true,
3048
    $with_base_content = false,
3049
    $session_field = 'session_id'
3050
) {
3051
    $session_id = (int) $session_id;
3052
3053
    if (empty($session_field)) {
3054
        $session_field = 'session_id';
3055
    }
3056
    // Condition to show resources by session
3057
    $condition_add = $and ? ' AND ' : ' WHERE ';
3058
3059
    if ($with_base_content) {
3060
        $condition_session = $condition_add." ( $session_field = $session_id OR $session_field = 0 OR $session_field IS NULL) ";
3061
    } else {
3062
        if (empty($session_id)) {
3063
            $condition_session = $condition_add." ($session_field = $session_id OR $session_field IS NULL)";
3064
        } else {
3065
            $condition_session = $condition_add." $session_field = $session_id ";
3066
        }
3067
    }
3068
3069
    return $condition_session;
3070
}
3071
3072
/**
3073
 * Returns the value of a setting from the web-adjustable admin config settings.
3074
 *
3075
 * WARNING true/false are stored as string, so when comparing you need to check e.g.
3076
 * if (api_get_setting('show_navigation_menu') == 'true') //CORRECT
3077
 * instead of
3078
 * if (api_get_setting('show_navigation_menu') == true) //INCORRECT
3079
 *
3080
 * @param string $variable The variable name
3081
 * @param string $key      The subkey (sub-variable) if any. Defaults to NULL
3082
 *
3083
 * @return string
3084
 *
3085
 * @author René Haentjens
3086
 * @author Bart Mollet
3087
 */
3088
function api_get_setting($variable, $key = null)
3089
{
3090
    global $_setting;
3091
    if ($variable == 'header_extra_content') {
3092
        $filename = api_get_home_path().'header_extra_content.txt';
3093
        if (file_exists($filename)) {
3094
            $value = file_get_contents($filename);
3095
3096
            return $value;
3097
        } else {
3098
            return '';
3099
        }
3100
    }
3101
    if ($variable == 'footer_extra_content') {
3102
        $filename = api_get_home_path().'footer_extra_content.txt';
3103
        if (file_exists($filename)) {
3104
            $value = file_get_contents($filename);
3105
3106
            return $value;
3107
        } else {
3108
            return '';
3109
        }
3110
    }
3111
    $value = null;
3112
    if (is_null($key)) {
3113
        $value = ((isset($_setting[$variable]) && $_setting[$variable] != '') ? $_setting[$variable] : null);
3114
    } else {
3115
        if (isset($_setting[$variable][$key])) {
3116
            $value = $_setting[$variable][$key];
3117
        }
3118
    }
3119
3120
    return $value;
3121
}
3122
3123
/**
3124
 * @param string $plugin
3125
 * @param string $variable
3126
 *
3127
 * @return string
3128
 */
3129
function api_get_plugin_setting($plugin, $variable)
3130
{
3131
    $settings = api_get_configuration_value('plugin_settings');
3132
3133
    if (!empty($settings) && isset($settings[$plugin]) && isset($settings[$plugin][$variable])) {
3134
        return $settings[$plugin][$variable];
3135
    }
3136
3137
    $variableName = $plugin.'_'.$variable;
3138
    $result = api_get_setting($variableName);
3139
3140
    if (isset($result[$plugin])) {
3141
        $value = $result[$plugin];
3142
        $unSerialized = UnserializeApi::unserialize('not_allowed_classes', $value, true);
3143
3144
        if (false !== $unSerialized) {
3145
            $value = $unSerialized;
3146
        }
3147
3148
        return $value;
3149
    }
3150
3151
    return null;
3152
}
3153
3154
/**
3155
 * Returns the value of a setting from the web-adjustable admin config settings.
3156
 */
3157
function api_get_settings_params($params)
3158
{
3159
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
3160
3161
    return Database::select('*', $table, ['where' => $params]);
3162
}
3163
3164
/**
3165
 * @param array $params example: [id = ? => '1']
3166
 *
3167
 * @return array
3168
 */
3169
function api_get_settings_params_simple($params)
3170
{
3171
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
3172
3173
    return Database::select('*', $table, ['where' => $params], 'one');
3174
}
3175
3176
/**
3177
 * Returns the value of a setting from the web-adjustable admin config settings.
3178
 */
3179
function api_delete_settings_params($params)
3180
{
3181
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
3182
    $result = Database::delete($table, $params);
3183
3184
    return $result;
3185
}
3186
3187
/**
3188
 * Returns an escaped version of $_SERVER['PHP_SELF'] to avoid XSS injection.
3189
 *
3190
 * @return string Escaped version of $_SERVER['PHP_SELF']
3191
 */
3192
function api_get_self()
3193
{
3194
    return htmlentities($_SERVER['PHP_SELF']);
3195
}
3196
3197
/* USER PERMISSIONS */
3198
3199
/**
3200
 * Checks whether current user is a platform administrator.
3201
 *
3202
 * @param bool $allowSessionAdmins Whether session admins should be considered admins or not
3203
 * @param bool $allowDrh           Whether HR directors should be considered admins or not
3204
 *
3205
 * @return bool true if the user has platform admin rights,
3206
 *              false otherwise
3207
 *
3208
 * @see usermanager::is_admin(user_id) for a user-id specific function
3209
 */
3210
function api_is_platform_admin($allowSessionAdmins = false, $allowDrh = false)
3211
{
3212
    $isAdmin = Session::read('is_platformAdmin');
3213
    if ($isAdmin) {
3214
        return true;
3215
    }
3216
    $user = api_get_user_info();
3217
3218
    return
3219
        isset($user['status']) &&
3220
        (
3221
            ($allowSessionAdmins && $user['status'] == SESSIONADMIN) ||
3222
            ($allowDrh && $user['status'] == DRH)
3223
        );
3224
}
3225
3226
/**
3227
 * Checks whether the user given as user id is in the admin table.
3228
 *
3229
 * @param int $user_id If none provided, will use current user
3230
 * @param int $url     URL ID. If provided, also check if the user is active on given URL
3231
 *
3232
 * @return bool True if the user is admin, false otherwise
3233
 */
3234
function api_is_platform_admin_by_id($user_id = null, $url = null)
3235
{
3236
    $user_id = (int) $user_id;
3237
    if (empty($user_id)) {
3238
        $user_id = api_get_user_id();
3239
    }
3240
    $admin_table = Database::get_main_table(TABLE_MAIN_ADMIN);
3241
    $sql = "SELECT * FROM $admin_table WHERE user_id = $user_id";
3242
    $res = Database::query($sql);
3243
    $is_admin = Database::num_rows($res) === 1;
3244
    if (!$is_admin || !isset($url)) {
3245
        return $is_admin;
3246
    }
3247
    // We get here only if $url is set
3248
    $url = (int) $url;
3249
    $url_user_table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
3250
    $sql = "SELECT * FROM $url_user_table
3251
            WHERE access_url_id = $url AND user_id = $user_id";
3252
    $res = Database::query($sql);
3253
    $result = Database::num_rows($res) === 1;
3254
3255
    return $result;
3256
}
3257
3258
/**
3259
 * Returns the user's numeric status ID from the users table.
3260
 *
3261
 * @param int $user_id If none provided, will use current user
3262
 *
3263
 * @return int User's status (1 for teacher, 5 for student, etc)
3264
 */
3265
function api_get_user_status($user_id = null)
3266
{
3267
    $user_id = (int) $user_id;
3268
    if (empty($user_id)) {
3269
        $user_id = api_get_user_id();
3270
    }
3271
    $table = Database::get_main_table(TABLE_MAIN_USER);
3272
    $sql = "SELECT status FROM $table WHERE user_id = $user_id ";
3273
    $result = Database::query($sql);
3274
    $status = null;
3275
    if (Database::num_rows($result)) {
3276
        $row = Database::fetch_array($result);
3277
        $status = $row['status'];
3278
    }
3279
3280
    return $status;
3281
}
3282
3283
/**
3284
 * Checks whether current user is allowed to create courses.
3285
 *
3286
 * @return bool true if the user has course creation rights,
3287
 *              false otherwise
3288
 */
3289
function api_is_allowed_to_create_course()
3290
{
3291
    if (api_is_platform_admin()) {
3292
        return true;
3293
    }
3294
3295
    // Teachers can only create courses
3296
    if (api_is_teacher()) {
3297
        if (api_get_setting('allow_users_to_create_courses') === 'true') {
3298
            return true;
3299
        } else {
3300
            return false;
3301
        }
3302
    }
3303
3304
    return Session::read('is_allowedCreateCourse');
3305
}
3306
3307
/**
3308
 * Checks whether the current user is a course administrator.
3309
 *
3310
 * @return bool True if current user is a course administrator
3311
 */
3312
function api_is_course_admin()
3313
{
3314
    if (api_is_platform_admin()) {
3315
        return true;
3316
    }
3317
3318
    return Session::read('is_courseAdmin');
3319
}
3320
3321
/**
3322
 * Checks whether the current user is a course coach
3323
 * Based on the presence of user in session.id_coach (session general coach).
3324
 *
3325
 * @return bool True if current user is a course coach
3326
 */
3327
function api_is_session_general_coach()
3328
{
3329
    return Session::read('is_session_general_coach');
3330
}
3331
3332
/**
3333
 * Checks whether the current user is a course tutor
3334
 * Based on the presence of user in session_rel_course_rel_user.user_id with status = 2.
3335
 *
3336
 * @return bool True if current user is a course tutor
3337
 */
3338
function api_is_course_tutor()
3339
{
3340
    return Session::read('is_courseTutor');
3341
}
3342
3343
/**
3344
 * @param int $user_id
3345
 * @param int $courseId
3346
 * @param int $session_id
3347
 *
3348
 * @return bool
3349
 */
3350
function api_is_course_session_coach($user_id, $courseId, $session_id)
3351
{
3352
    $session_table = Database::get_main_table(TABLE_MAIN_SESSION);
3353
    $session_rel_course_rel_user_table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3354
3355
    $user_id = (int) $user_id;
3356
    $session_id = (int) $session_id;
3357
    $courseId = (int) $courseId;
3358
3359
    $sql = "SELECT DISTINCT session.id
3360
            FROM $session_table
3361
            INNER JOIN $session_rel_course_rel_user_table session_rc_ru
3362
            ON session.id = session_rc_ru.session_id
3363
            WHERE
3364
                session_rc_ru.user_id = '".$user_id."'  AND
3365
                session_rc_ru.c_id = '$courseId' AND
3366
                session_rc_ru.status = 2 AND
3367
                session_rc_ru.session_id = '$session_id'";
3368
    $result = Database::query($sql);
3369
3370
    return Database::num_rows($result) > 0;
3371
}
3372
3373
/**
3374
 * Checks whether the current user is a course or session coach.
3375
 *
3376
 * @param int $session_id
3377
 * @param int $courseId
3378
 * @param bool  Check whether we are in student view and, if we are, return false
3379
 * @param int $userId
3380
 *
3381
 * @return bool True if current user is a course or session coach
3382
 */
3383
function api_is_coach($session_id = 0, $courseId = null, $check_student_view = true, $userId = 0)
3384
{
3385
    $userId = empty($userId) ? api_get_user_id() : (int) $userId;
3386
3387
    if (!empty($session_id)) {
3388
        $session_id = (int) $session_id;
3389
    } else {
3390
        $session_id = api_get_session_id();
3391
    }
3392
3393
    // The student preview was on
3394
    if ($check_student_view && api_is_student_view_active()) {
3395
        return false;
3396
    }
3397
3398
    if (!empty($courseId)) {
3399
        $courseId = (int) $courseId;
3400
    } else {
3401
        $courseId = api_get_course_int_id();
3402
    }
3403
3404
    $session_table = Database::get_main_table(TABLE_MAIN_SESSION);
3405
    $session_rel_course_rel_user_table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3406
    $sessionIsCoach = [];
3407
3408
    if (!empty($courseId)) {
3409
        $sql = "SELECT DISTINCT s.id, name, access_start_date, access_end_date
3410
                FROM $session_table s
3411
                INNER JOIN $session_rel_course_rel_user_table session_rc_ru
3412
                ON session_rc_ru.session_id = s.id AND session_rc_ru.user_id = '".$userId."'
3413
                WHERE
3414
                    session_rc_ru.c_id = '$courseId' AND
3415
                    session_rc_ru.status = 2 AND
3416
                    session_rc_ru.session_id = '$session_id'";
3417
        $result = Database::query($sql);
3418
        $sessionIsCoach = Database::store_result($result);
3419
    }
3420
3421
    if (!empty($session_id)) {
3422
        $sql = "SELECT DISTINCT id, name, access_start_date, access_end_date
3423
                FROM $session_table
3424
                WHERE session.id_coach = $userId AND id = $session_id
3425
                ORDER BY access_start_date, access_end_date, name";
3426
        $result = Database::query($sql);
3427
        if (!empty($sessionIsCoach)) {
3428
            $sessionIsCoach = array_merge(
3429
                $sessionIsCoach,
3430
                Database::store_result($result)
3431
            );
3432
        } else {
3433
            $sessionIsCoach = Database::store_result($result);
3434
        }
3435
    }
3436
3437
    return count($sessionIsCoach) > 0;
3438
}
3439
3440
/**
3441
 * Checks whether the current user is a session administrator.
3442
 *
3443
 * @return bool True if current user is a course administrator
3444
 */
3445
function api_is_session_admin()
3446
{
3447
    $user = api_get_user_info();
3448
3449
    return isset($user['status']) && $user['status'] == SESSIONADMIN;
3450
}
3451
3452
/**
3453
 * Checks whether the current user is a human resources manager.
3454
 *
3455
 * @return bool True if current user is a human resources manager
3456
 */
3457
function api_is_drh()
3458
{
3459
    $user = api_get_user_info();
3460
3461
    return isset($user['status']) && $user['status'] == DRH;
3462
}
3463
3464
/**
3465
 * Checks whether the current user is a student.
3466
 *
3467
 * @return bool True if current user is a human resources manager
3468
 */
3469
function api_is_student()
3470
{
3471
    $user = api_get_user_info();
3472
3473
    return isset($user['status']) && $user['status'] == STUDENT;
3474
}
3475
3476
/**
3477
 * Checks whether the current user has the status 'teacher'.
3478
 *
3479
 * @return bool True if current user is a human resources manager
3480
 */
3481
function api_is_teacher()
3482
{
3483
    $user = api_get_user_info();
3484
3485
    return isset($user['status']) && $user['status'] == COURSEMANAGER;
3486
}
3487
3488
/**
3489
 * Checks whether the current user is a invited user.
3490
 *
3491
 * @return bool
3492
 */
3493
function api_is_invitee()
3494
{
3495
    $user = api_get_user_info();
3496
3497
    return isset($user['status']) && $user['status'] == INVITEE;
3498
}
3499
3500
/**
3501
 * This function checks whether a session is assigned into a category.
3502
 *
3503
 * @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...
3504
 * @param string    - category name
3505
 *
3506
 * @return bool - true if is found, otherwise false
3507
 */
3508
function api_is_session_in_category($session_id, $category_name)
3509
{
3510
    $session_id = (int) $session_id;
3511
    $category_name = Database::escape_string($category_name);
3512
    $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
3513
    $tbl_session_category = Database::get_main_table(TABLE_MAIN_SESSION_CATEGORY);
3514
3515
    $sql = "SELECT 1
3516
            FROM $tbl_session
3517
            WHERE $session_id IN (
3518
                SELECT s.id FROM $tbl_session s, $tbl_session_category sc
3519
                WHERE
3520
                  s.session_category_id = sc.id AND
3521
                  sc.name LIKE '%$category_name'
3522
            )";
3523
    $rs = Database::query($sql);
3524
3525
    if (Database::num_rows($rs) > 0) {
3526
        return true;
3527
    } else {
3528
        return false;
3529
    }
3530
}
3531
3532
/**
3533
 * Displays the title of a tool.
3534
 * Normal use: parameter is a string:
3535
 * api_display_tool_title("My Tool").
3536
 *
3537
 * Optionally, there can be a subtitle below
3538
 * the normal title, and / or a supra title above the normal title.
3539
 *
3540
 * e.g. supra title:
3541
 * group
3542
 * GROUP PROPERTIES
3543
 *
3544
 * e.g. subtitle:
3545
 * AGENDA
3546
 * calender & events tool
3547
 *
3548
 * @author Hugues Peeters <[email protected]>
3549
 *
3550
 * @param mixed $title_element - it could either be a string or an array
3551
 *                             containing 'supraTitle', 'mainTitle',
3552
 *                             'subTitle'
3553
 */
3554
function api_display_tool_title($title_element)
3555
{
3556
    if (is_string($title_element)) {
3557
        $tit = $title_element;
3558
        unset($title_element);
3559
        $title_element = [];
3560
        $title_element['mainTitle'] = $tit;
3561
    }
3562
    echo '<h3>';
3563
    if (!empty($title_element['supraTitle'])) {
3564
        echo '<small>'.$title_element['supraTitle'].'</small><br />';
3565
    }
3566
    if (!empty($title_element['mainTitle'])) {
3567
        echo $title_element['mainTitle'];
3568
    }
3569
    if (!empty($title_element['subTitle'])) {
3570
        echo '<br /><small>'.$title_element['subTitle'].'</small>';
3571
    }
3572
    echo '</h3>';
3573
}
3574
3575
/**
3576
 * Displays options for switching between student view and course manager view.
3577
 *
3578
 * Changes in version 1.2 (Patrick Cool)
3579
 * Student view switch now behaves as a real switch. It maintains its current state until the state
3580
 * is changed explicitly
3581
 *
3582
 * Changes in version 1.1 (Patrick Cool)
3583
 * student view now works correctly in subfolders of the document tool
3584
 * student view works correctly in the new links tool
3585
 *
3586
 * Example code for using this in your tools:
3587
 * //if ($is_courseAdmin && api_get_setting('student_view_enabled') == 'true') {
3588
 * //   display_tool_view_option($isStudentView);
3589
 * //}
3590
 * //and in later sections, use api_is_allowed_to_edit()
3591
 *
3592
 * @author Roan Embrechts
3593
 * @author Patrick Cool
3594
 * @author Julio Montoya, changes added in Chamilo
3595
 *
3596
 * @version 1.2
3597
 *
3598
 * @todo rewrite code so it is easier to understand
3599
 */
3600
function api_display_tool_view_option()
3601
{
3602
    if (api_get_setting('student_view_enabled') != 'true') {
3603
        return '';
3604
    }
3605
3606
    $sourceurl = '';
3607
    $is_framed = false;
3608
    // Exceptions apply for all multi-frames pages
3609
    if (strpos($_SERVER['REQUEST_URI'], 'chat/chat_banner.php') !== false) {
3610
        // The chat is a multiframe bit that doesn't work too well with the student_view, so do not show the link
3611
        return '';
3612
    }
3613
3614
    // Uncomment to remove student view link from document view page
3615
    if (strpos($_SERVER['REQUEST_URI'], 'lp/lp_header.php') !== false) {
3616
        if (empty($_GET['lp_id'])) {
3617
            return '';
3618
        }
3619
        $sourceurl = substr($_SERVER['REQUEST_URI'], 0, strpos($_SERVER['REQUEST_URI'], '?'));
3620
        $sourceurl = str_replace(
3621
            'lp/lp_header.php',
3622
            'lp/lp_controller.php?'.api_get_cidreq().'&action=view&lp_id='.intval($_GET['lp_id']).'&isStudentView='.($_SESSION['studentview'] == 'studentview' ? 'false' : 'true'),
3623
            $sourceurl
3624
        );
3625
        //showinframes doesn't handle student view anyway...
3626
        //return '';
3627
        $is_framed = true;
3628
    }
3629
3630
    // Check whether the $_SERVER['REQUEST_URI'] contains already url parameters (thus a questionmark)
3631
    if (!$is_framed) {
3632
        if (strpos($_SERVER['REQUEST_URI'], '?') === false) {
3633
            $sourceurl = api_get_self().'?'.api_get_cidreq();
3634
        } else {
3635
            $sourceurl = $_SERVER['REQUEST_URI'];
3636
        }
3637
    }
3638
3639
    $output_string = '';
3640
    if (!empty($_SESSION['studentview'])) {
3641
        if ($_SESSION['studentview'] == 'studentview') {
3642
            // We have to remove the isStudentView=true from the $sourceurl
3643
            $sourceurl = str_replace('&isStudentView=true', '', $sourceurl);
3644
            $sourceurl = str_replace('&isStudentView=false', '', $sourceurl);
3645
            $output_string .= '<a class="btn btn-primary btn-sm" href="'.$sourceurl.'&isStudentView=false" target="_self">'.
3646
                Display::returnFontAwesomeIcon('eye').' '.get_lang('SwitchToTeacherView').'</a>';
3647
        } elseif ($_SESSION['studentview'] == 'teacherview') {
3648
            // Switching to teacherview
3649
            $sourceurl = str_replace('&isStudentView=true', '', $sourceurl);
3650
            $sourceurl = str_replace('&isStudentView=false', '', $sourceurl);
3651
            $output_string .= '<a class="btn btn-default btn-sm" href="'.$sourceurl.'&isStudentView=true" target="_self">'.
3652
                Display::returnFontAwesomeIcon('eye').' '.get_lang('SwitchToStudentView').'</a>';
3653
        }
3654
    } else {
3655
        $output_string .= '<a class="btn btn-default btn-sm" href="'.$sourceurl.'&isStudentView=true" target="_self">'.
3656
            Display::returnFontAwesomeIcon('eye').' '.get_lang('SwitchToStudentView').'</a>';
3657
    }
3658
    $output_string = Security::remove_XSS($output_string);
3659
    $html = Display::tag('div', $output_string, ['class' => 'view-options']);
3660
3661
    return $html;
3662
}
3663
3664
// TODO: This is for the permission section.
3665
/**
3666
 * Function that removes the need to directly use is_courseAdmin global in
3667
 * tool scripts. It returns true or false depending on the user's rights in
3668
 * this particular course.
3669
 * Optionally checking for tutor and coach roles here allows us to use the
3670
 * student_view feature altogether with these roles as well.
3671
 *
3672
 * @param bool  Whether to check if the user has the tutor role
3673
 * @param bool  Whether to check if the user has the coach role
3674
 * @param bool  Whether to check if the user has the session coach role
3675
 * @param bool  check the student view or not
3676
 *
3677
 * @author Roan Embrechts
3678
 * @author Patrick Cool
3679
 * @author Julio Montoya
3680
 *
3681
 * @version 1.1, February 2004
3682
 *
3683
 * @return bool true: the user has the rights to edit, false: he does not
3684
 */
3685
function api_is_allowed_to_edit(
3686
    $tutor = false,
3687
    $coach = false,
3688
    $session_coach = false,
3689
    $check_student_view = true
3690
) {
3691
    $allowSessionAdminEdit = api_get_configuration_value('session_admins_edit_courses_content') === true;
3692
3693
    // Admins can edit anything.
3694
    if (api_is_platform_admin($allowSessionAdminEdit)) {
3695
        //The student preview was on
3696
        if ($check_student_view && api_is_student_view_active()) {
3697
            return false;
3698
        }
3699
3700
        return true;
3701
    }
3702
3703
    $sessionId = api_get_session_id();
3704
3705
    if ($sessionId && api_get_configuration_value('session_courses_read_only_mode')) {
3706
        $efv = new ExtraFieldValue('course');
3707
        $lockExrafieldField = $efv->get_values_by_handler_and_field_variable(
3708
            api_get_course_int_id(),
3709
            'session_courses_read_only_mode'
3710
        );
3711
3712
        if (!empty($lockExrafieldField['value'])) {
3713
            return false;
3714
        }
3715
    }
3716
3717
    $is_allowed_coach_to_edit = api_is_coach(null, null, $check_student_view);
3718
    $session_visibility = api_get_session_visibility($sessionId);
3719
    $is_courseAdmin = api_is_course_admin();
3720
3721
    if (!$is_courseAdmin && $tutor) {
3722
        // If we also want to check if the user is a tutor...
3723
        $is_courseAdmin = $is_courseAdmin || api_is_course_tutor();
3724
    }
3725
3726
    if (!$is_courseAdmin && $coach) {
3727
        // If we also want to check if the user is a coach...';
3728
        // Check if session visibility is read only for coaches.
3729
        if ($session_visibility == SESSION_VISIBLE_READ_ONLY) {
3730
            $is_allowed_coach_to_edit = false;
3731
        }
3732
3733
        if (api_get_setting('allow_coach_to_edit_course_session') == 'true') {
3734
            // Check if coach is allowed to edit a course.
3735
            $is_courseAdmin = $is_courseAdmin || $is_allowed_coach_to_edit;
3736
        }
3737
    }
3738
3739
    if (!$is_courseAdmin && $session_coach) {
3740
        $is_courseAdmin = $is_courseAdmin || $is_allowed_coach_to_edit;
3741
    }
3742
3743
    // Check if the student_view is enabled, and if so, if it is activated.
3744
    if (api_get_setting('student_view_enabled') == 'true') {
3745
        if (!empty($sessionId)) {
3746
            // Check if session visibility is read only for coaches.
3747
            if ($session_visibility == SESSION_VISIBLE_READ_ONLY) {
3748
                $is_allowed_coach_to_edit = false;
3749
            }
3750
3751
            if (api_get_setting('allow_coach_to_edit_course_session') == 'true') {
3752
                // Check if coach is allowed to edit a course.
3753
                $is_allowed = $is_allowed_coach_to_edit;
3754
            } else {
3755
                $is_allowed = false;
3756
            }
3757
            if ($check_student_view) {
3758
                $is_allowed = $is_allowed && $_SESSION['studentview'] != 'studentview';
3759
            }
3760
        } else {
3761
            if ($check_student_view) {
3762
                $is_allowed = $is_courseAdmin && $_SESSION['studentview'] != 'studentview';
3763
            } else {
3764
                $is_allowed = $is_courseAdmin;
3765
            }
3766
        }
3767
3768
        return $is_allowed;
3769
    } else {
3770
        return $is_courseAdmin;
3771
    }
3772
}
3773
3774
/**
3775
 * Returns true if user is a course coach of at least one course in session.
3776
 *
3777
 * @param int $sessionId
3778
 *
3779
 * @return bool
3780
 */
3781
function api_is_coach_of_course_in_session($sessionId)
3782
{
3783
    if (api_is_platform_admin()) {
3784
        return true;
3785
    }
3786
3787
    $userId = api_get_user_id();
3788
    $courseList = UserManager::get_courses_list_by_session(
3789
        $userId,
3790
        $sessionId
3791
    );
3792
3793
    // Session visibility.
3794
    $visibility = api_get_session_visibility(
3795
        $sessionId,
3796
        null,
3797
        false
3798
    );
3799
3800
    if ($visibility != SESSION_VISIBLE && !empty($courseList)) {
3801
        // Course Coach session visibility.
3802
        $blockedCourseCount = 0;
3803
        $closedVisibilityList = [
3804
            COURSE_VISIBILITY_CLOSED,
3805
            COURSE_VISIBILITY_HIDDEN,
3806
        ];
3807
3808
        foreach ($courseList as $course) {
3809
            // Checking session visibility
3810
            $sessionCourseVisibility = api_get_session_visibility(
3811
                $sessionId,
3812
                $course['real_id']
3813
            );
3814
3815
            $courseIsVisible = !in_array(
3816
                $course['visibility'],
3817
                $closedVisibilityList
3818
            );
3819
            if ($courseIsVisible === false || $sessionCourseVisibility == SESSION_INVISIBLE) {
3820
                $blockedCourseCount++;
3821
            }
3822
        }
3823
3824
        // If all courses are blocked then no show in the list.
3825
        if ($blockedCourseCount === count($courseList)) {
3826
            $visibility = SESSION_INVISIBLE;
3827
        } else {
3828
            $visibility = SESSION_VISIBLE;
3829
        }
3830
    }
3831
3832
    switch ($visibility) {
3833
        case SESSION_VISIBLE_READ_ONLY:
3834
        case SESSION_VISIBLE:
3835
        case SESSION_AVAILABLE:
3836
            return true;
3837
            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...
3838
        case SESSION_INVISIBLE:
3839
            return false;
3840
    }
3841
3842
    return false;
3843
}
3844
3845
/**
3846
 * Checks if a student can edit contents in a session depending
3847
 * on the session visibility.
3848
 *
3849
 * @param bool $tutor Whether to check if the user has the tutor role
3850
 * @param bool $coach Whether to check if the user has the coach role
3851
 *
3852
 * @return bool true: the user has the rights to edit, false: he does not
3853
 */
3854
function api_is_allowed_to_session_edit($tutor = false, $coach = false)
3855
{
3856
    if (api_is_allowed_to_edit($tutor, $coach)) {
3857
        // If I'm a teacher, I will return true in order to not affect the normal behaviour of Chamilo tools.
3858
        return true;
3859
    } else {
3860
        $sessionId = api_get_session_id();
3861
3862
        if (0 == $sessionId) {
3863
            // I'm not in a session so i will return true to not affect the normal behaviour of Chamilo tools.
3864
            return true;
3865
        } else {
3866
            // I'm in a session and I'm a student
3867
            // Get the session visibility
3868
            $session_visibility = api_get_session_visibility($sessionId);
3869
            // if 5 the session is still available
3870
            switch ($session_visibility) {
3871
                case SESSION_VISIBLE_READ_ONLY: // 1
3872
                    return false;
3873
                case SESSION_VISIBLE:           // 2
3874
                    return true;
3875
                case SESSION_INVISIBLE:         // 3
3876
                    return false;
3877
                case SESSION_AVAILABLE:         //5
3878
                    return true;
3879
            }
3880
        }
3881
    }
3882
3883
    return false;
3884
}
3885
3886
/**
3887
 * Checks whether the user is allowed in a specific tool for a specific action.
3888
 *
3889
 * @param string $tool   the tool we are checking if the user has a certain permission
3890
 * @param string $action the action we are checking (add, edit, delete, move, visibility)
3891
 *
3892
 * @return bool
3893
 *
3894
 * @author Patrick Cool <[email protected]>, Ghent University
3895
 * @author Julio Montoya
3896
 *
3897
 * @version 1.0
3898
 */
3899
function api_is_allowed($tool, $action, $task_id = 0)
3900
{
3901
    $_user = api_get_user_info();
3902
    $_course = api_get_course_info();
3903
3904
    if (api_is_course_admin()) {
3905
        return true;
3906
    }
3907
3908
    if (is_array($_course) and count($_course) > 0) {
3909
        require_once __DIR__.'/../../permissions/permissions_functions.inc.php';
3910
3911
        // Getting the permissions of this user.
3912
        if ($task_id == 0) {
3913
            $user_permissions = get_permissions('user', $_user['user_id']);
3914
            $_SESSION['total_permissions'][$_course['code']] = $user_permissions;
3915
        }
3916
3917
        // Getting the permissions of the task.
3918
        if ($task_id != 0) {
3919
            $task_permissions = get_permissions('task', $task_id);
3920
            $_SESSION['total_permissions'][$_course['code']] = $task_permissions;
3921
        }
3922
        //print_r($_SESSION['total_permissions']);
3923
3924
        // Getting the permissions of the groups of the user
3925
        //$groups_of_user = GroupManager::get_group_ids($_course['db_name'], $_user['user_id']);
3926
3927
        //foreach($groups_of_user as $group)
3928
        //   $this_group_permissions = get_permissions('group', $group);
3929
3930
        // Getting the permissions of the courseroles of the user
3931
        $user_courserole_permissions = get_roles_permissions('user', $_user['user_id']);
3932
3933
        // Getting the permissions of the platformroles of the user
3934
        //$user_platformrole_permissions = get_roles_permissions('user', $_user['user_id'], ', platform');
3935
3936
        // Getting the permissions of the roles of the groups of the user
3937
        //foreach($groups_of_user as $group)
3938
        //    $this_group_courserole_permissions = get_roles_permissions('group', $group);
3939
3940
        // Getting the permissions of the platformroles of the groups of the user
3941
        //foreach($groups_of_user as $group)
3942
        //    $this_group_platformrole_permissions = get_roles_permissions('group', $group, 'platform');
3943
    }
3944
3945
    // If the permissions are limited, we have to map the extended ones to the limited ones.
3946
    if (api_get_setting('permissions') == 'limited') {
3947
        if ($action == 'Visibility') {
3948
            $action = 'Edit';
3949
        }
3950
        if ($action == 'Move') {
3951
            $action = 'Edit';
3952
        }
3953
    }
3954
3955
    // The session that contains all the permissions already exists for this course
3956
    // so there is no need to requery everything.
3957
    //my_print_r($_SESSION['total_permissions'][$_course['code']][$tool]);
3958
    if (is_array($_SESSION['total_permissions'][$_course['code']][$tool])) {
3959
        if (in_array($action, $_SESSION['total_permissions'][$_course['code']][$tool])) {
3960
            return true;
3961
        } else {
3962
            return false;
3963
        }
3964
    }
3965
3966
    return false;
3967
}
3968
3969
/**
3970
 * Tells whether this user is an anonymous user.
3971
 *
3972
 * @param int  $user_id  User ID (optional, will take session ID if not provided)
3973
 * @param bool $db_check Whether to check in the database (true) or simply in
3974
 *                       the session (false) to see if the current user is the anonymous user
3975
 *
3976
 * @return bool true if this user is anonymous, false otherwise
3977
 */
3978
function api_is_anonymous($user_id = null, $db_check = false)
3979
{
3980
    if (!isset($user_id)) {
3981
        $user_id = api_get_user_id();
3982
    }
3983
3984
    if ($db_check) {
3985
        $info = api_get_user_info($user_id);
3986
        if (false === $info || $info['status'] == ANONYMOUS) {
3987
            return true;
3988
        }
3989
    }
3990
3991
    $_user = api_get_user_info();
3992
3993
    if (isset($_user['status']) && $_user['status'] == ANONYMOUS) {
3994
        //if ($_user['user_id'] == 0) {
3995
        // In some cases, api_set_anonymous doesn't seem to be triggered in local.inc.php. Make sure it is.
3996
        // Occurs in agenda for admin links - YW
3997
        // it occurs when pages are opened directly without entering first the course home page. To fix it add
3998
        // $use_anonymous = true;
3999
        // before including global.inc.php in the page
4000
        global $use_anonymous;
4001
        if (isset($use_anonymous) && $use_anonymous) {
4002
            api_set_anonymous();
4003
        }
4004
4005
        return true;
4006
    }
4007
4008
    return (isset($_user['is_anonymous']) && $_user['is_anonymous'] === true) || $_user === false;
4009
}
4010
4011
/**
4012
 * Displays message "You are not allowed here..." and exits the entire script.
4013
 *
4014
 * @param bool   $print_headers Whether or not to print headers (default = false -> does not print them)
4015
 * @param string $message
4016
 * @param int    $responseCode
4017
 */
4018
function api_not_allowed(
4019
    $print_headers = false,
4020
    $message = null,
4021
    $responseCode = 0
4022
) {
4023
    if (api_get_setting('sso_authentication') === 'true') {
4024
        global $osso;
4025
        if ($osso) {
4026
            $osso->logout();
4027
        }
4028
    }
4029
    $home_url = api_get_path(WEB_PATH);
4030
    $user_id = api_get_user_id();
4031
    $course = api_get_course_id();
4032
4033
    global $this_section;
4034
4035
    if (CustomPages::enabled() && (empty($user_id) || api_is_anonymous())) {
4036
        // Why the CustomPages::enabled() need to be to set the request_uri
4037
        $_SESSION['request_uri'] = $_SERVER['REQUEST_URI'];
4038
        CustomPages::display(CustomPages::INDEX_UNLOGGED);
4039
    }
4040
4041
    $origin = api_get_origin();
4042
4043
    $msg = null;
4044
    if (isset($message)) {
4045
        $msg = $message;
4046
    } else {
4047
        $msg = Display::return_message(
4048
            get_lang('NotAllowedClickBack').'
4049
            <script>function goBack(){window.history.back();}</script>',
4050
            'error',
4051
            false
4052
        );
4053
        $msg .= '<p class="text-center">
4054
             <a onclick="goBack();" class="btn btn-default" href="'.$home_url.'">'.get_lang('GoBack').'</a>
4055
             </p>';
4056
    }
4057
4058
    $msg = Display::div($msg, ['align' => 'center']);
4059
4060
    $show_headers = 0;
4061
    if ($print_headers && $origin != 'learnpath') {
4062
        $show_headers = 1;
4063
    }
4064
4065
    $hideBreadCrumb = false;
4066
    if (api_get_configuration_value('hide_breadcrumb_if_not_allowed')) {
4067
        $hideBreadCrumb = true;
4068
    }
4069
4070
    $tpl = new Template(null, $show_headers, $show_headers, $hideBreadCrumb, true, false, true, $responseCode);
4071
    $tpl->assign('hide_login_link', 1);
4072
    $tpl->assign('content', $msg);
4073
4074
    if (($user_id != 0 && !api_is_anonymous()) &&
4075
        (!isset($course) || $course == -1) &&
4076
        empty($_GET['cidReq'])
4077
    ) {
4078
        // if the access is not authorized and there is some login information
4079
        // but the cidReq is not found, assume we are missing course data and send the user
4080
        // to the user_portal
4081
        $tpl->display_one_col_template();
4082
        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...
4083
    }
4084
4085
    $tplPlugin = new AppPlugin();
4086
    $loginTopRegionContent = $tplPlugin->load_region('login_top', $tpl, true);
4087
    $loginBottomRegionContent = $tplPlugin->load_region('login_bottom', $tpl, true);
4088
4089
    if (!empty($_SERVER['REQUEST_URI']) &&
4090
        (
4091
            !empty($_GET['cidReq']) ||
4092
            $this_section == SECTION_MYPROFILE ||
4093
            $this_section == SECTION_PLATFORM_ADMIN
4094
        )
4095
    ) {
4096
        $courseCode = api_get_course_id();
4097
        // Only display form and return to the previous URL if there was a course ID included
4098
        if ($user_id != 0 && !api_is_anonymous()) {
4099
            //if there is a user ID, then the user is not allowed but the session is still there. Say so and exit
4100
            $tpl->assign('content', $msg);
4101
            $tpl->display_one_col_template();
4102
            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...
4103
        }
4104
4105
        if (!is_null($courseCode)) {
4106
            api_set_firstpage_parameter($courseCode);
4107
        }
4108
4109
        // If the user has no user ID, then his session has expired
4110
        $form = api_get_not_allowed_login_form();
4111
4112
        // see same text in auth/gotocourse.php and main_api.lib.php function api_not_allowed (above)
4113
        $content = Display::return_message(get_lang('NotAllowed'), 'error', false);
4114
4115
        if (!empty($courseCode)) {
4116
            $content .= '<h4>'.get_lang('LoginToGoToThisCourse').'</h4>';
4117
        }
4118
4119
        if (api_is_cas_activated()) {
4120
            $content .= Display::return_message(sprintf(get_lang('YouHaveAnInstitutionalAccount'), api_get_setting("Institution")), '', false);
4121
            $content .= Display::div(
4122
                Template::displayCASLoginButton(),
4123
                ['align' => 'center']
4124
            );
4125
            $content .= Display::return_message(get_lang('YouDontHaveAnInstitutionAccount'));
4126
            $content .= "<p style='text-align:center'><a href='#' onclick='$(this).parent().next().toggle()'>".get_lang('LoginWithExternalAccount')."</a></p>";
4127
            $content .= "<div style='display:none;'>";
4128
        }
4129
        $content .= PHP_EOL.$loginTopRegionContent;
4130
        $content .= '<div class="well">';
4131
        $content .= $form->returnForm();
4132
        $content .= '</div>';
4133
        $content .= PHP_EOL.$loginBottomRegionContent;
4134
        if (api_is_cas_activated()) {
4135
            $content .= "</div>";
4136
        }
4137
4138
        if (!empty($courseCode)) {
4139
            $content .= '<hr/><p style="text-align:center"><a href="'.$home_url.'">'.
4140
                get_lang('ReturnToCourseHomepage').'</a></p>';
4141
        } else {
4142
            $content .= '<hr/><p style="text-align:center"><a href="'.$home_url.'">'.
4143
                get_lang('BackHome').'</a></p>';
4144
        }
4145
4146
        $tpl->setLoginBodyClass();
4147
        $tpl->assign('content', $content);
4148
        $tpl->display_one_col_template();
4149
        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...
4150
    }
4151
4152
    if ($user_id != 0 && !api_is_anonymous()) {
4153
        $tpl->display_one_col_template();
4154
        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...
4155
    }
4156
4157
    $msg = null;
4158
    // The session is over and we were not in a course,
4159
    // or we try to get directly to a private course without being logged
4160
    $courseId = api_get_course_int_id();
4161
    if (!empty($courseId)) {
4162
        api_set_firstpage_parameter(api_get_course_id());
4163
        $tpl->setLoginBodyClass();
4164
4165
        // see same text in auth/gotocourse.php and main_api.lib.php function api_not_allowed (bellow)
4166
        $msg = Display::return_message(get_lang('NotAllowed'), 'error', false);
4167
        $msg .= '<h4>'.get_lang('LoginToGoToThisCourse').'</h4>';
4168
        $casEnabled = api_is_cas_activated();
4169
        if ($casEnabled) {
4170
            $msg .= Display::return_message(
4171
                sprintf(get_lang('YouHaveAnInstitutionalAccount'), api_get_setting("Institution")),
4172
                '',
4173
                false
4174
            );
4175
            $msg .= Display::div(
4176
                Template::displayCASLoginButton(),
4177
                ['align' => 'center']
4178
            );
4179
            $msg .= Display::return_message(get_lang('YouDontHaveAnInstitutionAccount'));
4180
            $msg .= "<p style='text-align:center'><a href='#' onclick='$(this).parent().next().toggle()'>".get_lang('LoginWithExternalAccount')."</a></p>";
4181
            $msg .= "<div style='display:none;'>";
4182
        }
4183
        $form = api_get_not_allowed_login_form();
4184
        $msg .= PHP_EOL.$loginTopRegionContent;
4185
        $msg .= '<div class="well">';
4186
        $msg .= $form->returnForm();
4187
        $msg .= '</div>';
4188
        $msg .= PHP_EOL.$loginBottomRegionContent;
4189
        if ($casEnabled) {
4190
            $msg .= "</div>";
4191
        }
4192
    } else {
4193
        // we were not in a course, return to home page
4194
        $msg = Display::return_message(
4195
            get_lang('NotAllowed'),
4196
            'error',
4197
            false
4198
        );
4199
4200
        $msg .= '<p class="text-center">
4201
                 <a class="btn btn-default" href="'.$home_url.'">'.get_lang('BackHome').'</a>
4202
                 </p>';
4203
4204
        if (!empty($message)) {
4205
            $msg = $message;
4206
        }
4207
4208
        if (api_is_anonymous()) {
4209
            $form = api_get_not_allowed_login_form();
4210
            $msg .= PHP_EOL.$loginTopRegionContent;
4211
            $msg .= '<div class="well">';
4212
            $msg .= $form->returnForm();
4213
            $msg .= '</div>';
4214
            $msg .= PHP_EOL.$loginBottomRegionContent;
4215
        }
4216
    }
4217
4218
    $tpl->assign('content', $msg);
4219
    $tpl->display_one_col_template();
4220
    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...
4221
}
4222
4223
/**
4224
 * @return FormValidator
4225
 */
4226
function api_get_not_allowed_login_form()
4227
{
4228
    $action = api_get_self().'?'.Security::remove_XSS($_SERVER['QUERY_STRING']);
4229
    $action = str_replace('&amp;', '&', $action);
4230
    Session::write('redirect_after_not_allow_page', $action);
4231
    $action .= '&redirect_after_not_allow_page=1';
4232
4233
    $form = new FormValidator(
4234
        'formLogin',
4235
        'post',
4236
        $action,
4237
        null,
4238
        ['class' => 'form-stacked']
4239
    );
4240
    $params = [
4241
        'placeholder' => get_lang('UserName'),
4242
        'class' => 'col-md-3',
4243
    ];
4244
    if (api_browser_support('autocapitalize')) {
4245
        $params['autocapitalize'] = 'none';
4246
    }
4247
4248
    $form->addElement(
4249
        'text',
4250
        'login',
4251
        null,
4252
        $params
4253
    );
4254
    $form->addElement(
4255
        'password',
4256
        'password',
4257
        null,
4258
        ['placeholder' => get_lang('Password'), 'class' => 'col-md-3']
4259
    ); //new
4260
    $form->addButtonNext(get_lang('LoginEnter'), 'submitAuth');
4261
4262
    return $form;
4263
}
4264
4265
/**
4266
 * Gets a UNIX timestamp from a database (MySQL) datetime format string.
4267
 *
4268
 * @param string $last_post_datetime standard output date in a sql query
4269
 *
4270
 * @return int timestamp
4271
 *
4272
 * @author Toon Van Hoecke <[email protected]>
4273
 *
4274
 * @version October 2003
4275
 * @desc convert sql date to unix timestamp
4276
 */
4277
function convert_sql_date($last_post_datetime)
4278
{
4279
    list($last_post_date, $last_post_time) = explode(' ', $last_post_datetime);
4280
    list($year, $month, $day) = explode('-', $last_post_date);
4281
    list($hour, $min, $sec) = explode(':', $last_post_time);
4282
4283
    return gmmktime((int) $hour, (int) $min, (int) $sec, (int) $month, (int) $day, (int) $year);
4284
}
4285
4286
/**
4287
 * Gets item visibility from the item_property table.
4288
 *
4289
 * Getting the visibility is done by getting the last updated visibility entry,
4290
 * using the largest session ID found if session 0 and another was found (meaning
4291
 * the only one that is actually from the session, in case there are results from
4292
 * session 0 *AND* session n).
4293
 *
4294
 * @param array  $_course  Course properties array (result of api_get_course_info())
4295
 * @param string $tool     Tool (learnpath, document, etc)
4296
 * @param int    $id       The item ID in the given tool
4297
 * @param int    $session  The session ID (optional)
4298
 * @param int    $user_id
4299
 * @param string $type
4300
 * @param string $group_id
4301
 *
4302
 * @return int -1 on error, 0 if invisible, 1 if visible
4303
 */
4304
function api_get_item_visibility(
4305
    $_course,
4306
    $tool,
4307
    $id,
4308
    $session = 0,
4309
    $user_id = null,
4310
    $type = null,
4311
    $group_id = null
4312
) {
4313
    if (!is_array($_course) || count($_course) == 0 || empty($tool) || empty($id)) {
4314
        return -1;
4315
    }
4316
4317
    $tool = Database::escape_string($tool);
4318
    $id = (int) $id;
4319
    $session = (int) $session;
4320
    $TABLE_ITEMPROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY);
4321
    $course_id = (int) $_course['real_id'];
4322
4323
    $userCondition = '';
4324
    if (!empty($user_id)) {
4325
        $user_id = (int) $user_id;
4326
        $userCondition = " AND to_user_id = $user_id ";
4327
    }
4328
4329
    $typeCondition = '';
4330
    if (!empty($type)) {
4331
        $type = Database::escape_string($type);
4332
        $typeCondition = " AND lastedit_type = '$type' ";
4333
    }
4334
4335
    $groupCondition = '';
4336
    if (!empty($group_id)) {
4337
        $group_id = (int) $group_id;
4338
        $groupCondition = " AND to_group_id = '$group_id' ";
4339
    }
4340
4341
    $sql = "SELECT visibility
4342
            FROM $TABLE_ITEMPROPERTY
4343
            WHERE
4344
                c_id = $course_id AND
4345
                tool = '$tool' AND
4346
                ref = $id AND
4347
                (session_id = $session OR session_id = 0 OR session_id IS NULL)
4348
                $userCondition $typeCondition $groupCondition
4349
            ORDER BY session_id DESC, lastedit_date DESC
4350
            LIMIT 1";
4351
4352
    $res = Database::query($sql);
4353
    if ($res === false || Database::num_rows($res) == 0) {
4354
        return -1;
4355
    }
4356
    $row = Database::fetch_array($res);
4357
4358
    return (int) $row['visibility'];
4359
}
4360
4361
/**
4362
 * Delete a row in the c_item_property table.
4363
 *
4364
 * @param array  $courseInfo
4365
 * @param string $tool
4366
 * @param int    $itemId
4367
 * @param int    $userId
4368
 * @param int    $groupId    group.iid
4369
 * @param int    $sessionId
4370
 *
4371
 * @return false|null
4372
 */
4373
function api_item_property_delete(
4374
    $courseInfo,
4375
    $tool,
4376
    $itemId,
4377
    $userId,
4378
    $groupId = 0,
4379
    $sessionId = 0
4380
) {
4381
    if (empty($courseInfo)) {
4382
        return false;
4383
    }
4384
4385
    $courseId = (int) $courseInfo['real_id'];
4386
4387
    if (empty($courseId) || empty($tool) || empty($itemId)) {
4388
        return false;
4389
    }
4390
4391
    $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4392
    $tool = Database::escape_string($tool);
4393
    $itemId = intval($itemId);
4394
    $userId = intval($userId);
4395
    $groupId = intval($groupId);
4396
    $sessionId = intval($sessionId);
4397
4398
    $groupCondition = " AND to_group_id = $groupId ";
4399
    if (empty($groupId)) {
4400
        $groupCondition = " AND (to_group_id is NULL OR to_group_id = 0) ";
4401
    }
4402
4403
    $userCondition = " AND to_user_id = $userId ";
4404
    if (empty($userId)) {
4405
        $userCondition = " AND (to_user_id is NULL OR to_user_id = 0) ";
4406
    }
4407
    $sessionCondition = api_get_session_condition($sessionId, true, false, 'session_id');
4408
    $sql = "DELETE FROM $table
4409
            WHERE
4410
                c_id = $courseId AND
4411
                tool  = '$tool' AND
4412
                ref = $itemId
4413
                $sessionCondition
4414
                $userCondition
4415
                $groupCondition
4416
            ";
4417
4418
    Database::query($sql);
4419
}
4420
4421
/**
4422
 * Updates or adds item properties to the Item_propetry table
4423
 * Tool and lastedit_type are language independant strings (langvars->get_lang!).
4424
 *
4425
 * @param array  $_course        array with course properties
4426
 * @param string $tool           tool id, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4427
 * @param int    $item_id        id of the item itself, linked to key of every tool ('id', ...)
4428
 * @param string $last_edit_type add or update action
4429
 *                               (1) message to be translated (in trad4all) : e.g. DocumentAdded, DocumentUpdated;
4430
 *                               (2) "delete"
4431
 *                               (3) "visible"
4432
 *                               (4) "invisible"
4433
 * @param int    $user_id        id of the editing/adding user
4434
 * @param array  $groupInfo      must include group.iid/group.od
4435
 * @param int    $to_user_id     id of the intended user (always has priority over $to_group_id !), only relevant for $type (1)
4436
 * @param string $start_visible  0000-00-00 00:00:00 format
4437
 * @param string $end_visible    0000-00-00 00:00:00 format
4438
 * @param int    $session_id     The session ID, if any, otherwise will default to 0
4439
 *
4440
 * @return bool false if update fails
4441
 *
4442
 * @author Toon Van Hoecke <[email protected]>, Ghent University
4443
 *
4444
 * @version January 2005
4445
 * @desc update the item_properties table (if entry not exists, insert) of the course
4446
 */
4447
function api_item_property_update(
4448
    $_course,
4449
    $tool,
4450
    $item_id,
4451
    $last_edit_type,
4452
    $user_id,
4453
    $groupInfo = [],
4454
    $to_user_id = null,
4455
    $start_visible = '',
4456
    $end_visible = '',
4457
    $session_id = 0
4458
) {
4459
    if (empty($_course)) {
4460
        return false;
4461
    }
4462
4463
    $course_id = $_course['real_id'];
4464
4465
    if (empty($course_id)) {
4466
        return false;
4467
    }
4468
4469
    $to_group_id = 0;
4470
    if (!empty($groupInfo) && isset($groupInfo['iid'])) {
4471
        $to_group_id = (int) $groupInfo['iid'];
4472
    }
4473
4474
    $em = Database::getManager();
4475
4476
    // Definition of variables.
4477
    $tool = Database::escape_string($tool);
4478
    $item_id = (int) $item_id;
4479
    $lastEditTypeNoFilter = $last_edit_type;
4480
    $last_edit_type = Database::escape_string($last_edit_type);
4481
    $user_id = (int) $user_id;
4482
4483
    $startVisible = "NULL";
4484
    if (!empty($start_visible)) {
4485
        $start_visible = Database::escape_string($start_visible);
4486
        $startVisible = "'$start_visible'";
4487
    }
4488
4489
    $endVisible = "NULL";
4490
    if (!empty($end_visible)) {
4491
        $end_visible = Database::escape_string($end_visible);
4492
        $endVisible = "'$end_visible'";
4493
    }
4494
4495
    $to_filter = '';
4496
    $time = api_get_utc_datetime();
4497
4498
    if (!empty($session_id)) {
4499
        $session_id = (int) $session_id;
4500
    } else {
4501
        $session_id = api_get_session_id();
4502
    }
4503
4504
    // Definition of tables.
4505
    $tableItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
4506
4507
    if ($to_user_id <= 0) {
4508
        $to_user_id = null; // No to_user_id set
4509
    }
4510
4511
    if (!is_null($to_user_id)) {
4512
        // $to_user_id has more priority than $to_group_id
4513
        $to_user_id = (int) $to_user_id;
4514
        $to_field = 'to_user_id';
4515
        $to_value = $to_user_id;
4516
    } else {
4517
        // $to_user_id is not set.
4518
        $to_field = 'to_group_id';
4519
        $to_value = $to_group_id;
4520
    }
4521
4522
    $toValueCondition = empty($to_value) ? 'NULL' : "'$to_value'";
4523
    // Set filters for $to_user_id and $to_group_id, with priority for $to_user_id
4524
    $condition_session = " AND session_id = $session_id ";
4525
    if (empty($session_id)) {
4526
        $condition_session = ' AND (session_id = 0 OR session_id IS NULL) ';
4527
    }
4528
4529
    $filter = " c_id = $course_id AND tool = '$tool' AND ref = $item_id $condition_session ";
4530
4531
    // Check whether $to_user_id and $to_group_id are passed in the function call.
4532
    // If both are not passed (both are null) then it is a message for everybody and $to_group_id should be 0 !
4533
    if (is_null($to_user_id) && is_null($to_group_id)) {
4534
        $to_group_id = 0;
4535
    }
4536
4537
    if (!is_null($to_user_id)) {
4538
        // Set filter to intended user.
4539
        $to_filter = " AND to_user_id = $to_user_id $condition_session";
4540
    } else {
4541
        // Set filter to intended group.
4542
        if (($to_group_id != 0) && $to_group_id == strval(intval($to_group_id))) {
4543
            $to_filter = " AND to_group_id = $to_group_id $condition_session";
4544
        }
4545
    }
4546
4547
    // Adding filter if set.
4548
    $filter .= $to_filter;
4549
4550
    // Update if possible
4551
    $set_type = '';
4552
4553
    switch ($lastEditTypeNoFilter) {
4554
        case 'delete':
4555
            // delete = make item only visible for the platform admin.
4556
            $visibility = '2';
4557
            if (!empty($session_id)) {
4558
                // Check whether session id already exist into item_properties for updating visibility or add it.
4559
                $sql = "SELECT session_id FROM $tableItemProperty
4560
                        WHERE
4561
                            c_id = $course_id AND
4562
                            tool = '$tool' AND
4563
                            ref = $item_id AND
4564
                            session_id = $session_id";
4565
                $rs = Database::query($sql);
4566
                if (Database::num_rows($rs) > 0) {
4567
                    $sql = "UPDATE $tableItemProperty
4568
                            SET lastedit_type       = '".str_replace('_', '', ucwords($tool))."Deleted',
4569
                                lastedit_date       = '$time',
4570
                                lastedit_user_id    = $user_id,
4571
                                visibility          = $visibility,
4572
                                session_id          = $session_id $set_type
4573
                            WHERE $filter";
4574
                    $result = Database::query($sql);
4575
                } else {
4576
                    $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)
4577
                            VALUES ($course_id, '$tool',$item_id, '$time', $user_id, '$time', '$last_edit_type',$user_id, $toValueCondition, $visibility, $startVisible, $endVisible, $session_id)";
4578
                    $result = Database::query($sql);
4579
                    $id = Database::insert_id();
4580
                    if ($id) {
4581
                        $sql = "UPDATE $tableItemProperty SET id = iid WHERE iid = $id";
4582
                        Database::query($sql);
4583
                    }
4584
                }
4585
            } else {
4586
                $sql = "UPDATE $tableItemProperty
4587
                        SET
4588
                            lastedit_type='".str_replace('_', '', ucwords($tool))."Deleted',
4589
                            lastedit_date='$time',
4590
                            lastedit_user_id = $user_id,
4591
                            visibility = $visibility $set_type
4592
                        WHERE $filter";
4593
                $result = Database::query($sql);
4594
            }
4595
            break;
4596
        case 'visible': // Change item to visible.
4597
            $visibility = '1';
4598
            if (!empty($session_id)) {
4599
                // Check whether session id already exist into item_properties for updating visibility or add it.
4600
                $sql = "SELECT session_id FROM $tableItemProperty
4601
                        WHERE
4602
                            c_id = $course_id AND
4603
                            tool = '$tool' AND
4604
                            ref = $item_id AND
4605
                            session_id = $session_id";
4606
                $rs = Database::query($sql);
4607
                if (Database::num_rows($rs) > 0) {
4608
                    $sql = "UPDATE $tableItemProperty
4609
                            SET
4610
                                lastedit_type='".str_replace('_', '', ucwords($tool))."Visible',
4611
                                lastedit_date='$time',
4612
                                lastedit_user_id = $user_id,
4613
                                visibility = $visibility,
4614
                                session_id = $session_id $set_type
4615
                            WHERE $filter";
4616
                    $result = Database::query($sql);
4617
                } else {
4618
                    $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)
4619
                            VALUES ($course_id, '$tool', $item_id, '$time', $user_id, '$time', '$last_edit_type', $user_id, $toValueCondition, $visibility, $startVisible, $endVisible, $session_id)";
4620
                    $result = Database::query($sql);
4621
                    $id = Database::insert_id();
4622
                    if ($id) {
4623
                        $sql = "UPDATE $tableItemProperty SET id = iid WHERE iid = $id";
4624
                        Database::query($sql);
4625
                    }
4626
                }
4627
            } else {
4628
                $sql = "UPDATE $tableItemProperty
4629
                        SET
4630
                            lastedit_type='".str_replace('_', '', ucwords($tool))."Visible',
4631
                            lastedit_date='$time',
4632
                            lastedit_user_id = $user_id,
4633
                            visibility = $visibility $set_type
4634
                        WHERE $filter";
4635
                $result = Database::query($sql);
4636
            }
4637
            break;
4638
        case 'invisible': // Change item to invisible.
4639
            $visibility = '0';
4640
            if (!empty($session_id)) {
4641
                // Check whether session id already exist into item_properties for updating visibility or add it
4642
                $sql = "SELECT session_id FROM $tableItemProperty
4643
                        WHERE
4644
                            c_id = $course_id AND
4645
                            tool = '$tool' AND
4646
                            ref = $item_id AND
4647
                            session_id = $session_id";
4648
                $rs = Database::query($sql);
4649
                if (Database::num_rows($rs) > 0) {
4650
                    $sql = "UPDATE $tableItemProperty
4651
                            SET
4652
                                lastedit_type = '".str_replace('_', '', ucwords($tool))."Invisible',
4653
                                lastedit_date = '$time',
4654
                                lastedit_user_id = $user_id,
4655
                                visibility = $visibility,
4656
                                session_id = $session_id $set_type
4657
                            WHERE $filter";
4658
                    $result = Database::query($sql);
4659
                } else {
4660
                    $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)
4661
                            VALUES ($course_id, '$tool', $item_id, '$time', $user_id, '$time', '$last_edit_type', $user_id, $toValueCondition, $visibility, $startVisible, $endVisible, $session_id)";
4662
                    $result = Database::query($sql);
4663
                    $id = Database::insert_id();
4664
                    if ($id) {
4665
                        $sql = "UPDATE $tableItemProperty SET id = iid WHERE iid = $id";
4666
                        Database::query($sql);
4667
                    }
4668
                }
4669
            } else {
4670
                $sql = "UPDATE $tableItemProperty
4671
                        SET
4672
                            lastedit_type = '".str_replace('_', '', ucwords($tool))."Invisible',
4673
                            lastedit_date = '$time',
4674
                            lastedit_user_id = $user_id,
4675
                            visibility = $visibility $set_type
4676
                        WHERE $filter";
4677
                $result = Database::query($sql);
4678
            }
4679
            break;
4680
        default: // The item will be added or updated.
4681
            $set_type = ", lastedit_type = '$last_edit_type' ";
4682
            $visibility = '1';
4683
            //$filter .= $to_filter; already added
4684
            $sql = "UPDATE $tableItemProperty
4685
                    SET
4686
                      lastedit_date = '$time',
4687
                      lastedit_user_id = $user_id $set_type
4688
                    WHERE $filter";
4689
            $result = Database::query($sql);
4690
    }
4691
4692
    // Insert if no entries are found (can only happen in case of $last_edit_type switch is 'default').
4693
    if ($result == false || Database::affected_rows($result) == 0) {
4694
        $objCourse = $em->find('ChamiloCoreBundle:Course', intval($course_id));
4695
        $objTime = new DateTime('now', new DateTimeZone('UTC'));
4696
        $objUser = api_get_user_entity($user_id);
4697
        if (empty($objUser)) {
4698
            // Use anonymous
4699
            $user_id = api_get_anonymous_id();
4700
            $objUser = api_get_user_entity($user_id);
4701
        }
4702
4703
        $objGroup = null;
4704
        if (!empty($to_group_id)) {
4705
            $objGroup = $em->find('ChamiloCourseBundle:CGroupInfo', $to_group_id);
4706
        }
4707
4708
        $objToUser = api_get_user_entity($to_user_id);
4709
        $objSession = $em->find('ChamiloCoreBundle:Session', intval($session_id));
4710
4711
        $startVisibleDate = !empty($start_visible) ? new DateTime($start_visible, new DateTimeZone('UTC')) : null;
4712
        $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...
4713
4714
        $cItemProperty = new CItemProperty($objCourse);
4715
        $cItemProperty
4716
            ->setTool($tool)
4717
            ->setRef($item_id)
4718
            ->setInsertDate($objTime)
4719
            ->setInsertUser($objUser)
4720
            ->setLasteditDate($objTime)
4721
            ->setLasteditType($last_edit_type)
4722
            ->setGroup($objGroup)
4723
            ->setToUser($objToUser)
4724
            ->setVisibility($visibility)
4725
            ->setStartVisible($startVisibleDate)
4726
            ->setEndVisible($endVisibleDate)
4727
            ->setSession($objSession);
4728
4729
        $em->persist($cItemProperty);
4730
        $em->flush();
4731
4732
        $id = $cItemProperty->getIid();
4733
4734
        if ($id) {
4735
            $cItemProperty->setId($id);
4736
            $em->merge($cItemProperty);
4737
            $em->flush();
4738
4739
            return false;
4740
        }
4741
    }
4742
4743
    return true;
4744
}
4745
4746
/**
4747
 * Gets item property by tool.
4748
 *
4749
 * @param string $tool        tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4750
 * @param string $course_code
4751
 * @param int    $session_id
4752
 *
4753
 * @return array All fields from c_item_property (all rows found) or empty array
4754
 */
4755
function api_get_item_property_by_tool($tool, $course_code, $session_id = null)
4756
{
4757
    $course_info = api_get_course_info($course_code);
4758
    $tool = Database::escape_string($tool);
4759
4760
    // Definition of tables.
4761
    $item_property_table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4762
    $session_id = (int) $session_id;
4763
    $session_condition = ' AND session_id = '.$session_id;
4764
    if (empty($session_id)) {
4765
        $session_condition = " AND (session_id = 0 OR session_id IS NULL) ";
4766
    }
4767
    $course_id = $course_info['real_id'];
4768
4769
    $sql = "SELECT * FROM $item_property_table
4770
            WHERE
4771
                c_id = $course_id AND
4772
                tool = '$tool'
4773
                $session_condition ";
4774
    $rs = Database::query($sql);
4775
    $list = [];
4776
    if (Database::num_rows($rs) > 0) {
4777
        while ($row = Database::fetch_array($rs, 'ASSOC')) {
4778
            $list[] = $row;
4779
        }
4780
    }
4781
4782
    return $list;
4783
}
4784
4785
/**
4786
 * Gets item property by tool and user.
4787
 *
4788
 * @param int $userId
4789
 * @param int $tool
4790
 * @param int $courseId
4791
 * @param int $session_id
4792
 *
4793
 * @return array
4794
 */
4795
function api_get_item_property_list_by_tool_by_user(
4796
    $userId,
4797
    $tool,
4798
    $courseId,
4799
    $session_id = 0
4800
) {
4801
    $userId = intval($userId);
4802
    $tool = Database::escape_string($tool);
4803
    $session_id = intval($session_id);
4804
    $courseId = intval($courseId);
4805
4806
    // Definition of tables.
4807
    $item_property_table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4808
    $session_condition = ' AND session_id = '.$session_id;
4809
    if (empty($session_id)) {
4810
        $session_condition = " AND (session_id = 0 OR session_id IS NULL) ";
4811
    }
4812
    $sql = "SELECT * FROM $item_property_table
4813
            WHERE
4814
                insert_user_id = $userId AND
4815
                c_id = $courseId AND
4816
                tool = '$tool'
4817
                $session_condition ";
4818
4819
    $rs = Database::query($sql);
4820
    $list = [];
4821
    if (Database::num_rows($rs) > 0) {
4822
        while ($row = Database::fetch_array($rs, 'ASSOC')) {
4823
            $list[] = $row;
4824
        }
4825
    }
4826
4827
    return $list;
4828
}
4829
4830
/**
4831
 * Gets item property id from tool of a course.
4832
 *
4833
 * @param string $course_code course code
4834
 * @param string $tool        tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4835
 * @param int    $ref         id of the item itself, linked to key of every tool ('id', ...), "*" = all items of the tool
4836
 * @param int    $sessionId   Session ID (optional)
4837
 *
4838
 * @return int
4839
 */
4840
function api_get_item_property_id($course_code, $tool, $ref, $sessionId = 0)
4841
{
4842
    $course_info = api_get_course_info($course_code);
4843
    $tool = Database::escape_string($tool);
4844
    $ref = (int) $ref;
4845
4846
    // Definition of tables.
4847
    $tableItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
4848
    $course_id = $course_info['real_id'];
4849
    $sessionId = (int) $sessionId;
4850
    $sessionCondition = " AND session_id = $sessionId ";
4851
    if (empty($sessionId)) {
4852
        $sessionCondition = ' AND (session_id = 0 OR session_id IS NULL) ';
4853
    }
4854
    $sql = "SELECT id FROM $tableItemProperty
4855
            WHERE
4856
                c_id = $course_id AND
4857
                tool = '$tool' AND
4858
                ref = $ref
4859
                $sessionCondition";
4860
    $rs = Database::query($sql);
4861
    $item_property_id = '';
4862
    if (Database::num_rows($rs) > 0) {
4863
        $row = Database::fetch_array($rs);
4864
        $item_property_id = $row['id'];
4865
    }
4866
4867
    return $item_property_id;
4868
}
4869
4870
/**
4871
 * Inserts a record in the track_e_item_property table (No update).
4872
 *
4873
 * @param string $tool
4874
 * @param int    $ref
4875
 * @param string $title
4876
 * @param string $content
4877
 * @param int    $progress
4878
 *
4879
 * @return bool|int
4880
 */
4881
function api_track_item_property_update($tool, $ref, $title, $content, $progress)
4882
{
4883
    $tbl_stats_item_property = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ITEM_PROPERTY);
4884
    $course_id = api_get_course_int_id(); //numeric
4885
    $course_code = api_get_course_id(); //alphanumeric
4886
    $item_property_id = api_get_item_property_id($course_code, $tool, $ref);
4887
    if (!empty($item_property_id)) {
4888
        $sql = "INSERT IGNORE INTO $tbl_stats_item_property SET
4889
                course_id           = '$course_id',
4890
                item_property_id    = '$item_property_id',
4891
                title               = '".Database::escape_string($title)."',
4892
                content             = '".Database::escape_string($content)."',
4893
                progress            = '".intval($progress)."',
4894
                lastedit_date       = '".api_get_utc_datetime()."',
4895
                lastedit_user_id    = '".api_get_user_id()."',
4896
                session_id          = '".api_get_session_id()."'";
4897
        $result = Database::query($sql);
4898
        $affected_rows = Database::affected_rows($result);
4899
4900
        return $affected_rows;
4901
    }
4902
4903
    return false;
4904
}
4905
4906
/**
4907
 * @param string $tool
4908
 * @param int    $ref
4909
 *
4910
 * @return array|resource
4911
 */
4912
function api_get_track_item_property_history($tool, $ref)
4913
{
4914
    $tbl_stats_item_property = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ITEM_PROPERTY);
4915
    $course_id = api_get_course_int_id(); //numeric
4916
    $course_code = api_get_course_id(); //alphanumeric
4917
    $item_property_id = api_get_item_property_id($course_code, $tool, $ref);
4918
    $sql = "SELECT * FROM $tbl_stats_item_property
4919
            WHERE item_property_id = $item_property_id AND course_id = $course_id
4920
            ORDER BY lastedit_date DESC";
4921
    $result = Database::query($sql);
4922
    if ($result === false or $result === null) {
4923
        $result = [];
4924
    } else {
4925
        $result = Database::store_result($result, 'ASSOC');
4926
    }
4927
4928
    return $result;
4929
}
4930
4931
/**
4932
 * Gets item property data from tool of a course id.
4933
 *
4934
 * @param int    $course_id
4935
 * @param string $tool       tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4936
 * @param int    $ref        id of the item itself, linked to key of every tool ('id', ...), "*" = all items of the tool
4937
 * @param int    $session_id
4938
 * @param int    $groupId
4939
 *
4940
 * @return array with all fields from c_item_property, empty array if not found or false if course could not be found
4941
 */
4942
function api_get_item_property_info($course_id, $tool, $ref, $session_id = 0, $groupId = 0)
4943
{
4944
    $courseInfo = api_get_course_info_by_id($course_id);
4945
4946
    if (empty($courseInfo)) {
4947
        return false;
4948
    }
4949
4950
    $tool = Database::escape_string($tool);
4951
    $course_id = $courseInfo['real_id'];
4952
    $ref = (int) $ref;
4953
    $session_id = (int) $session_id;
4954
4955
    $sessionCondition = " session_id = $session_id";
4956
    if (empty($session_id)) {
4957
        $sessionCondition = ' (session_id = 0 OR session_id IS NULL) ';
4958
    }
4959
4960
    // Definition of tables.
4961
    $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4962
4963
    $sql = "SELECT * FROM $table
4964
            WHERE
4965
                c_id = $course_id AND
4966
                tool = '$tool' AND
4967
                ref = $ref AND
4968
                $sessionCondition ";
4969
4970
    if (!empty($groupId)) {
4971
        $groupId = (int) $groupId;
4972
        $sql .= " AND to_group_id = $groupId ";
4973
    }
4974
4975
    $rs = Database::query($sql);
4976
    $row = [];
4977
    if (Database::num_rows($rs) > 0) {
4978
        $row = Database::fetch_array($rs, 'ASSOC');
4979
    }
4980
4981
    return $row;
4982
}
4983
4984
/**
4985
 * Gets the last item property data from tool of a course id, in chronological order.
4986
 *
4987
 * @param string $tool      tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4988
 * @param int    $ref       id of the item itself, linked to key of every tool ('id', ...), "*" = all items of the tool
4989
 * @param int    $sessionId
4990
 * @param int    $groupId
4991
 *
4992
 * @return array with all fields from c_item_property, empty array if not found or false if course could not be found
4993
 */
4994
function api_get_last_item_property_info(int $courseId, string $tool, int $ref, int $sessionId = null, int $groupId = null): array
4995
{
4996
    $tool = Database::escape_string($tool);
4997
    // Definition of tables.
4998
    $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4999
    $sessionCondition = " session_id = $sessionId";
5000
    if (empty($sessionId)) {
5001
        $sessionCondition = ' (session_id = 0 OR session_id IS NULL) ';
5002
    }
5003
5004
    $sql = "SELECT * FROM $table
5005
            WHERE
5006
                c_id = $courseId AND
5007
                tool = '$tool' AND
5008
                ref = $ref AND
5009
                $sessionCondition ";
5010
5011
    if (!empty($groupId)) {
5012
        $sql .= " AND to_group_id = $groupId ";
5013
    }
5014
    // Add criteria to only get the last one
5015
    $sql .= "ORDER BY lastedit_date DESC LIMIT 1";
5016
    $rs = Database::query($sql);
5017
    $row = [];
5018
    if (Database::num_rows($rs) > 0) {
5019
        $row = Database::fetch_array($rs, 'ASSOC');
5020
    }
5021
5022
    return $row;
5023
}
5024
5025
/**
5026
 * Displays a combo box so the user can select his/her preferred language.
5027
 *
5028
 * @param string The desired name= value for the select
5029
 * @param bool Whether we use the JQuery Chozen library or not
5030
 * (in some cases, like the indexing language picker, it can alter the presentation)
5031
 *
5032
 * @return string
5033
 */
5034
function api_get_languages_combo($name = 'language')
5035
{
5036
    $ret = '';
5037
    $platformLanguage = api_get_setting('platformLanguage');
5038
5039
    // Retrieve a complete list of all the languages.
5040
    $language_list = api_get_languages();
5041
5042
    if (count($language_list['name']) < 2) {
5043
        return $ret;
5044
    }
5045
5046
    // The the current language of the user so that his/her language occurs as selected in the dropdown menu.
5047
    if (isset($_SESSION['user_language_choice'])) {
5048
        $default = $_SESSION['user_language_choice'];
5049
    } else {
5050
        $default = $platformLanguage;
5051
    }
5052
5053
    $languages = $language_list['name'];
5054
    $folder = $language_list['folder'];
5055
5056
    $ret .= '<select name="'.$name.'" id="language_chosen" class="selectpicker form-control">';
5057
    foreach ($languages as $key => $value) {
5058
        if ($folder[$key] == $default) {
5059
            $selected = ' selected="selected"';
5060
        } else {
5061
            $selected = '';
5062
        }
5063
        $ret .= sprintf('<option value=%s" %s>%s</option>', $folder[$key], $selected, $value);
5064
    }
5065
    $ret .= '</select>';
5066
5067
    return $ret;
5068
}
5069
5070
/**
5071
 * Displays a form (drop down menu) so the user can select his/her preferred language.
5072
 * The form works with or without javascript.
5073
 *
5074
 * @param  bool Hide form if only one language available (defaults to false = show the box anyway)
5075
 * @param bool $showAsButton
5076
 *
5077
 * @return string|null Display the box directly
5078
 */
5079
function api_display_language_form($hide_if_no_choice = false, $showAsButton = false)
5080
{
5081
    // Retrieve a complete list of all the languages.
5082
    $language_list = api_get_languages();
5083
    if (count($language_list['name']) <= 1 && $hide_if_no_choice) {
5084
        return null; //don't show any form
5085
    }
5086
5087
    // The the current language of the user so that his/her language occurs as selected in the dropdown menu.
5088
    if (isset($_SESSION['user_language_choice'])) {
5089
        $user_selected_language = $_SESSION['user_language_choice'];
5090
    }
5091
    if (empty($user_selected_language)) {
5092
        $user_selected_language = api_get_setting('platformLanguage');
5093
    }
5094
5095
    $currentLanguageId = api_get_language_id($user_selected_language);
5096
    $currentLanguageInfo = api_get_language_info($currentLanguageId);
5097
5098
    $countryCode = languageCodeToCountryIsoCodeForFlags($currentLanguageInfo['isocode']);
5099
    $url = api_get_self();
5100
    if ($showAsButton) {
5101
        $html = '<div class="btn-group">
5102
              <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
5103
                <span class="flag-icon flag-icon-'.$countryCode.'"></span>
5104
                '.$currentLanguageInfo['original_name'].'
5105
                <span class="caret">
5106
                </span>
5107
              </button>';
5108
    } else {
5109
        $html = '
5110
            <a href="'.$url.'" class="dropdown-toggle" data-toggle="dropdown" role="button">
5111
                <span class="flag-icon flag-icon-'.$countryCode.'"></span>
5112
                '.$currentLanguageInfo['original_name'].'
5113
                <span class="caret"></span>
5114
            </a>
5115
            ';
5116
    }
5117
5118
    $html .= '<ul class="dropdown-menu" role="menu">';
5119
    foreach ($language_list['all'] as $key => $data) {
5120
        $urlLink = $url.'?language='.$data['english_name'];
5121
        $html .= '<li><a href="'.$urlLink.'"><span class="flag-icon flag-icon-'.languageCodeToCountryIsoCodeForFlags($data['isocode']).'"></span> '.$data['original_name'].'</a></li>';
5122
    }
5123
    $html .= '</ul>';
5124
5125
    if ($showAsButton) {
5126
        $html .= '</div>';
5127
    }
5128
5129
    return $html;
5130
}
5131
5132
/**
5133
 * Return a country code based on a language in order to show a country flag.
5134
 * Note: Showing a "language" flag is arguably a bad idea, as several countries
5135
 * share languages and the right flag cannot be shown for all of them.
5136
 *
5137
 * @param string $languageIsoCode
5138
 *
5139
 * @return string
5140
 */
5141
function languageCodeToCountryIsoCodeForFlags($languageIsoCode)
5142
{
5143
    $allow = api_get_configuration_value('language_flags_by_country');
5144
5145
    // @todo save in DB
5146
    switch ($languageIsoCode) {
5147
        case 'ar':
5148
            $country = 'ae';
5149
            break;
5150
        case 'bs':
5151
            $country = 'ba';
5152
            break;
5153
        case 'ca':
5154
            $country = 'es';
5155
            if ($allow) {
5156
                $country = 'catalan';
5157
            }
5158
            break;
5159
        case 'cs':
5160
            $country = 'cz';
5161
            break;
5162
        case 'da':
5163
            $country = 'dk';
5164
            break;
5165
        case 'el':
5166
            $country = 'gr';
5167
            break;
5168
        case 'en':
5169
            $country = 'gb';
5170
            break;
5171
        case 'eu': // Euskera
5172
            $country = 'es';
5173
            if ($allow) {
5174
                $country = 'basque';
5175
            }
5176
            break;
5177
        case 'gl': // galego
5178
            $country = 'es';
5179
            if ($allow) {
5180
                $country = 'galician';
5181
            }
5182
            break;
5183
        case 'he':
5184
            $country = 'il';
5185
            break;
5186
        case 'ja':
5187
            $country = 'jp';
5188
            break;
5189
        case 'ka':
5190
            $country = 'ge';
5191
            break;
5192
        case 'ko':
5193
            $country = 'kr';
5194
            break;
5195
        case 'ms':
5196
            $country = 'my';
5197
            break;
5198
        case 'pt-BR':
5199
            $country = 'br';
5200
            break;
5201
        case 'qu':
5202
            $country = 'pe';
5203
            break;
5204
        case 'sl':
5205
            $country = 'si';
5206
            break;
5207
        case 'sv':
5208
            $country = 'se';
5209
            break;
5210
        case 'uk': // Ukraine
5211
            $country = 'ua';
5212
            break;
5213
        case 'vi': // Vietnam - GH#4231
5214
            $country = 'vn';
5215
            break;
5216
        case 'zh-TW':
5217
        case 'zh':
5218
            $country = 'cn';
5219
            break;
5220
        default:
5221
            $country = $languageIsoCode;
5222
            break;
5223
    }
5224
    $country = strtolower($country);
5225
5226
    return $country;
5227
}
5228
5229
/**
5230
 * Returns a list of all the languages that are made available by the admin.
5231
 *
5232
 * @return array An array with all languages. Structure of the array is
5233
 *               array['name'] = An array with the name of every language
5234
 *               array['folder'] = An array with the corresponding names of the language-folders in the filesystem
5235
 */
5236
function api_get_languages()
5237
{
5238
    $tbl_language = Database::get_main_table(TABLE_MAIN_LANGUAGE);
5239
    $sql = "SELECT * FROM $tbl_language WHERE available='1'
5240
            ORDER BY original_name ASC";
5241
    $result = Database::query($sql);
5242
    $language_list = [];
5243
    while ($row = Database::fetch_array($result)) {
5244
        $language_list['name'][] = $row['original_name'];
5245
        $language_list['folder'][] = $row['dokeos_folder'];
5246
        $language_list['all'][] = $row;
5247
    }
5248
5249
    return $language_list;
5250
}
5251
5252
/**
5253
 * Returns a list of all the languages that are made available by the admin.
5254
 *
5255
 * @return array
5256
 */
5257
function api_get_languages_to_array()
5258
{
5259
    $tbl_language = Database::get_main_table(TABLE_MAIN_LANGUAGE);
5260
    $sql = "SELECT * FROM $tbl_language
5261
            WHERE available='1' ORDER BY original_name ASC";
5262
    $result = Database::query($sql);
5263
    $languages = [];
5264
    while ($row = Database::fetch_array($result)) {
5265
        $languages[$row['dokeos_folder']] = $row['original_name'];
5266
    }
5267
5268
    return $languages;
5269
}
5270
5271
/**
5272
 * Returns the id (the database id) of a language.
5273
 *
5274
 * @param   string  language name (the corresponding name of the language-folder in the filesystem)
5275
 *
5276
 * @return int id of the language
5277
 */
5278
function api_get_language_id($language)
5279
{
5280
    if (empty($language)) {
5281
        return null;
5282
    }
5283
5284
    static $staticResult = [];
5285
5286
    if (isset($staticResult[$language])) {
5287
        return $staticResult[$language];
5288
    } else {
5289
        $table = Database::get_main_table(TABLE_MAIN_LANGUAGE);
5290
        $language = Database::escape_string($language);
5291
        $sql = "SELECT id FROM $table
5292
                WHERE dokeos_folder = '$language' LIMIT 1";
5293
        $result = Database::query($sql);
5294
        $row = Database::fetch_array($result);
5295
5296
        $staticResult[$language] = $row['id'];
5297
5298
        return $row['id'];
5299
    }
5300
}
5301
5302
/**
5303
 * Gets language of the requested type for the current user. Types are :
5304
 * user_profil_lang : profile language of current user
5305
 * user_select_lang : language selected by user at login
5306
 * course_lang : language of the current course
5307
 * platform_lang : default platform language.
5308
 *
5309
 * @param string $lang_type
5310
 *
5311
 * @return string
5312
 */
5313
function api_get_language_from_type($lang_type)
5314
{
5315
    $return = false;
5316
    switch ($lang_type) {
5317
        case 'platform_lang':
5318
            $temp_lang = api_get_setting('platformLanguage');
5319
            if (!empty($temp_lang)) {
5320
                $return = $temp_lang;
5321
            }
5322
            break;
5323
        case 'user_profil_lang':
5324
            $_user = api_get_user_info();
5325
            if (isset($_user['language']) && !empty($_user['language'])) {
5326
                $return = $_user['language'];
5327
            }
5328
            break;
5329
        case 'user_selected_lang':
5330
            if (isset($_SESSION['user_language_choice']) && !empty($_SESSION['user_language_choice'])) {
5331
                $return = $_SESSION['user_language_choice'];
5332
            }
5333
            break;
5334
        case 'course_lang':
5335
            global $_course;
5336
            $cidReq = null;
5337
            if (empty($_course)) {
5338
                // Code modified because the local.inc.php file it's declarated after this work
5339
                // causing the function api_get_course_info() returns a null value
5340
                $cidReq = isset($_GET["cidReq"]) ? Database::escape_string($_GET["cidReq"]) : null;
5341
                $cDir = (!empty($_GET['cDir']) ? $_GET['cDir'] : null);
5342
                if (empty($cidReq) && !empty($cDir)) {
5343
                    $c = CourseManager::getCourseCodeFromDirectory($cDir);
5344
                    if ($c) {
5345
                        $cidReq = $c;
5346
                    }
5347
                }
5348
            }
5349
            $_course = api_get_course_info($cidReq);
5350
            if (isset($_course['language']) && !empty($_course['language'])) {
5351
                $return = $_course['language'];
5352
                $showCourseInUserLanguage = api_get_course_setting('show_course_in_user_language');
5353
                if ($showCourseInUserLanguage == 1) {
5354
                    $userInfo = api_get_user_info();
5355
                    if (isset($userInfo['language'])) {
5356
                        $return = $userInfo['language'];
5357
                    }
5358
                }
5359
            }
5360
            break;
5361
        default:
5362
            $return = false;
5363
            break;
5364
    }
5365
5366
    return $return;
5367
}
5368
5369
/**
5370
 * Get the language information by its id.
5371
 *
5372
 * @param int $languageId
5373
 *
5374
 * @throws Exception
5375
 *
5376
 * @return array
5377
 */
5378
function api_get_language_info($languageId)
5379
{
5380
    if (empty($languageId)) {
5381
        return [];
5382
    }
5383
5384
    $language = Database::getManager()
5385
        ->find('ChamiloCoreBundle:Language', $languageId);
5386
5387
    if (!$language) {
5388
        return [];
5389
    }
5390
5391
    return [
5392
        'id' => $language->getId(),
5393
        'original_name' => $language->getOriginalName(),
5394
        'english_name' => $language->getEnglishName(),
5395
        'isocode' => $language->getIsocode(),
5396
        'dokeos_folder' => $language->getDokeosFolder(),
5397
        'available' => $language->getAvailable(),
5398
        'parent_id' => $language->getParent() ? $language->getParent()->getId() : null,
5399
    ];
5400
}
5401
5402
/**
5403
 * Returns the name of the visual (CSS) theme to be applied on the current page.
5404
 * The returned name depends on the platform, course or user -wide settings.
5405
 *
5406
 * @return string The visual theme's name, it is the name of a folder inside web/css/themes
5407
 */
5408
function api_get_visual_theme()
5409
{
5410
    static $visual_theme;
5411
5412
    $course_id = api_get_course_id();
5413
    $courseThemeAvailable = false;
5414
    // If called from CLI or from inside a course, it should be reloaded.
5415
    if ('cli' === PHP_SAPI) {
5416
        $visual_theme = null;
5417
    } elseif (!empty($course_id)) {
5418
        $courseThemeAvailable = api_get_setting('allow_course_theme') == 'true';
5419
        if ($courseThemeAvailable) {
5420
            $visual_theme = null;
5421
        }
5422
    }
5423
5424
    if (!isset($visual_theme)) {
5425
        $cacheAvailable = api_get_configuration_value('apc');
5426
        $userThemeAvailable = api_get_setting('user_selected_theme') == 'true';
5427
        // only use a shared cache if no user-based or course-based theme is allowed
5428
        $useCache = ($cacheAvailable && !$userThemeAvailable && !$courseThemeAvailable);
5429
        $apcVar = '';
5430
        if ($useCache) {
5431
            $apcVar = api_get_configuration_value('apc_prefix').'my_campus_visual_theme';
5432
            if (apcu_exists($apcVar)) {
5433
                return apcu_fetch($apcVar);
5434
            }
5435
        }
5436
5437
        $accessUrlId = api_get_current_access_url_id();
5438
        if ('cli' === PHP_SAPI) {
5439
            $accessUrlId = api_get_configuration_value('access_url');
5440
        }
5441
5442
        // Get style directly from DB
5443
        $styleFromDatabase = api_get_settings_params_simple(
5444
            [
5445
                'variable = ? AND access_url = ?' => [
5446
                    'stylesheets',
5447
                    $accessUrlId,
5448
                ],
5449
            ]
5450
        );
5451
        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...
5452
            $platform_theme = $styleFromDatabase['selected_value'];
5453
        } else {
5454
            $platform_theme = api_get_setting('stylesheets');
5455
        }
5456
5457
        // Platform's theme.
5458
        $visual_theme = $platform_theme;
5459
        if ($userThemeAvailable) {
5460
            $user_info = api_get_user_info();
5461
            if (isset($user_info['theme'])) {
5462
                $user_theme = $user_info['theme'];
5463
5464
                if (!empty($user_theme)) {
5465
                    $visual_theme = $user_theme;
5466
                    // User's theme.
5467
                }
5468
            }
5469
        }
5470
5471
        if (!empty($course_id)) {
5472
            if ($courseThemeAvailable) {
5473
                $course_theme = api_get_course_setting('course_theme', api_get_course_info());
5474
5475
                if (!empty($course_theme) && $course_theme != -1) {
5476
                    if (!empty($course_theme)) {
5477
                        // Course's theme.
5478
                        $visual_theme = $course_theme;
5479
                    }
5480
                }
5481
5482
                $allow_lp_theme = api_get_course_setting('allow_learning_path_theme');
5483
                if ($allow_lp_theme == 1) {
5484
                    global $lp_theme_css, $lp_theme_config;
5485
                    // These variables come from the file lp_controller.php.
5486
                    if (!$lp_theme_config) {
5487
                        if (!empty($lp_theme_css)) {
5488
                            // LP's theme.
5489
                            $visual_theme = $lp_theme_css;
5490
                        }
5491
                    }
5492
                }
5493
            }
5494
        }
5495
5496
        if (empty($visual_theme)) {
5497
            $visual_theme = 'chamilo';
5498
        }
5499
5500
        global $lp_theme_log;
5501
        if ($lp_theme_log) {
5502
            $visual_theme = $platform_theme;
5503
        }
5504
        if ($useCache) {
5505
            apcu_store($apcVar, $visual_theme, 120);
5506
        }
5507
    }
5508
5509
    return $visual_theme;
5510
}
5511
5512
/**
5513
 * Returns a list of CSS themes currently available in the CSS folder
5514
 * The folder must have a default.css file.
5515
 *
5516
 * @param bool $getOnlyThemeFromVirtualInstance Used by the vchamilo plugin
5517
 *
5518
 * @return array list of themes directories from the css folder
5519
 *               Note: Directory names (names of themes) in the file system should contain ASCII-characters only
5520
 */
5521
function api_get_themes($getOnlyThemeFromVirtualInstance = false)
5522
{
5523
    // This configuration value is set by the vchamilo plugin
5524
    $virtualTheme = api_get_configuration_value('virtual_css_theme_folder');
5525
5526
    $readCssFolder = function ($dir) use ($virtualTheme) {
5527
        $finder = new Finder();
5528
        $themes = $finder->directories()->in($dir)->depth(0)->sortByName();
5529
        $list = [];
5530
        /** @var Symfony\Component\Finder\SplFileInfo $theme */
5531
        foreach ($themes as $theme) {
5532
            $folder = $theme->getFilename();
5533
            // A theme folder is consider if there's a default.css file
5534
            if (!file_exists($theme->getPathname().'/default.css')) {
5535
                continue;
5536
            }
5537
            $name = ucwords(str_replace('_', ' ', $folder));
5538
            if ($folder == $virtualTheme) {
5539
                continue;
5540
            }
5541
            $list[$folder] = $name;
5542
        }
5543
5544
        return $list;
5545
    };
5546
5547
    $dir = api_get_path(SYS_CSS_PATH).'themes/';
5548
    $list = $readCssFolder($dir);
5549
5550
    if (!empty($virtualTheme)) {
5551
        $newList = $readCssFolder($dir.'/'.$virtualTheme);
5552
        if ($getOnlyThemeFromVirtualInstance) {
5553
            return $newList;
5554
        }
5555
        $list = $list + $newList;
5556
        asort($list);
5557
    }
5558
5559
    return $list;
5560
}
5561
5562
/**
5563
 * Find the largest sort value in a given user_course_category
5564
 * This function is used when we are moving a course to a different category
5565
 * and also when a user subscribes to courses (the new course is added at the end of the main category.
5566
 *
5567
 * @author Patrick Cool <[email protected]>, Ghent University
5568
 *
5569
 * @param int $user_course_category the id of the user_course_category
5570
 * @param int $user_id
5571
 *
5572
 * @return int the value of the highest sort of the user_course_category
5573
 */
5574
function api_max_sort_value($user_course_category, $user_id)
5575
{
5576
    $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
5577
    $sql = "SELECT max(sort) as max_sort FROM $tbl_course_user
5578
            WHERE
5579
                user_id='".intval($user_id)."' AND
5580
                relation_type<>".COURSE_RELATION_TYPE_RRHH." AND
5581
                user_course_cat='".intval($user_course_category)."'";
5582
    $result_max = Database::query($sql);
5583
    if (Database::num_rows($result_max) == 1) {
5584
        $row_max = Database::fetch_array($result_max);
5585
5586
        return $row_max['max_sort'];
5587
    }
5588
5589
    return 0;
5590
}
5591
5592
/**
5593
 * Transforms a number of seconds in hh:mm:ss format.
5594
 *
5595
 * @author Julian Prud'homme
5596
 *
5597
 * @param int    $seconds      number of seconds
5598
 * @param string $space
5599
 * @param bool   $showSeconds
5600
 * @param bool   $roundMinutes
5601
 *
5602
 * @return string the formatted time
5603
 */
5604
function api_time_to_hms($seconds, $space = ':', $showSeconds = true, $roundMinutes = false)
5605
{
5606
    // $seconds = -1 means that we have wrong data in the db.
5607
    if ($seconds == -1) {
5608
        return
5609
            get_lang('Unknown').
5610
            Display::return_icon(
5611
                'info2.gif',
5612
                get_lang('WrongDatasForTimeSpentOnThePlatform'),
5613
                ['align' => 'absmiddle', 'hspace' => '3px']
5614
            );
5615
    }
5616
5617
    // How many hours ?
5618
    $hours = floor($seconds / 3600);
5619
5620
    // How many minutes ?
5621
    $min = floor(($seconds - ($hours * 3600)) / 60);
5622
5623
    if ($roundMinutes) {
5624
        if ($min >= 45) {
5625
            $min = 45;
5626
        }
5627
5628
        if ($min >= 30 && $min <= 44) {
5629
            $min = 30;
5630
        }
5631
5632
        if ($min >= 15 && $min <= 29) {
5633
            $min = 15;
5634
        }
5635
5636
        if ($min >= 0 && $min <= 14) {
5637
            $min = 0;
5638
        }
5639
    }
5640
5641
    // How many seconds
5642
    $sec = floor($seconds - ($hours * 3600) - ($min * 60));
5643
5644
    if ($hours < 10) {
5645
        $hours = "0$hours";
5646
    }
5647
5648
    if ($sec < 10) {
5649
        $sec = "0$sec";
5650
    }
5651
5652
    if ($min < 10) {
5653
        $min = "0$min";
5654
    }
5655
5656
    $seconds = '';
5657
    if ($showSeconds) {
5658
        $seconds = $space.$sec;
5659
    }
5660
5661
    return $hours.$space.$min.$seconds;
5662
}
5663
5664
/* FILE SYSTEM RELATED FUNCTIONS */
5665
5666
/**
5667
 * Returns the permissions to be assigned to every newly created directory by the web-server.
5668
 * The return value is based on the platform administrator's setting
5669
 * "Administration > Configuration settings > Security > Permissions for new directories".
5670
 *
5671
 * @return int returns the permissions in the format "Owner-Group-Others, Read-Write-Execute", as an integer value
5672
 */
5673
function api_get_permissions_for_new_directories()
5674
{
5675
    static $permissions;
5676
    if (!isset($permissions)) {
5677
        $permissions = trim(api_get_setting('permissions_for_new_directories'));
5678
        // The default value 0777 is according to that in the platform administration panel after fresh system installation.
5679
        $permissions = octdec(!empty($permissions) ? $permissions : '0777');
5680
    }
5681
5682
    return $permissions;
5683
}
5684
5685
/**
5686
 * Returns the permissions to be assigned to every newly created directory by the web-server.
5687
 * The return value is based on the platform administrator's setting
5688
 * "Administration > Configuration settings > Security > Permissions for new files".
5689
 *
5690
 * @return int returns the permissions in the format
5691
 *             "Owner-Group-Others, Read-Write-Execute", as an integer value
5692
 */
5693
function api_get_permissions_for_new_files()
5694
{
5695
    static $permissions;
5696
    if (!isset($permissions)) {
5697
        $permissions = trim(api_get_setting('permissions_for_new_files'));
5698
        // The default value 0666 is according to that in the platform
5699
        // administration panel after fresh system installation.
5700
        $permissions = octdec(!empty($permissions) ? $permissions : '0666');
5701
    }
5702
5703
    return $permissions;
5704
}
5705
5706
/**
5707
 * Deletes a file, or a folder and its contents.
5708
 *
5709
 * @author      Aidan Lister <[email protected]>
5710
 *
5711
 * @version     1.0.3
5712
 *
5713
 * @param string $dirname Directory to delete
5714
 * @param       bool     Deletes only the content or not
5715
 * @param bool $strict if one folder/file fails stop the loop
5716
 *
5717
 * @return bool Returns TRUE on success, FALSE on failure
5718
 *
5719
 * @see http://aidanlister.com/2004/04/recursively-deleting-a-folder-in-php/
5720
 *
5721
 * @author      Yannick Warnier, adaptation for the Chamilo LMS, April, 2008
5722
 * @author      Ivan Tcholakov, a sanity check about Directory class creation has been added, September, 2009
5723
 */
5724
function rmdirr($dirname, $delete_only_content_in_folder = false, $strict = false)
5725
{
5726
    $res = true;
5727
    // A sanity check.
5728
    if (!file_exists($dirname)) {
5729
        return false;
5730
    }
5731
    $php_errormsg = '';
5732
    // Simple delete for a file.
5733
    if (is_file($dirname) || is_link($dirname)) {
5734
        $res = unlink($dirname);
5735
        if ($res === false) {
5736
            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);
5737
        }
5738
5739
        return $res;
5740
    }
5741
5742
    // Loop through the folder.
5743
    $dir = dir($dirname);
5744
    // A sanity check.
5745
    $is_object_dir = is_object($dir);
5746
    if ($is_object_dir) {
5747
        while (false !== $entry = $dir->read()) {
5748
            // Skip pointers.
5749
            if ($entry == '.' || $entry == '..') {
5750
                continue;
5751
            }
5752
5753
            // Recurse.
5754
            if ($strict) {
5755
                $result = rmdirr("$dirname/$entry");
5756
                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...
5757
                    $res = false;
5758
                    break;
5759
                }
5760
            } else {
5761
                rmdirr("$dirname/$entry");
5762
            }
5763
        }
5764
    }
5765
5766
    // Clean up.
5767
    if ($is_object_dir) {
5768
        $dir->close();
5769
    }
5770
5771
    if ($delete_only_content_in_folder == false) {
5772
        $res = rmdir($dirname);
5773
        if ($res === false) {
5774
            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);
5775
        }
5776
    }
5777
5778
    return $res;
5779
}
5780
5781
// TODO: This function is to be simplified. File access modes to be implemented.
5782
/**
5783
 * function adapted from a php.net comment
5784
 * copy recursively a folder.
5785
 *
5786
 * @param string $source       the source folder
5787
 * @param string $dest         the dest folder
5788
 * @param array  $exclude      an array of excluded file_name (without extension)
5789
 * @param array  $copied_files the returned array of copied files
5790
 */
5791
function copyr($source, $dest, $exclude = [], $copied_files = [])
5792
{
5793
    if (empty($dest)) {
5794
        return false;
5795
    }
5796
    // Simple copy for a file
5797
    if (is_file($source)) {
5798
        $path_info = pathinfo($source);
5799
        if (!in_array($path_info['filename'], $exclude)) {
5800
            copy($source, $dest);
5801
        }
5802
5803
        return true;
5804
    } elseif (!is_dir($source)) {
5805
        //then source is not a dir nor a file, return
5806
        return false;
5807
    }
5808
5809
    // Make destination directory.
5810
    if (!is_dir($dest)) {
5811
        mkdir($dest, api_get_permissions_for_new_directories());
5812
    }
5813
5814
    // Loop through the folder.
5815
    $dir = dir($source);
5816
    while (false !== $entry = $dir->read()) {
5817
        // Skip pointers
5818
        if ($entry == '.' || $entry == '..') {
5819
            continue;
5820
        }
5821
5822
        // Deep copy directories.
5823
        if ($dest !== "$source/$entry") {
5824
            $files = copyr("$source/$entry", "$dest/$entry", $exclude, $copied_files);
5825
        }
5826
    }
5827
    // Clean up.
5828
    $dir->close();
5829
5830
    return true;
5831
}
5832
5833
/**
5834
 * @param string $pathname
5835
 * @param string $base_path_document
5836
 * @param int    $session_id
5837
 * @param array
5838
 * @param string
5839
 *
5840
 * @return mixed True if directory already exists, false if a file already exists at
5841
 *               the destination and null if everything goes according to plan
5842
 *@todo: Using DIRECTORY_SEPARATOR is not recommended, this is an obsolete approach.
5843
 * Documentation header to be added here.
5844
 */
5845
function copy_folder_course_session(
5846
    $pathname,
5847
    $base_path_document,
5848
    $session_id,
5849
    $course_info,
5850
    $document,
5851
    $source_course_id,
5852
    $originalFolderNameList = [],
5853
    $originalBaseName = ''
5854
) {
5855
    // Check whether directory already exists.
5856
    if (empty($pathname) || is_dir($pathname)) {
5857
        return true;
5858
    }
5859
5860
    // Ensure that a file with the same name does not already exist.
5861
    if (is_file($pathname)) {
5862
        trigger_error('copy_folder_course_session(): File exists', E_USER_WARNING);
5863
5864
        return false;
5865
    }
5866
5867
    //error_log('checking:');
5868
    //error_log(str_replace($base_path_document.DIRECTORY_SEPARATOR, '', $pathname));
5869
    $baseNoDocument = str_replace('document', '', $originalBaseName);
5870
    $folderTitles = explode('/', $baseNoDocument);
5871
    $folderTitles = array_filter($folderTitles);
5872
5873
    //error_log($baseNoDocument);error_log(print_r($folderTitles, 1));
5874
5875
    $table = Database::get_course_table(TABLE_DOCUMENT);
5876
    $session_id = (int) $session_id;
5877
    $source_course_id = (int) $source_course_id;
5878
    $course_id = $course_info['real_id'];
5879
    $folders = explode(DIRECTORY_SEPARATOR, str_replace($base_path_document.DIRECTORY_SEPARATOR, '', $pathname));
5880
    $new_pathname = $base_path_document;
5881
5882
    $path = '';
5883
    foreach ($folders as $index => $folder) {
5884
        $new_pathname .= DIRECTORY_SEPARATOR.$folder;
5885
        $path .= DIRECTORY_SEPARATOR.$folder;
5886
5887
        if (!file_exists($new_pathname)) {
5888
            $path = Database::escape_string($path);
5889
            //error_log("path: $path");
5890
            $sql = "SELECT * FROM $table
5891
                    WHERE
5892
                        c_id = $source_course_id AND
5893
                        path = '$path' AND
5894
                        filetype = 'folder' AND
5895
                        session_id = '$session_id'";
5896
            $rs1 = Database::query($sql);
5897
            $num_rows = Database::num_rows($rs1);
5898
5899
            if (0 == $num_rows) {
5900
                mkdir($new_pathname, api_get_permissions_for_new_directories());
5901
                $title = basename($new_pathname);
5902
5903
                if (isset($folderTitles[$index + 1])) {
5904
                    $checkPath = $folderTitles[$index + 1];
5905
                    //error_log("check $checkPath");
5906
                    if (isset($originalFolderNameList[$checkPath])) {
5907
                        $title = $originalFolderNameList[$checkPath];
5908
                        //error_log('use this name: '.$title);
5909
                    }
5910
                }
5911
5912
                // Insert new folder with destination session_id.
5913
                $params = [
5914
                    'c_id' => $course_id,
5915
                    'path' => $path,
5916
                    'comment' => $document->comment,
5917
                    'title' => $title,
5918
                    'filetype' => 'folder',
5919
                    'size' => '0',
5920
                    'session_id' => $session_id,
5921
                ];
5922
5923
                //error_log("old $folder"); error_log("Add doc $title in $path");
5924
                $document_id = Database::insert($table, $params);
5925
                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...
5926
                    $sql = "UPDATE $table SET id = iid WHERE iid = $document_id";
5927
                    Database::query($sql);
5928
5929
                    api_item_property_update(
5930
                        $course_info,
5931
                        TOOL_DOCUMENT,
5932
                        $document_id,
5933
                        'FolderCreated',
5934
                        api_get_user_id(),
5935
                        0,
5936
                        0,
5937
                        null,
5938
                        null,
5939
                        $session_id
5940
                    );
5941
                }
5942
            }
5943
        }
5944
    }
5945
}
5946
5947
// TODO: chmodr() is a better name. Some corrections are needed. Documentation header to be added here.
5948
/**
5949
 * @param string $path
5950
 */
5951
function api_chmod_R($path, $filemode)
5952
{
5953
    if (!is_dir($path)) {
5954
        return chmod($path, $filemode);
5955
    }
5956
5957
    $handler = opendir($path);
5958
    while ($file = readdir($handler)) {
5959
        if ($file != '.' && $file != '..') {
5960
            $fullpath = "$path/$file";
5961
            if (!is_dir($fullpath)) {
5962
                if (!chmod($fullpath, $filemode)) {
5963
                    return false;
5964
                }
5965
            } else {
5966
                if (!api_chmod_R($fullpath, $filemode)) {
5967
                    return false;
5968
                }
5969
            }
5970
        }
5971
    }
5972
5973
    closedir($handler);
5974
5975
    return chmod($path, $filemode);
5976
}
5977
5978
// TODO: Where the following function has been copy/pased from? There is no information about author and license. Style, coding conventions...
5979
/**
5980
 * Parse info file format. (e.g: file.info).
5981
 *
5982
 * Files should use an ini-like format to specify values.
5983
 * White-space generally doesn't matter, except inside values.
5984
 * e.g.
5985
 *
5986
 * @verbatim
5987
 *   key = value
5988
 *   key = "value"
5989
 *   key = 'value'
5990
 *   key = "multi-line
5991
 *
5992
 *   value"
5993
 *   key = 'multi-line
5994
 *
5995
 *   value'
5996
 *   key
5997
 *   =
5998
 *   'value'
5999
 * @endverbatim
6000
 *
6001
 * Arrays are created using a GET-like syntax:
6002
 *
6003
 * @verbatim
6004
 *   key[] = "numeric array"
6005
 *   key[index] = "associative array"
6006
 *   key[index][] = "nested numeric array"
6007
 *   key[index][index] = "nested associative array"
6008
 * @endverbatim
6009
 *
6010
 * PHP constants are substituted in, but only when used as the entire value:
6011
 *
6012
 * Comments should start with a semi-colon at the beginning of a line.
6013
 *
6014
 * This function is NOT for placing arbitrary module-specific settings. Use
6015
 * variable_get() and variable_set() for that.
6016
 *
6017
 * Information stored in the module.info file:
6018
 * - name: The real name of the module for display purposes.
6019
 * - description: A brief description of the module.
6020
 * - dependencies: An array of shortnames of other modules this module depends on.
6021
 * - package: The name of the package of modules this module belongs to.
6022
 *
6023
 * Example of .info file:
6024
 * <code>
6025
 * @verbatim
6026
 *   name = Forum
6027
 *   description = Enables threaded discussions about general topics.
6028
 *   dependencies[] = taxonomy
6029
 *   dependencies[] = comment
6030
 *   package = Core - optional
6031
 *   version = VERSION
6032
 * @endverbatim
6033
 * </code>
6034
 *
6035
 * @param string $filename
6036
 *                         The file we are parsing. Accepts file with relative or absolute path.
6037
 *
6038
 * @return
6039
 *   The info array
6040
 */
6041
function api_parse_info_file($filename)
6042
{
6043
    $info = [];
6044
6045
    if (!file_exists($filename)) {
6046
        return $info;
6047
    }
6048
6049
    $data = file_get_contents($filename);
6050
    if (preg_match_all('
6051
        @^\s*                           # Start at the beginning of a line, ignoring leading whitespace
6052
        ((?:
6053
          [^=;\[\]]|                    # Key names cannot contain equal signs, semi-colons or square brackets,
6054
          \[[^\[\]]*\]                  # unless they are balanced and not nested
6055
        )+?)
6056
        \s*=\s*                         # Key/value pairs are separated by equal signs (ignoring white-space)
6057
        (?:
6058
          ("(?:[^"]|(?<=\\\\)")*")|     # Double-quoted string, which may contain slash-escaped quotes/slashes
6059
          (\'(?:[^\']|(?<=\\\\)\')*\')| # Single-quoted string, which may contain slash-escaped quotes/slashes
6060
          ([^\r\n]*?)                   # Non-quoted string
6061
        )\s*$                           # Stop at the next end of a line, ignoring trailing whitespace
6062
        @msx', $data, $matches, PREG_SET_ORDER)) {
6063
        $key = $value1 = $value2 = $value3 = '';
6064
        foreach ($matches as $match) {
6065
            // Fetch the key and value string.
6066
            $i = 0;
6067
            foreach (['key', 'value1', 'value2', 'value3'] as $var) {
6068
                $$var = isset($match[++$i]) ? $match[$i] : '';
6069
            }
6070
            $value = stripslashes(substr($value1, 1, -1)).stripslashes(substr($value2, 1, -1)).$value3;
6071
6072
            // Parse array syntax.
6073
            $keys = preg_split('/\]?\[/', rtrim($key, ']'));
6074
            $last = array_pop($keys);
6075
            $parent = &$info;
6076
6077
            // Create nested arrays.
6078
            foreach ($keys as $key) {
6079
                if ($key == '') {
6080
                    $key = count($parent);
6081
                }
6082
                if (!isset($parent[$key]) || !is_array($parent[$key])) {
6083
                    $parent[$key] = [];
6084
                }
6085
                $parent = &$parent[$key];
6086
            }
6087
6088
            // Handle PHP constants.
6089
            if (defined($value)) {
6090
                $value = constant($value);
6091
            }
6092
6093
            // Insert actual value.
6094
            if ($last == '') {
6095
                $last = count($parent);
6096
            }
6097
            $parent[$last] = $value;
6098
        }
6099
    }
6100
6101
    return $info;
6102
}
6103
6104
/**
6105
 * Gets Chamilo version from the configuration files.
6106
 *
6107
 * @return string A string of type "1.8.4", or an empty string if the version could not be found
6108
 */
6109
function api_get_version()
6110
{
6111
    return (string) api_get_configuration_value('system_version');
6112
}
6113
6114
/**
6115
 * Gets the software name (the name/brand of the Chamilo-based customized system).
6116
 *
6117
 * @return string
6118
 */
6119
function api_get_software_name()
6120
{
6121
    $name = api_get_configuration_value('software_name');
6122
    if (!empty($name)) {
6123
        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...
6124
    } else {
6125
        return 'Chamilo';
6126
    }
6127
}
6128
6129
/**
6130
 * Checks whether status given in parameter exists in the platform.
6131
 *
6132
 * @param mixed the status (can be either int either string)
6133
 *
6134
 * @return bool if the status exists, else returns false
6135
 */
6136
function api_status_exists($status_asked)
6137
{
6138
    global $_status_list;
6139
6140
    return in_array($status_asked, $_status_list) ? true : isset($_status_list[$status_asked]);
6141
}
6142
6143
/**
6144
 * Checks whether status given in parameter exists in the platform. The function
6145
 * returns the status ID or false if it does not exist, but given the fact there
6146
 * is no "0" status, the return value can be checked against
6147
 * if(api_status_key()) to know if it exists.
6148
 *
6149
 * @param   mixed   The status (can be either int or string)
6150
 *
6151
 * @return mixed Status ID if exists, false otherwise
6152
 */
6153
function api_status_key($status)
6154
{
6155
    global $_status_list;
6156
6157
    return isset($_status_list[$status]) ? $status : array_search($status, $_status_list);
6158
}
6159
6160
/**
6161
 * Gets the status langvars list.
6162
 *
6163
 * @return string[] the list of status with their translations
6164
 */
6165
function api_get_status_langvars()
6166
{
6167
    return [
6168
        COURSEMANAGER => get_lang('Teacher', ''),
6169
        SESSIONADMIN => get_lang('SessionsAdmin', ''),
6170
        DRH => get_lang('Drh', ''),
6171
        STUDENT => get_lang('Student', ''),
6172
        ANONYMOUS => get_lang('Anonymous', ''),
6173
        STUDENT_BOSS => get_lang('RoleStudentBoss', ''),
6174
        INVITEE => get_lang('Invited'),
6175
    ];
6176
}
6177
6178
/**
6179
 * The function that retrieves all the possible settings for a certain config setting.
6180
 *
6181
 * @author Patrick Cool <[email protected]>, Ghent University
6182
 */
6183
function api_get_settings_options($var)
6184
{
6185
    $table_settings_options = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
6186
    $var = Database::escape_string($var);
6187
    $sql = "SELECT * FROM $table_settings_options
6188
            WHERE variable = '$var'
6189
            ORDER BY id";
6190
    $result = Database::query($sql);
6191
    $settings_options_array = [];
6192
    while ($row = Database::fetch_array($result, 'ASSOC')) {
6193
        $settings_options_array[] = $row;
6194
    }
6195
6196
    return $settings_options_array;
6197
}
6198
6199
/**
6200
 * @param array $params
6201
 */
6202
function api_set_setting_option($params)
6203
{
6204
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
6205
    if (empty($params['id'])) {
6206
        Database::insert($table, $params);
6207
    } else {
6208
        Database::update($table, $params, ['id = ? ' => $params['id']]);
6209
    }
6210
}
6211
6212
/**
6213
 * @param array $params
6214
 */
6215
function api_set_setting_simple($params)
6216
{
6217
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
6218
    $url_id = api_get_current_access_url_id();
6219
6220
    if (empty($params['id'])) {
6221
        $params['access_url'] = $url_id;
6222
        Database::insert($table, $params);
6223
    } else {
6224
        Database::update($table, $params, ['id = ? ' => [$params['id']]]);
6225
    }
6226
}
6227
6228
/**
6229
 * @param int $id
6230
 */
6231
function api_delete_setting_option($id)
6232
{
6233
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
6234
    if (!empty($id)) {
6235
        Database::delete($table, ['id = ? ' => $id]);
6236
    }
6237
}
6238
6239
/**
6240
 * Sets a platform configuration setting to a given value.
6241
 *
6242
 * @param string    The variable we want to update
6243
 * @param string    The value we want to record
6244
 * @param string    The sub-variable if any (in most cases, this will remain null)
6245
 * @param string    The category if any (in most cases, this will remain null)
6246
 * @param int       The access_url for which this parameter is valid
6247
 * @param string $cat
6248
 *
6249
 * @return bool|null
6250
 */
6251
function api_set_setting($var, $value, $subvar = null, $cat = null, $access_url = 1)
6252
{
6253
    if (empty($var)) {
6254
        return false;
6255
    }
6256
    $t_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
6257
    $var = Database::escape_string($var);
6258
    $value = Database::escape_string($value);
6259
    $access_url = (int) $access_url;
6260
    if (empty($access_url)) {
6261
        $access_url = 1;
6262
    }
6263
    $select = "SELECT id FROM $t_settings WHERE variable = '$var' ";
6264
    if (!empty($subvar)) {
6265
        $subvar = Database::escape_string($subvar);
6266
        $select .= " AND subkey = '$subvar'";
6267
    }
6268
    if (!empty($cat)) {
6269
        $cat = Database::escape_string($cat);
6270
        $select .= " AND category = '$cat'";
6271
    }
6272
    if ($access_url > 1) {
6273
        $select .= " AND access_url = $access_url";
6274
    } else {
6275
        $select .= " AND access_url = 1 ";
6276
    }
6277
6278
    $res = Database::query($select);
6279
    if (Database::num_rows($res) > 0) {
6280
        // Found item for this access_url.
6281
        $row = Database::fetch_array($res);
6282
        $sql = "UPDATE $t_settings SET selected_value = '$value'
6283
                WHERE id = ".$row['id'];
6284
        Database::query($sql);
6285
    } else {
6286
        // Item not found for this access_url, we have to check if it exist with access_url = 1
6287
        $select = "SELECT * FROM $t_settings
6288
                   WHERE variable = '$var' AND access_url = 1 ";
6289
        // Just in case
6290
        if ($access_url == 1) {
6291
            if (!empty($subvar)) {
6292
                $select .= " AND subkey = '$subvar'";
6293
            }
6294
            if (!empty($cat)) {
6295
                $select .= " AND category = '$cat'";
6296
            }
6297
            $res = Database::query($select);
6298
            if (Database::num_rows($res) > 0) {
6299
                // We have a setting for access_url 1, but none for the current one, so create one.
6300
                $row = Database::fetch_array($res);
6301
                $insert = "INSERT INTO $t_settings (variable, subkey, type,category, selected_value, title, comment, scope, subkeytext, access_url)
6302
                        VALUES
6303
                        ('".$row['variable']."',".(!empty($row['subkey']) ? "'".$row['subkey']."'" : "NULL").",".
6304
                        "'".$row['type']."','".$row['category']."',".
6305
                        "'$value','".$row['title']."',".
6306
                        "".(!empty($row['comment']) ? "'".$row['comment']."'" : "NULL").",".(!empty($row['scope']) ? "'".$row['scope']."'" : "NULL").",".
6307
                        "".(!empty($row['subkeytext']) ? "'".$row['subkeytext']."'" : "NULL").",$access_url)";
6308
                Database::query($insert);
6309
            } else {
6310
                // Such a setting does not exist.
6311
                //error_log(__FILE__.':'.__LINE__.': Attempting to update setting '.$var.' ('.$subvar.') which does not exist at all', 0);
6312
            }
6313
        } else {
6314
            // Other access url.
6315
            if (!empty($subvar)) {
6316
                $select .= " AND subkey = '$subvar'";
6317
            }
6318
            if (!empty($cat)) {
6319
                $select .= " AND category = '$cat'";
6320
            }
6321
            $res = Database::query($select);
6322
6323
            if (Database::num_rows($res) > 0) {
6324
                // We have a setting for access_url 1, but none for the current one, so create one.
6325
                $row = Database::fetch_array($res);
6326
                if ($row['access_url_changeable'] == 1) {
6327
                    $insert = "INSERT INTO $t_settings (variable,subkey, type,category, selected_value,title, comment,scope, subkeytext,access_url, access_url_changeable) VALUES
6328
                            ('".$row['variable']."',".
6329
                            (!empty($row['subkey']) ? "'".$row['subkey']."'" : "NULL").",".
6330
                            "'".$row['type']."','".$row['category']."',".
6331
                            "'$value','".$row['title']."',".
6332
                            "".(!empty($row['comment']) ? "'".$row['comment']."'" : "NULL").",".
6333
                            (!empty($row['scope']) ? "'".$row['scope']."'" : "NULL").",".
6334
                            "".(!empty($row['subkeytext']) ? "'".$row['subkeytext']."'" : "NULL").",$access_url,".$row['access_url_changeable'].")";
6335
                    Database::query($insert);
6336
                }
6337
            } else { // Such a setting does not exist.
6338
                //error_log(__FILE__.':'.__LINE__.': Attempting to update setting '.$var.' ('.$subvar.') which does not exist at all. The access_url is: '.$access_url.' ',0);
6339
            }
6340
        }
6341
    }
6342
}
6343
6344
/**
6345
 * Sets a whole category of settings to one specific value.
6346
 *
6347
 * @param string    Category
6348
 * @param string    Value
6349
 * @param int       Access URL. Optional. Defaults to 1
6350
 * @param array     Optional array of filters on field type
6351
 * @param string $category
6352
 * @param string $value
6353
 *
6354
 * @return bool
6355
 */
6356
function api_set_settings_category($category, $value = null, $access_url = 1, $fieldtype = [])
6357
{
6358
    if (empty($category)) {
6359
        return false;
6360
    }
6361
    $category = Database::escape_string($category);
6362
    $t_s = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
6363
    $access_url = (int) $access_url;
6364
    if (empty($access_url)) {
6365
        $access_url = 1;
6366
    }
6367
    if (isset($value)) {
6368
        $value = Database::escape_string($value);
6369
        $sql = "UPDATE $t_s SET selected_value = '$value'
6370
                WHERE category = '$category' AND access_url = $access_url";
6371
        if (is_array($fieldtype) && count($fieldtype) > 0) {
6372
            $sql .= " AND ( ";
6373
            $i = 0;
6374
            foreach ($fieldtype as $type) {
6375
                if ($i > 0) {
6376
                    $sql .= ' OR ';
6377
                }
6378
                $type = Database::escape_string($type);
6379
                $sql .= " type='".$type."' ";
6380
                $i++;
6381
            }
6382
            $sql .= ")";
6383
        }
6384
        $res = Database::query($sql);
6385
6386
        return $res !== false;
6387
    } else {
6388
        $sql = "UPDATE $t_s SET selected_value = NULL
6389
                WHERE category = '$category' AND access_url = $access_url";
6390
        if (is_array($fieldtype) && count($fieldtype) > 0) {
6391
            $sql .= " AND ( ";
6392
            $i = 0;
6393
            foreach ($fieldtype as $type) {
6394
                if ($i > 0) {
6395
                    $sql .= ' OR ';
6396
                }
6397
                $type = Database::escape_string($type);
6398
                $sql .= " type='".$type."' ";
6399
                $i++;
6400
            }
6401
            $sql .= ")";
6402
        }
6403
        $res = Database::query($sql);
6404
6405
        return $res !== false;
6406
    }
6407
}
6408
6409
/**
6410
 * Gets all available access urls in an array (as in the database).
6411
 *
6412
 * @return array An array of database records
6413
 */
6414
function api_get_access_urls($from = 0, $to = 1000000, $order = 'url', $direction = 'ASC')
6415
{
6416
    $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
6417
    $from = (int) $from;
6418
    $to = (int) $to;
6419
    $order = Database::escape_string($order);
6420
    $direction = Database::escape_string($direction);
6421
    $direction = !in_array(strtolower(trim($direction)), ['asc', 'desc']) ? 'asc' : $direction;
6422
6423
    $sql = "SELECT id, url, description, active, created_by, tms
6424
            FROM $table
6425
            ORDER BY `$order` $direction
6426
            LIMIT $to OFFSET $from";
6427
    $res = Database::query($sql);
6428
6429
    return Database::store_result($res);
6430
}
6431
6432
/**
6433
 * Gets the access url info in an array.
6434
 *
6435
 * @param int  $id            Id of the access url
6436
 * @param bool $returnDefault Set to false if you want the real URL if URL 1 is still 'http://localhost/'
6437
 *
6438
 * @return array All the info (url, description, active, created_by, tms)
6439
 *               from the access_url table
6440
 *
6441
 * @author Julio Montoya
6442
 */
6443
function api_get_access_url($id, $returnDefault = true)
6444
{
6445
    static $staticResult;
6446
    $id = (int) $id;
6447
6448
    if (isset($staticResult[$id])) {
6449
        $result = $staticResult[$id];
6450
    } else {
6451
        // Calling the Database:: library dont work this is handmade.
6452
        $table_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
6453
        $sql = "SELECT url, description, active, created_by, tms
6454
                FROM $table_access_url WHERE id = '$id' ";
6455
        $res = Database::query($sql);
6456
        $result = @Database::fetch_array($res);
6457
        $staticResult[$id] = $result;
6458
    }
6459
6460
    // If the result url is 'http://localhost/' (the default) and the root_web
6461
    // (=current url) is different, and the $id is = 1 (which might mean
6462
    // api_get_current_access_url_id() returned 1 by default), then return the
6463
    // root_web setting instead of the current URL
6464
    // This is provided as an option to avoid breaking the storage of URL-specific
6465
    // homepages in home/localhost/
6466
    if ($id === 1 && $returnDefault === false) {
6467
        $currentUrl = api_get_current_access_url_id();
6468
        // only do this if we are on the main URL (=1), otherwise we could get
6469
        // information on another URL instead of the one asked as parameter
6470
        if ($currentUrl === 1) {
6471
            $rootWeb = api_get_path(WEB_PATH);
6472
            $default = 'http://localhost/';
6473
            if ($result['url'] === $default && $rootWeb != $default) {
6474
                $result['url'] = $rootWeb;
6475
            }
6476
        }
6477
    }
6478
6479
    return $result;
6480
}
6481
6482
/**
6483
 * Gets all the current settings for a specific access url.
6484
 *
6485
 * @param string    The category, if any, that we want to get
6486
 * @param string    Whether we want a simple list (display a category) or
6487
 * a grouped list (group by variable as in settings.php default). Values: 'list' or 'group'
6488
 * @param int       Access URL's ID. Optional. Uses 1 by default, which is the unique URL
6489
 *
6490
 * @return array Array of database results for the current settings of the current access URL
6491
 */
6492
function api_get_settings($cat = null, $ordering = 'list', $access_url = 1, $url_changeable = 0)
6493
{
6494
    // Try getting settings from cache first (avoids query w/ ~375 rows result)
6495
    $apcVarName = '';
6496
    $apcVar = [];
6497
    $cacheAvailable = api_get_configuration_value('apc');
6498
    if ($cacheAvailable) {
6499
        $apcVarName = api_get_configuration_value('apc_prefix').'settings';
6500
        $catName = (empty($cat) ? 'global' : $cat);
6501
6502
        if (apcu_exists($apcVarName)) {
6503
            $apcVar = apcu_fetch($apcVarName);
6504
            if (!empty($apcVar[$catName]) && !empty($apcVar[$catName][$ordering]) && isset($apcVar[$catName][$ordering][$url_changeable])) {
6505
                return $apcVar[$catName][$ordering][$url_changeable];
6506
            }
6507
        }
6508
    }
6509
    // Could not find settings in cache (or already expired), so query DB
6510
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
6511
    $access_url = (int) $access_url;
6512
    $where_condition = '';
6513
    if ($url_changeable == 1) {
6514
        $where_condition = " AND access_url_changeable= '1' ";
6515
    }
6516
    if (empty($access_url) || $access_url == -1) {
6517
        $access_url = 1;
6518
    }
6519
    $sql = "SELECT * FROM $table
6520
            WHERE access_url = $access_url  $where_condition ";
6521
6522
    if (!empty($cat)) {
6523
        $cat = Database::escape_string($cat);
6524
        $sql .= " AND category='$cat' ";
6525
    }
6526
    if ($ordering == 'group') {
6527
        $sql .= " ORDER BY id ASC";
6528
    } else {
6529
        $sql .= " ORDER BY 1,2 ASC";
6530
    }
6531
    $result = Database::query($sql);
6532
    if ($result === null) {
6533
        return [];
6534
    }
6535
    $result = Database::store_result($result, 'ASSOC');
6536
6537
    if ($cacheAvailable) {
6538
        // If we got here, it means cache is available but the settings
6539
        // were not recently stored, so now we have them, let's store them
6540
        if (empty($apcVar[$catName])) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $catName does not seem to be defined for all execution paths leading up to this point.
Loading history...
6541
            $apcVar[$catName] = [];
6542
        }
6543
        if (empty($apcVar[$catName][$ordering])) {
6544
            $apcVar[$catName][$ordering] = [];
6545
        }
6546
        $apcVar[$catName][$ordering][$url_changeable] = $result;
6547
        apcu_store($apcVarName, $apcVar, 600);
6548
    }
6549
6550
    return $result;
6551
}
6552
6553
/**
6554
 * @param string $value       The value we want to record
6555
 * @param string $variable    The variable name we want to insert
6556
 * @param string $subKey      The subkey for the variable we want to insert
6557
 * @param string $type        The type for the variable we want to insert
6558
 * @param string $category    The category for the variable we want to insert
6559
 * @param string $title       The title
6560
 * @param string $comment     The comment
6561
 * @param string $scope       The scope
6562
 * @param string $subKeyText  The subkey text
6563
 * @param int    $accessUrlId The access_url for which this parameter is valid
6564
 * @param int    $visibility  The changeability of this setting for non-master urls
6565
 *
6566
 * @return int The setting ID
6567
 */
6568
function api_add_setting(
6569
    $value,
6570
    $variable,
6571
    $subKey = '',
6572
    $type = 'textfield',
6573
    $category = '',
6574
    $title = '',
6575
    $comment = '',
6576
    $scope = '',
6577
    $subKeyText = '',
6578
    $accessUrlId = 1,
6579
    $visibility = 0
6580
) {
6581
    $em = Database::getManager();
6582
    $settingRepo = $em->getRepository('ChamiloCoreBundle:SettingsCurrent');
6583
    $accessUrlId = (int) $accessUrlId ?: 1;
6584
6585
    if (is_array($value)) {
6586
        $value = serialize($value);
6587
    } else {
6588
        $value = trim($value);
6589
    }
6590
6591
    $criteria = ['variable' => $variable, 'accessUrl' => $accessUrlId];
6592
6593
    if (!empty($subKey)) {
6594
        $criteria['subkey'] = $subKey;
6595
    }
6596
6597
    // Check if this variable doesn't exist already
6598
    /** @var SettingsCurrent $setting */
6599
    $setting = $settingRepo->findOneBy($criteria);
6600
6601
    if ($setting) {
0 ignored issues
show
introduced by
$setting is of type Chamilo\CoreBundle\Entity\SettingsCurrent, thus it always evaluated to true.
Loading history...
6602
        $setting->setSelectedValue($value);
6603
6604
        $em->persist($setting);
6605
        $em->flush();
6606
6607
        return $setting->getId();
6608
    }
6609
6610
    // Item not found for this access_url, we have to check if the whole thing is missing
6611
    // (in which case we ignore the insert) or if there *is* a record but just for access_url = 1
6612
    $setting = new SettingsCurrent();
6613
    $setting
6614
        ->setVariable($variable)
6615
        ->setSelectedValue($value)
6616
        ->setType($type)
6617
        ->setCategory($category)
6618
        ->setSubkey($subKey)
6619
        ->setTitle($title)
6620
        ->setComment($comment)
6621
        ->setScope($scope)
6622
        ->setSubkeytext($subKeyText)
6623
        ->setAccessUrl($accessUrlId)
6624
        ->setAccessUrlChangeable($visibility);
6625
6626
    $em->persist($setting);
6627
    $em->flush();
6628
6629
    return $setting->getId();
6630
}
6631
6632
/**
6633
 * Checks wether a user can or can't view the contents of a course.
6634
 *
6635
 * @deprecated use CourseManager::is_user_subscribed_in_course
6636
 *
6637
 * @param int $userid User id or NULL to get it from $_SESSION
6638
 * @param int $cid    course id to check whether the user is allowed
6639
 *
6640
 * @return bool
6641
 */
6642
function api_is_course_visible_for_user($userid = null, $cid = null)
6643
{
6644
    if ($userid === null) {
6645
        $userid = api_get_user_id();
6646
    }
6647
    if (empty($userid) || strval(intval($userid)) != $userid) {
6648
        if (api_is_anonymous()) {
6649
            $userid = api_get_anonymous_id();
6650
        } else {
6651
            return false;
6652
        }
6653
    }
6654
    $cid = Database::escape_string($cid);
6655
6656
    $courseInfo = api_get_course_info($cid);
6657
    $courseId = $courseInfo['real_id'];
6658
    $is_platformAdmin = api_is_platform_admin();
6659
6660
    $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
6661
    $course_cat_table = Database::get_main_table(TABLE_MAIN_CATEGORY);
6662
6663
    $sql = "SELECT
6664
                $course_table.category_code,
6665
                $course_table.visibility,
6666
                $course_table.code,
6667
                $course_cat_table.code
6668
            FROM $course_table
6669
            LEFT JOIN $course_cat_table
6670
                ON $course_table.category_code = $course_cat_table.code
6671
            WHERE
6672
                $course_table.code = '$cid'
6673
            LIMIT 1";
6674
6675
    $result = Database::query($sql);
6676
6677
    if (Database::num_rows($result) > 0) {
6678
        $visibility = Database::fetch_array($result);
6679
        $visibility = $visibility['visibility'];
6680
    } else {
6681
        $visibility = 0;
6682
    }
6683
    // Shortcut permissions in case the visibility is "open to the world".
6684
    if ($visibility === COURSE_VISIBILITY_OPEN_WORLD) {
6685
        return true;
6686
    }
6687
6688
    $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
6689
6690
    $sql = "SELECT
6691
                is_tutor, status
6692
            FROM $tbl_course_user
6693
            WHERE
6694
                user_id  = '$userid' AND
6695
                relation_type <> '".COURSE_RELATION_TYPE_RRHH."' AND
6696
                c_id = $courseId
6697
            LIMIT 1";
6698
6699
    $result = Database::query($sql);
6700
6701
    if (Database::num_rows($result) > 0) {
6702
        // This user has got a recorded state for this course.
6703
        $cuData = Database::fetch_array($result);
6704
        $is_courseMember = true;
6705
        $is_courseAdmin = ($cuData['status'] == 1);
6706
    }
6707
6708
    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...
6709
        // This user has no status related to this course.
6710
        // Is it the session coach or the session admin?
6711
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
6712
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
6713
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
6714
6715
        $sql = "SELECT
6716
                    session.id_coach, session_admin_id, session.id
6717
                FROM
6718
                    $tbl_session as session
6719
                INNER JOIN $tbl_session_course
6720
                    ON session_rel_course.session_id = session.id
6721
                    AND session_rel_course.c_id = '$courseId'
6722
                LIMIT 1";
6723
6724
        $result = Database::query($sql);
6725
        $row = Database::store_result($result);
6726
6727
        if ($row[0]['id_coach'] == $userid) {
6728
            $is_courseMember = true;
6729
            $is_courseAdmin = false;
6730
        } elseif ($row[0]['session_admin_id'] == $userid) {
6731
            $is_courseMember = false;
6732
            $is_courseAdmin = false;
6733
        } else {
6734
            // Check if the current user is the course coach.
6735
            $sql = "SELECT 1
6736
                    FROM $tbl_session_course
6737
                    WHERE session_rel_course.c_id = '$courseId'
6738
                    AND session_rel_course.id_coach = '$userid'
6739
                    LIMIT 1";
6740
6741
            $result = Database::query($sql);
6742
6743
            //if ($row = Database::fetch_array($result)) {
6744
            if (Database::num_rows($result) > 0) {
6745
                $is_courseMember = true;
6746
                $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
6747
6748
                $sql = "SELECT status FROM $tbl_user
6749
                        WHERE user_id = $userid
6750
                        LIMIT 1";
6751
6752
                $result = Database::query($sql);
6753
6754
                if (Database::result($result, 0, 0) == 1) {
6755
                    $is_courseAdmin = true;
6756
                } else {
6757
                    $is_courseAdmin = false;
6758
                }
6759
            } else {
6760
                // Check if the user is a student is this session.
6761
                $sql = "SELECT  id
6762
                        FROM $tbl_session_course_user
6763
                        WHERE
6764
                            user_id  = '$userid' AND
6765
                            c_id = '$courseId'
6766
                        LIMIT 1";
6767
6768
                if (Database::num_rows($result) > 0) {
6769
                    // This user haa got a recorded state for this course.
6770
                    while ($row = Database::fetch_array($result)) {
6771
                        $is_courseMember = true;
6772
                        $is_courseAdmin = false;
6773
                    }
6774
                }
6775
            }
6776
        }
6777
    }
6778
6779
    switch ($visibility) {
6780
        case COURSE_VISIBILITY_OPEN_WORLD:
6781
            return true;
6782
        case COURSE_VISIBILITY_OPEN_PLATFORM:
6783
            return isset($userid);
6784
        case COURSE_VISIBILITY_REGISTERED:
6785
        case COURSE_VISIBILITY_CLOSED:
6786
            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...
6787
        case COURSE_VISIBILITY_HIDDEN:
6788
            return $is_platformAdmin;
6789
    }
6790
6791
    return false;
6792
}
6793
6794
/**
6795
 * Returns whether an element (forum, message, survey ...) belongs to a session or not.
6796
 *
6797
 * @param string the tool of the element
6798
 * @param int the element id in database
6799
 * @param int the session_id to compare with element session id
6800
 *
6801
 * @return bool true if the element is in the session, false else
6802
 */
6803
function api_is_element_in_the_session($tool, $element_id, $session_id = null)
6804
{
6805
    if (is_null($session_id)) {
6806
        $session_id = api_get_session_id();
6807
    }
6808
6809
    $element_id = (int) $element_id;
6810
6811
    if (empty($element_id)) {
6812
        return false;
6813
    }
6814
6815
    // Get information to build query depending of the tool.
6816
    switch ($tool) {
6817
        case TOOL_SURVEY:
6818
            $table_tool = Database::get_course_table(TABLE_SURVEY);
6819
            $key_field = 'survey_id';
6820
            break;
6821
        case TOOL_ANNOUNCEMENT:
6822
            $table_tool = Database::get_course_table(TABLE_ANNOUNCEMENT);
6823
            $key_field = 'id';
6824
            break;
6825
        case TOOL_AGENDA:
6826
            $table_tool = Database::get_course_table(TABLE_AGENDA);
6827
            $key_field = 'id';
6828
            break;
6829
        case TOOL_GROUP:
6830
            $table_tool = Database::get_course_table(TABLE_GROUP);
6831
            $key_field = 'id';
6832
            break;
6833
        default:
6834
            return false;
6835
    }
6836
    $course_id = api_get_course_int_id();
6837
6838
    $sql = "SELECT session_id FROM $table_tool
6839
            WHERE c_id = $course_id AND $key_field =  ".$element_id;
6840
    $rs = Database::query($sql);
6841
    if ($element_session_id = Database::result($rs, 0, 0)) {
6842
        if ($element_session_id == intval($session_id)) {
6843
            // The element belongs to the session.
6844
            return true;
6845
        }
6846
    }
6847
6848
    return false;
6849
}
6850
6851
/**
6852
 * Replaces "forbidden" characters in a filename string.
6853
 *
6854
 * @param string $filename
6855
 * @param bool   $treat_spaces_as_hyphens
6856
 *
6857
 * @return string
6858
 */
6859
function api_replace_dangerous_char($filename, $treat_spaces_as_hyphens = true)
6860
{
6861
    // Some non-properly encoded file names can cause the whole file to be
6862
    // skipped when uploaded. Avoid this by detecting the encoding and
6863
    // converting to UTF-8, setting the source as ASCII (a reasonably
6864
    // limited characters set) if nothing could be found (BT#
6865
    $encoding = api_detect_encoding($filename);
6866
    if (empty($encoding)) {
6867
        $encoding = 'ASCII';
6868
        if (!api_is_valid_ascii($filename)) {
6869
            // try iconv and try non standard ASCII a.k.a CP437
6870
            // see BT#15022
6871
            if (function_exists('iconv')) {
6872
                $result = iconv('CP437', 'UTF-8', $filename);
6873
                if (api_is_valid_utf8($result)) {
6874
                    $filename = $result;
6875
                    $encoding = 'UTF-8';
6876
                }
6877
            }
6878
        }
6879
    }
6880
6881
    $filename = api_to_system_encoding($filename, $encoding);
6882
6883
    $url = URLify::filter(
6884
        $filename,
6885
        250,
6886
        '',
6887
        true,
6888
        false,
6889
        false,
6890
        false,
6891
        $treat_spaces_as_hyphens
6892
    );
6893
6894
    // Replace multiple dots at the end.
6895
    $regex = "/\.+$/";
6896
    $url = preg_replace($regex, '', $url);
6897
6898
    return $url;
6899
}
6900
6901
/**
6902
 * Fixes the $_SERVER['REQUEST_URI'] that is empty in IIS6.
6903
 *
6904
 * @author Ivan Tcholakov, 28-JUN-2006.
6905
 */
6906
function api_request_uri()
6907
{
6908
    if (!empty($_SERVER['REQUEST_URI'])) {
6909
        return $_SERVER['REQUEST_URI'];
6910
    }
6911
    $uri = $_SERVER['SCRIPT_NAME'];
6912
    if (!empty($_SERVER['QUERY_STRING'])) {
6913
        $uri .= '?'.$_SERVER['QUERY_STRING'];
6914
    }
6915
    $_SERVER['REQUEST_URI'] = $uri;
6916
6917
    return $uri;
6918
}
6919
6920
/**
6921
 * Gets the current access_url id of the Chamilo Platform.
6922
 *
6923
 * @return int access_url_id of the current Chamilo Installation or 1 if multiple_access_urls is not enabled
6924
 *
6925
 * @author Julio Montoya <[email protected]>
6926
 */
6927
function api_get_current_access_url_id()
6928
{
6929
    if ('cli' === PHP_SAPI) {
6930
        $accessUrlId = api_get_configuration_value('access_url');
6931
        if (!empty($accessUrlId)) {
6932
            return $accessUrlId;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $accessUrlId also could return the type boolean which is incompatible with the documented return type integer.
Loading history...
6933
        }
6934
    }
6935
6936
    static $id;
6937
    if (!empty($id)) {
6938
        return (int) $id;
6939
    }
6940
6941
    if (!api_get_multiple_access_url()) {
6942
        // If the feature is not enabled, assume 1 and return before querying
6943
        // the database
6944
        return 1;
6945
    }
6946
6947
    $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
6948
    $path = Database::escape_string(api_get_path(WEB_PATH));
6949
    $sql = "SELECT id FROM $table WHERE url = '".$path."'";
6950
    $result = Database::query($sql);
6951
    if (Database::num_rows($result) > 0) {
6952
        $id = Database::result($result, 0, 0);
6953
        if ($id === false) {
6954
            return -1;
6955
        }
6956
6957
        return (int) $id;
6958
    }
6959
6960
    $id = 1;
6961
6962
    //if the url in WEB_PATH was not found, it can only mean that there is
6963
    // either a configuration problem or the first URL has not been defined yet
6964
    // (by default it is http://localhost/). Thus the more sensible thing we can
6965
    // do is return 1 (the main URL) as the user cannot hack this value anyway
6966
    return 1;
6967
}
6968
6969
/**
6970
 * Gets the registered urls from a given user id.
6971
 *
6972
 * @param int $user_id
6973
 * @param int $checkCourseId the course id to check url access
6974
 *
6975
 * @return array
6976
 *
6977
 * @author Julio Montoya <[email protected]>
6978
 */
6979
function api_get_access_url_from_user($user_id, $checkCourseId = null)
6980
{
6981
    $user_id = (int) $user_id;
6982
    $table_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
6983
    $table_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
6984
    $includeIds = "";
6985
    if (isset($checkCourseId)) {
6986
        $cid = (int) $checkCourseId;
6987
        $tblUrlCourse = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
6988
        $sql = "SELECT access_url_id
6989
            FROM $tblUrlCourse url_rel_course
6990
            INNER JOIN $table_url u
6991
            ON (url_rel_course.access_url_id = u.id)
6992
            WHERE c_id = $cid";
6993
        $rs = Database::query($sql);
6994
        $courseUrlIds = [];
6995
        if (Database::num_rows($rs) > 0) {
6996
            while ($rowC = Database::fetch_array($rs, 'ASSOC')) {
6997
                $courseUrlIds[] = $rowC['access_url_id'];
6998
            }
6999
        }
7000
        if (!empty($courseUrlIds)) {
7001
            $includeIds = " AND access_url_id IN (".implode(',', $courseUrlIds).")";
7002
        }
7003
    }
7004
7005
    $sql = "SELECT access_url_id
7006
            FROM $table_url_rel_user url_rel_user
7007
            INNER JOIN $table_url u
7008
            ON (url_rel_user.access_url_id = u.id)
7009
            WHERE user_id = $user_id $includeIds
7010
            ORDER BY access_url_id";
7011
    $result = Database::query($sql);
7012
    $list = [];
7013
    while ($row = Database::fetch_array($result, 'ASSOC')) {
7014
        $list[] = $row['access_url_id'];
7015
    }
7016
7017
    return $list;
7018
}
7019
7020
/**
7021
 * Gets the status of a user in a course.
7022
 *
7023
 * @param int $user_id
7024
 * @param int $courseId
7025
 *
7026
 * @return int user status
7027
 */
7028
function api_get_status_of_user_in_course($user_id, $courseId)
7029
{
7030
    $tbl_rel_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
7031
    if (!empty($user_id) && !empty($courseId)) {
7032
        $user_id = intval($user_id);
7033
        $courseId = intval($courseId);
7034
        $sql = 'SELECT status
7035
                FROM '.$tbl_rel_course_user.'
7036
                WHERE user_id='.$user_id.' AND c_id = '.$courseId;
7037
        $result = Database::query($sql);
7038
        $row_status = Database::fetch_array($result, 'ASSOC');
7039
7040
        return $row_status['status'];
7041
    } else {
7042
        return 0;
7043
    }
7044
}
7045
7046
/**
7047
 * Checks whether the curent user is in a group or not.
7048
 *
7049
 * @param string        The group id - optional (takes it from session if not given)
7050
 * @param string        The course code - optional (no additional check by course if course code is not given)
7051
 *
7052
 * @return bool
7053
 *
7054
 * @author Ivan Tcholakov
7055
 */
7056
function api_is_in_group($groupIdParam = null, $courseCodeParam = null)
7057
{
7058
    if (!empty($courseCodeParam)) {
7059
        $courseCode = api_get_course_id();
7060
        if (!empty($courseCode)) {
7061
            if ($courseCodeParam != $courseCode) {
7062
                return false;
7063
            }
7064
        } else {
7065
            return false;
7066
        }
7067
    }
7068
7069
    $groupId = api_get_group_id();
7070
7071
    if (!empty($groupId)) {
7072
        if (!empty($groupIdParam)) {
7073
            return $groupIdParam == $groupId;
7074
        } else {
7075
            return true;
7076
        }
7077
    }
7078
7079
    return false;
7080
}
7081
7082
/**
7083
 * Checks whether a secret key is valid.
7084
 *
7085
 * @param string $original_key_secret - secret key from (webservice) client
7086
 * @param string $security_key        - security key from Chamilo
7087
 *
7088
 * @return bool - true if secret key is valid, false otherwise
7089
 */
7090
function api_is_valid_secret_key($original_key_secret, $security_key)
7091
{
7092
    if (empty($original_key_secret) || empty($security_key)) {
7093
        return false;
7094
    }
7095
7096
    return (string) $original_key_secret === sha1($security_key);
7097
}
7098
7099
/**
7100
 * Checks whether a user is into course.
7101
 *
7102
 * @param int $course_id - the course id
7103
 * @param int $user_id   - the user id
7104
 *
7105
 * @return bool
7106
 */
7107
function api_is_user_of_course($course_id, $user_id)
7108
{
7109
    $tbl_course_rel_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
7110
    $sql = 'SELECT user_id FROM '.$tbl_course_rel_user.'
7111
            WHERE
7112
                c_id ="'.intval($course_id).'" AND
7113
                user_id = "'.intval($user_id).'" AND
7114
                relation_type <> '.COURSE_RELATION_TYPE_RRHH.' ';
7115
    $result = Database::query($sql);
7116
7117
    return Database::num_rows($result) == 1;
7118
}
7119
7120
/**
7121
 * Checks whether the server's operating system is Windows (TM).
7122
 *
7123
 * @return bool - true if the operating system is Windows, false otherwise
7124
 */
7125
function api_is_windows_os()
7126
{
7127
    if (function_exists('php_uname')) {
7128
        // php_uname() exists as of PHP 4.0.2, according to the documentation.
7129
        // We expect that this function will always work for Chamilo 1.8.x.
7130
        $os = php_uname();
7131
    }
7132
    // The following methods are not needed, but let them stay, just in case.
7133
    elseif (isset($_ENV['OS'])) {
7134
        // Sometimes $_ENV['OS'] may not be present (bugs?)
7135
        $os = $_ENV['OS'];
7136
    } elseif (defined('PHP_OS')) {
7137
        // PHP_OS means on which OS PHP was compiled, this is why
7138
        // using PHP_OS is the last choice for detection.
7139
        $os = PHP_OS;
7140
    } else {
7141
        return false;
7142
    }
7143
7144
    return strtolower(substr((string) $os, 0, 3)) == 'win';
7145
}
7146
7147
/**
7148
 * This function informs whether the sent request is XMLHttpRequest.
7149
 */
7150
function api_is_xml_http_request()
7151
{
7152
    return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest';
7153
}
7154
7155
/**
7156
 * This wrapper function has been implemented for avoiding some known problems about the function getimagesize().
7157
 *
7158
 * @see http://php.net/manual/en/function.getimagesize.php
7159
 * @see http://www.dokeos.com/forum/viewtopic.php?t=12345
7160
 * @see http://www.dokeos.com/forum/viewtopic.php?t=16355
7161
 *
7162
 * @return int
7163
 */
7164
function api_getimagesize($path)
7165
{
7166
    $image = new Image($path);
7167
7168
    return $image->get_image_size();
7169
}
7170
7171
/**
7172
 * This function resizes an image, with preserving its proportions (or aspect ratio).
7173
 *
7174
 * @author Ivan Tcholakov, MAY-2009.
7175
 *
7176
 * @param int $image         System path or URL of the image
7177
 * @param int $target_width  Targeted width
7178
 * @param int $target_height Targeted height
7179
 *
7180
 * @return array Calculated new width and height
7181
 */
7182
function api_resize_image($image, $target_width, $target_height)
7183
{
7184
    $image_properties = api_getimagesize($image);
7185
7186
    return api_calculate_image_size(
7187
        $image_properties['width'],
7188
        $image_properties['height'],
7189
        $target_width,
7190
        $target_height
7191
    );
7192
}
7193
7194
/**
7195
 * This function calculates new image size, with preserving image's proportions (or aspect ratio).
7196
 *
7197
 * @author Ivan Tcholakov, MAY-2009.
7198
 * @author The initial idea has been taken from code by Patrick Cool, MAY-2004.
7199
 *
7200
 * @param int $image_width   Initial width
7201
 * @param int $image_height  Initial height
7202
 * @param int $target_width  Targeted width
7203
 * @param int $target_height Targeted height
7204
 *
7205
 * @return array Calculated new width and height
7206
 */
7207
function api_calculate_image_size(
7208
    $image_width,
7209
    $image_height,
7210
    $target_width,
7211
    $target_height
7212
) {
7213
    // Only maths is here.
7214
    $result = ['width' => $image_width, 'height' => $image_height];
7215
    if ($image_width <= 0 || $image_height <= 0) {
7216
        return $result;
7217
    }
7218
    $resize_factor_width = $target_width / $image_width;
7219
    $resize_factor_height = $target_height / $image_height;
7220
    $delta_width = $target_width - $image_width * $resize_factor_height;
7221
    $delta_height = $target_height - $image_height * $resize_factor_width;
7222
    if ($delta_width > $delta_height) {
7223
        $result['width'] = ceil($image_width * $resize_factor_height);
7224
        $result['height'] = ceil($image_height * $resize_factor_height);
7225
    } elseif ($delta_width < $delta_height) {
7226
        $result['width'] = ceil($image_width * $resize_factor_width);
7227
        $result['height'] = ceil($image_height * $resize_factor_width);
7228
    } else {
7229
        $result['width'] = ceil($target_width);
7230
        $result['height'] = ceil($target_height);
7231
    }
7232
7233
    return $result;
7234
}
7235
7236
/**
7237
 * Returns a list of Chamilo's tools or
7238
 * checks whether a given identificator is a valid Chamilo's tool.
7239
 *
7240
 * @author Isaac flores paz
7241
 *
7242
 * @param string The tool name to filter
7243
 *
7244
 * @return mixed Filtered string or array
7245
 */
7246
function api_get_tools_lists($my_tool = null)
7247
{
7248
    $tools_list = [
7249
        TOOL_DOCUMENT,
7250
        TOOL_THUMBNAIL,
7251
        TOOL_HOTPOTATOES,
7252
        TOOL_CALENDAR_EVENT,
7253
        TOOL_LINK,
7254
        TOOL_COURSE_DESCRIPTION,
7255
        TOOL_SEARCH,
7256
        TOOL_LEARNPATH,
7257
        TOOL_ANNOUNCEMENT,
7258
        TOOL_FORUM,
7259
        TOOL_THREAD,
7260
        TOOL_POST,
7261
        TOOL_DROPBOX,
7262
        TOOL_QUIZ,
7263
        TOOL_USER,
7264
        TOOL_GROUP,
7265
        TOOL_BLOGS,
7266
        TOOL_CHAT,
7267
        TOOL_STUDENTPUBLICATION,
7268
        TOOL_TRACKING,
7269
        TOOL_HOMEPAGE_LINK,
7270
        TOOL_COURSE_SETTING,
7271
        TOOL_BACKUP,
7272
        TOOL_COPY_COURSE_CONTENT,
7273
        TOOL_RECYCLE_COURSE,
7274
        TOOL_COURSE_HOMEPAGE,
7275
        TOOL_COURSE_RIGHTS_OVERVIEW,
7276
        TOOL_UPLOAD,
7277
        TOOL_COURSE_MAINTENANCE,
7278
        TOOL_SURVEY,
7279
        TOOL_WIKI,
7280
        TOOL_GLOSSARY,
7281
        TOOL_GRADEBOOK,
7282
        TOOL_NOTEBOOK,
7283
        TOOL_ATTENDANCE,
7284
        TOOL_COURSE_PROGRESS,
7285
    ];
7286
    if (empty($my_tool)) {
7287
        return $tools_list;
7288
    }
7289
7290
    return in_array($my_tool, $tools_list) ? $my_tool : '';
7291
}
7292
7293
/**
7294
 * Checks whether we already approved the last version term and condition.
7295
 *
7296
 * @param int user id
7297
 *
7298
 * @return bool true if we pass false otherwise
7299
 */
7300
function api_check_term_condition($userId)
7301
{
7302
    if (api_get_setting('allow_terms_conditions') === 'true') {
7303
        // Check if exists terms and conditions
7304
        if (LegalManager::count() == 0) {
7305
            return true;
7306
        }
7307
7308
        $extraFieldValue = new ExtraFieldValue('user');
7309
        $data = $extraFieldValue->get_values_by_handler_and_field_variable(
7310
            $userId,
7311
            'legal_accept'
7312
        );
7313
7314
        if (!empty($data) && isset($data['value']) && !empty($data['value'])) {
7315
            $result = $data['value'];
7316
            $user_conditions = explode(':', $result);
7317
            $version = $user_conditions[0];
7318
            $langId = $user_conditions[1];
7319
            $realVersion = LegalManager::get_last_version($langId);
7320
7321
            return $version >= $realVersion;
7322
        }
7323
7324
        return false;
7325
    }
7326
7327
    return false;
7328
}
7329
7330
/**
7331
 * Gets all information of a tool into course.
7332
 *
7333
 * @param int The tool id
7334
 *
7335
 * @return array
7336
 */
7337
function api_get_tool_information_by_name($name)
7338
{
7339
    $t_tool = Database::get_course_table(TABLE_TOOL_LIST);
7340
    $course_id = api_get_course_int_id();
7341
    $sql = "SELECT * FROM $t_tool
7342
            WHERE c_id = $course_id  AND name = '".Database::escape_string($name)."' ";
7343
    $rs = Database::query($sql);
7344
7345
    return Database::fetch_array($rs, 'ASSOC');
7346
}
7347
7348
/**
7349
 * Function used to protect a "global" admin script.
7350
 * The function blocks access when the user has no global platform admin rights.
7351
 * Global admins are the admins that are registered in the main.admin table
7352
 * AND the users who have access to the "principal" portal.
7353
 * That means that there is a record in the main.access_url_rel_user table
7354
 * with his user id and the access_url_id=1.
7355
 *
7356
 * @author Julio Montoya
7357
 *
7358
 * @param int $user_id
7359
 *
7360
 * @return bool
7361
 */
7362
function api_is_global_platform_admin($user_id = null)
7363
{
7364
    $user_id = (int) $user_id;
7365
    if (empty($user_id)) {
7366
        $user_id = api_get_user_id();
7367
    }
7368
    if (api_is_platform_admin_by_id($user_id)) {
7369
        $urlList = api_get_access_url_from_user($user_id);
7370
        // The admin is registered in the first "main" site with access_url_id = 1
7371
        if (in_array(1, $urlList)) {
7372
            return true;
7373
        } else {
7374
            return false;
7375
        }
7376
    }
7377
7378
    return false;
7379
}
7380
7381
/**
7382
 * @param int  $admin_id_to_check
7383
 * @param int  $my_user_id
7384
 * @param bool $allow_session_admin
7385
 *
7386
 * @return bool
7387
 */
7388
function api_global_admin_can_edit_admin(
7389
    $admin_id_to_check,
7390
    $my_user_id = null,
7391
    $allow_session_admin = false
7392
) {
7393
    if (empty($my_user_id)) {
7394
        $my_user_id = api_get_user_id();
7395
    }
7396
7397
    $iam_a_global_admin = api_is_global_platform_admin($my_user_id);
7398
    $user_is_global_admin = api_is_global_platform_admin($admin_id_to_check);
7399
7400
    if ($iam_a_global_admin) {
7401
        // Global admin can edit everything
7402
        return true;
7403
    } else {
7404
        // If i'm a simple admin
7405
        $is_platform_admin = api_is_platform_admin_by_id($my_user_id);
7406
7407
        if ($allow_session_admin) {
7408
            $is_platform_admin = api_is_platform_admin_by_id($my_user_id) || (api_get_user_status($my_user_id) == SESSIONADMIN);
7409
        }
7410
7411
        if ($is_platform_admin) {
7412
            if ($user_is_global_admin) {
7413
                return false;
7414
            } else {
7415
                return true;
7416
            }
7417
        } else {
7418
            return false;
7419
        }
7420
    }
7421
}
7422
7423
/**
7424
 * @param int  $admin_id_to_check
7425
 * @param int  $my_user_id
7426
 * @param bool $allow_session_admin
7427
 *
7428
 * @return bool|null
7429
 */
7430
function api_protect_super_admin($admin_id_to_check, $my_user_id = null, $allow_session_admin = false)
7431
{
7432
    if (api_global_admin_can_edit_admin($admin_id_to_check, $my_user_id, $allow_session_admin)) {
7433
        return true;
7434
    } else {
7435
        api_not_allowed();
7436
    }
7437
}
7438
7439
/**
7440
 * Function used to protect a global admin script.
7441
 * The function blocks access when the user has no global platform admin rights.
7442
 * See also the api_is_global_platform_admin() function wich defines who's a "global" admin.
7443
 *
7444
 * @author Julio Montoya
7445
 */
7446
function api_protect_global_admin_script()
7447
{
7448
    if (!api_is_global_platform_admin()) {
7449
        api_not_allowed();
7450
7451
        return false;
7452
    }
7453
7454
    return true;
7455
}
7456
7457
/**
7458
 * Get active template.
7459
 *
7460
 * @param string    theme type (optional: default)
7461
 * @param string    path absolute(abs) or relative(rel) (optional:rel)
7462
 *
7463
 * @return string actived template path
7464
 */
7465
function api_get_template($path_type = 'rel')
7466
{
7467
    $path_types = ['rel', 'abs'];
7468
    $template_path = '';
7469
    if (in_array($path_type, $path_types)) {
7470
        if ($path_type == 'rel') {
7471
            $template_path = api_get_path(SYS_TEMPLATE_PATH);
7472
        } else {
7473
            $template_path = api_get_path(WEB_TEMPLATE_PATH);
7474
        }
7475
    }
7476
    $actived_theme = 'default';
7477
    if (api_get_setting('active_template')) {
7478
        $actived_theme = api_get_setting('active_template');
7479
    }
7480
    $actived_theme_path = $template_path.$actived_theme.DIRECTORY_SEPARATOR;
7481
7482
    return $actived_theme_path;
7483
}
7484
7485
/**
7486
 * Check browser support for specific file types or features
7487
 * This function checks if the user's browser supports a file format or given
7488
 * feature, or returns the current browser and major version when
7489
 * $format=check_browser. Only a limited number of formats and features are
7490
 * checked by this method. Make sure you check its definition first.
7491
 *
7492
 * @param string $format Can be a file format (extension like svg, webm, ...) or a feature (like autocapitalize, ...)
7493
 *
7494
 * @return bool or return text array if $format=check_browser
7495
 *
7496
 * @author Juan Carlos Raña Trabado
7497
 */
7498
function api_browser_support($format = '')
7499
{
7500
    $browser = new Browser();
7501
    $current_browser = $browser->getBrowser();
7502
    $a_versiontemp = explode('.', $browser->getVersion());
7503
    $current_majorver = $a_versiontemp[0];
7504
7505
    static $result;
7506
7507
    if (isset($result[$format])) {
7508
        return $result[$format];
7509
    }
7510
7511
    // Native svg support
7512
    if ($format == 'svg') {
7513
        if (($current_browser == 'Internet Explorer' && $current_majorver >= 9) ||
7514
            ($current_browser == 'Firefox' && $current_majorver > 1) ||
7515
            ($current_browser == 'Safari' && $current_majorver >= 4) ||
7516
            ($current_browser == 'Chrome' && $current_majorver >= 1) ||
7517
            ($current_browser == 'Opera' && $current_majorver >= 9)
7518
        ) {
7519
            $result[$format] = true;
7520
7521
            return true;
7522
        } else {
7523
            $result[$format] = false;
7524
7525
            return false;
7526
        }
7527
    } elseif ($format == 'pdf') {
7528
        // native pdf support
7529
        if (($current_browser == 'Chrome' && $current_majorver >= 6) ||
7530
            ('Firefox' === $current_browser && $current_majorver >= 15)
7531
        ) {
7532
            $result[$format] = true;
7533
7534
            return true;
7535
        } else {
7536
            $result[$format] = false;
7537
7538
            return false;
7539
        }
7540
    } elseif ($format == 'tif' || $format == 'tiff') {
7541
        //native tif support
7542
        if ($current_browser == 'Safari' && $current_majorver >= 5) {
7543
            $result[$format] = true;
7544
7545
            return true;
7546
        } else {
7547
            $result[$format] = false;
7548
7549
            return false;
7550
        }
7551
    } elseif ($format == 'ogg' || $format == 'ogx' || $format == 'ogv' || $format == 'oga') {
7552
        //native ogg, ogv,oga support
7553
        if (($current_browser == 'Firefox' && $current_majorver >= 3) ||
7554
            ($current_browser == 'Chrome' && $current_majorver >= 3) ||
7555
            ($current_browser == 'Opera' && $current_majorver >= 9)) {
7556
            $result[$format] = true;
7557
7558
            return true;
7559
        } else {
7560
            $result[$format] = false;
7561
7562
            return false;
7563
        }
7564
    } elseif ($format == 'mpg' || $format == 'mpeg') {
7565
        //native mpg support
7566
        if (($current_browser == 'Safari' && $current_majorver >= 5)) {
7567
            $result[$format] = true;
7568
7569
            return true;
7570
        } else {
7571
            $result[$format] = false;
7572
7573
            return false;
7574
        }
7575
    } elseif ($format == 'mp4') {
7576
        //native mp4 support (TODO: Android, iPhone)
7577
        if ($current_browser == 'Android' || $current_browser == 'iPhone') {
7578
            $result[$format] = true;
7579
7580
            return true;
7581
        } else {
7582
            $result[$format] = false;
7583
7584
            return false;
7585
        }
7586
    } elseif ($format == 'mov') {
7587
        //native mov support( TODO:check iPhone)
7588
        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...
7589
            $result[$format] = true;
7590
7591
            return true;
7592
        } else {
7593
            $result[$format] = false;
7594
7595
            return false;
7596
        }
7597
    } elseif ($format == 'avi') {
7598
        //native avi support
7599
        if ($current_browser == 'Safari' && $current_majorver >= 5) {
7600
            $result[$format] = true;
7601
7602
            return true;
7603
        } else {
7604
            $result[$format] = false;
7605
7606
            return false;
7607
        }
7608
    } elseif ($format == 'wmv') {
7609
        //native wmv support
7610
        if ($current_browser == 'Firefox' && $current_majorver >= 4) {
7611
            $result[$format] = true;
7612
7613
            return true;
7614
        } else {
7615
            $result[$format] = false;
7616
7617
            return false;
7618
        }
7619
    } elseif ($format == 'webm') {
7620
        //native webm support (TODO:check IE9, Chrome9, Android)
7621
        if (($current_browser == 'Firefox' && $current_majorver >= 4) ||
7622
            ($current_browser == 'Opera' && $current_majorver >= 9) ||
7623
            ($current_browser == 'Internet Explorer' && $current_majorver >= 9) ||
7624
            ($current_browser == 'Chrome' && $current_majorver >= 9) ||
7625
            $current_browser == 'Android'
7626
        ) {
7627
            $result[$format] = true;
7628
7629
            return true;
7630
        } else {
7631
            $result[$format] = false;
7632
7633
            return false;
7634
        }
7635
    } elseif ($format == 'wav') {
7636
        //native wav support (only some codecs !)
7637
        if (($current_browser == 'Firefox' && $current_majorver >= 4) ||
7638
            ($current_browser == 'Safari' && $current_majorver >= 5) ||
7639
            ($current_browser == 'Opera' && $current_majorver >= 9) ||
7640
            ($current_browser == 'Internet Explorer' && $current_majorver >= 9) ||
7641
            ($current_browser == 'Chrome' && $current_majorver > 9) ||
7642
            $current_browser == 'Android' ||
7643
            $current_browser == 'iPhone'
7644
        ) {
7645
            $result[$format] = true;
7646
7647
            return true;
7648
        } else {
7649
            $result[$format] = false;
7650
7651
            return false;
7652
        }
7653
    } elseif ($format == 'mid' || $format == 'kar') {
7654
        //native midi support (TODO:check Android)
7655
        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...
7656
            $result[$format] = true;
7657
7658
            return true;
7659
        } else {
7660
            $result[$format] = false;
7661
7662
            return false;
7663
        }
7664
    } elseif ($format == 'wma') {
7665
        //native wma support
7666
        if ($current_browser == 'Firefox' && $current_majorver >= 4) {
7667
            $result[$format] = true;
7668
7669
            return true;
7670
        } else {
7671
            $result[$format] = false;
7672
7673
            return false;
7674
        }
7675
    } elseif ($format == 'au') {
7676
        //native au support
7677
        if ($current_browser == 'Safari' && $current_majorver >= 5) {
7678
            $result[$format] = true;
7679
7680
            return true;
7681
        } else {
7682
            $result[$format] = false;
7683
7684
            return false;
7685
        }
7686
    } elseif ($format == 'mp3') {
7687
        //native mp3 support (TODO:check Android, iPhone)
7688
        if (($current_browser == 'Safari' && $current_majorver >= 5) ||
7689
            ($current_browser == 'Chrome' && $current_majorver >= 6) ||
7690
            ($current_browser == 'Internet Explorer' && $current_majorver >= 9) ||
7691
            $current_browser == 'Android' ||
7692
            $current_browser == 'iPhone' ||
7693
            $current_browser == 'Firefox'
7694
        ) {
7695
            $result[$format] = true;
7696
7697
            return true;
7698
        } else {
7699
            $result[$format] = false;
7700
7701
            return false;
7702
        }
7703
    } elseif ($format == 'autocapitalize') {
7704
        // Help avoiding showing the autocapitalize option if the browser doesn't
7705
        // support it: this attribute is against the HTML5 standard
7706
        if ($current_browser == 'Safari' || $current_browser == 'iPhone') {
7707
            return true;
7708
        } else {
7709
            return false;
7710
        }
7711
    } elseif ($format == "check_browser") {
7712
        $array_check_browser = [$current_browser, $current_majorver];
7713
7714
        return $array_check_browser;
7715
    } else {
7716
        $result[$format] = false;
7717
7718
        return false;
7719
    }
7720
}
7721
7722
/**
7723
 * This function checks if exist path and file browscap.ini
7724
 * In order for this to work, your browscap configuration setting in php.ini
7725
 * must point to the correct location of the browscap.ini file on your system
7726
 * http://php.net/manual/en/function.get-browser.php.
7727
 *
7728
 * @return bool
7729
 *
7730
 * @author Juan Carlos Raña Trabado
7731
 */
7732
function api_check_browscap()
7733
{
7734
    $setting = ini_get('browscap');
7735
    if ($setting) {
7736
        $browser = get_browser($_SERVER['HTTP_USER_AGENT'], true);
7737
        if (strpos($setting, 'browscap.ini') && !empty($browser)) {
7738
            return true;
7739
        }
7740
    }
7741
7742
    return false;
7743
}
7744
7745
/**
7746
 * Returns the <script> HTML tag.
7747
 */
7748
function api_get_js($file)
7749
{
7750
    return '<script src="'.api_get_path(WEB_LIBRARY_PATH).'javascript/'.$file.'"></script>'."\n";
7751
}
7752
7753
/**
7754
 * Returns the <script> HTML tag.
7755
 *
7756
 * @return string
7757
 */
7758
function api_get_asset($file)
7759
{
7760
    return '<script src="'.api_get_path(WEB_PUBLIC_PATH).'assets/'.$file.'"></script>'."\n";
7761
}
7762
7763
/**
7764
 * Returns the <script> HTML tag.
7765
 *
7766
 * @param string $file
7767
 * @param string $media
7768
 *
7769
 * @return string
7770
 */
7771
function api_get_css_asset($file, $media = 'screen')
7772
{
7773
    return '<link href="'.api_get_path(WEB_PUBLIC_PATH).'assets/'.$file.'" rel="stylesheet" media="'.$media.'" type="text/css" />'."\n";
7774
}
7775
7776
/**
7777
 * Returns the <link> HTML tag.
7778
 *
7779
 * @param string $file
7780
 * @param string $media
7781
 */
7782
function api_get_css($file, $media = 'screen')
7783
{
7784
    return '<link href="'.$file.'" rel="stylesheet" media="'.$media.'" type="text/css" />'."\n";
7785
}
7786
7787
/**
7788
 * Returns the js header to include the jquery library.
7789
 */
7790
function api_get_jquery_js()
7791
{
7792
    return api_get_asset('jquery/dist/jquery.min.js');
7793
}
7794
7795
/**
7796
 * Returns the jquery path.
7797
 *
7798
 * @return string
7799
 */
7800
function api_get_jquery_web_path()
7801
{
7802
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery/dist/jquery.min.js';
7803
}
7804
7805
/**
7806
 * @return string
7807
 */
7808
function api_get_jquery_ui_js_web_path()
7809
{
7810
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery-ui/jquery-ui.min.js';
7811
}
7812
7813
/**
7814
 * @return string
7815
 */
7816
function api_get_jquery_ui_css_web_path()
7817
{
7818
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery-ui/themes/smoothness/jquery-ui.min.css';
7819
}
7820
7821
/**
7822
 * Returns the jquery-ui library js headers.
7823
 *
7824
 * @param   bool    add the jqgrid library
7825
 *
7826
 * @return string html tags
7827
 */
7828
function api_get_jquery_ui_js($include_jqgrid = false)
7829
{
7830
    $libraries = [];
7831
    if ($include_jqgrid) {
7832
        $libraries[] = 'jqgrid';
7833
    }
7834
7835
    return api_get_jquery_libraries_js($libraries);
7836
}
7837
7838
function api_get_jqgrid_js()
7839
{
7840
    return api_get_jquery_libraries_js(['jqgrid']);
7841
}
7842
7843
/**
7844
 * Returns the jquery library js and css headers.
7845
 *
7846
 * @param   array   list of jquery libraries supported jquery-ui, jqgrid
7847
 * @param   bool    add the jquery library
7848
 *
7849
 * @return string html tags
7850
 */
7851
function api_get_jquery_libraries_js($libraries)
7852
{
7853
    $js = '';
7854
    $js_path = api_get_path(WEB_LIBRARY_PATH).'javascript/';
7855
7856
    //jqgrid js and css
7857
    if (in_array('jqgrid', $libraries)) {
7858
        $languaje = 'en';
7859
        $platform_isocode = strtolower(api_get_language_isocode());
7860
7861
        //languages supported by jqgrid see files in main/inc/lib/javascript/jqgrid/js/i18n
7862
        $jqgrid_langs = [
7863
            'bg', 'bg1251', 'cat', 'cn', 'cs', 'da', 'de', 'el', 'en', 'es', 'fa', 'fi', 'fr', 'gl', 'he', 'hu', 'is', 'it', 'ja', 'nl', 'no', 'pl', 'pt-br', 'pt', 'ro', 'ru', 'sk', 'sr', 'sv', 'tr', 'ua',
7864
        ];
7865
7866
        if (in_array($platform_isocode, $jqgrid_langs)) {
7867
            $languaje = $platform_isocode;
7868
        }
7869
        //$js .= '<link rel="stylesheet" href="'.$js_path.'jqgrid/css/ui.jqgrid.css" type="text/css">';
7870
        $js .= api_get_css($js_path.'jqgrid/css/ui.jqgrid.css');
7871
        $js .= api_get_js('jqgrid/js/i18n/grid.locale-'.$languaje.'.js');
7872
        $js .= api_get_js('jqgrid/js/jquery.jqGrid.min.js');
7873
    }
7874
7875
    //Document multiple upload funcionality
7876
    if (in_array('jquery-upload', $libraries)) {
7877
        $js .= api_get_asset('blueimp-load-image/js/load-image.all.min.js');
7878
        $js .= api_get_asset('blueimp-canvas-to-blob/js/canvas-to-blob.min.js');
7879
        $js .= api_get_asset('jquery-file-upload/js/jquery.iframe-transport.js');
7880
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload.js');
7881
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-process.js');
7882
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-image.js');
7883
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-audio.js');
7884
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-video.js');
7885
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-validate.js');
7886
7887
        $js .= api_get_css(api_get_path(WEB_PUBLIC_PATH).'assets/jquery-file-upload/css/jquery.fileupload.css');
7888
        $js .= api_get_css(api_get_path(WEB_PUBLIC_PATH).'assets/jquery-file-upload/css/jquery.fileupload-ui.css');
7889
    }
7890
7891
    // jquery datepicker
7892
    if (in_array('datepicker', $libraries)) {
7893
        $languaje = 'en-GB';
7894
        $platform_isocode = strtolower(api_get_language_isocode());
7895
7896
        // languages supported by jqgrid see files in main/inc/lib/javascript/jqgrid/js/i18n
7897
        $datapicker_langs = [
7898
            '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',
7899
        ];
7900
        if (in_array($platform_isocode, $datapicker_langs)) {
7901
            $languaje = $platform_isocode;
7902
        }
7903
7904
        $js .= api_get_js('jquery-ui/jquery-ui-i18n.min.js');
7905
        $script = '<script>
7906
        $(function(){
7907
            $.datepicker.setDefaults($.datepicker.regional["'.$languaje.'"]);
7908
            $.datepicker.regional["local"] = $.datepicker.regional["'.$languaje.'"];
7909
        });
7910
        </script>
7911
        ';
7912
        $js .= $script;
7913
    }
7914
7915
    return $js;
7916
}
7917
7918
/**
7919
 * Returns the URL to the course or session, removing the complexity of the URL
7920
 * building piece by piece.
7921
 *
7922
 * This function relies on api_get_course_info()
7923
 *
7924
 * @param string $courseCode The course code - optional (takes it from context if not given)
7925
 * @param int    $sessionId  The session ID  - optional (takes it from context if not given)
7926
 * @param int    $groupId    The group ID - optional (takes it from context if not given)
7927
 *
7928
 * @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
7929
 *
7930
 * @author  Julio Montoya <[email protected]>
7931
 */
7932
function api_get_course_url($courseCode = null, $sessionId = null, $groupId = null)
7933
{
7934
    $courseDirectory = '';
7935
    $url = '';
7936
    // If courseCode not set, get context or []
7937
    if (empty($courseCode)) {
7938
        $courseInfo = api_get_course_info();
7939
    } else {
7940
        $courseInfo = api_get_course_info($courseCode);
7941
    }
7942
7943
    // If course defined, get directory, otherwise keep empty string
7944
    if (!empty($courseInfo['directory'])) {
7945
        $courseDirectory = $courseInfo['directory'];
7946
    }
7947
7948
    // If sessionId not set, get context or 0
7949
    if (empty($sessionId)) {
7950
        $sessionId = api_get_session_id();
7951
    }
7952
7953
    // If groupId not set, get context or 0
7954
    if (empty($groupId)) {
7955
        $groupId = api_get_group_id();
7956
    }
7957
7958
    // Build the URL
7959
    if (!empty($courseDirectory)) {
7960
        // directory not empty, so we do have a course
7961
        $url = api_get_path(WEB_COURSE_PATH).$courseDirectory.'/index.php?id_session='.$sessionId.'&gidReq='.$groupId;
7962
    } elseif (!empty($sessionId) && api_get_configuration_value('remove_session_url') !== true) {
7963
        // if the course was unset and the session was set, send directly to the session
7964
        $url = api_get_path(WEB_CODE_PATH).'session/index.php?session_id='.$sessionId;
7965
    }
7966
    // if not valid combination was found, return an empty string
7967
    return $url;
7968
}
7969
7970
/**
7971
 * Check if the current portal has the $_configuration['multiple_access_urls'] parameter on.
7972
 *
7973
 * @return bool true if multi site is enabled
7974
 */
7975
function api_get_multiple_access_url()
7976
{
7977
    global $_configuration;
7978
    if (isset($_configuration['multiple_access_urls']) && $_configuration['multiple_access_urls']) {
7979
        return true;
7980
    }
7981
7982
    return false;
7983
}
7984
7985
/**
7986
 * Just a synonym for api_get_multiple_access_url().
7987
 *
7988
 * @return bool
7989
 */
7990
function api_is_multiple_url_enabled()
7991
{
7992
    return api_get_multiple_access_url();
7993
}
7994
7995
/**
7996
 * Returns a md5 unique id.
7997
 *
7998
 * @todo add more parameters
7999
 */
8000
function api_get_unique_id()
8001
{
8002
    $id = md5(time().uniqid().api_get_user_id().api_get_course_id().api_get_session_id());
8003
8004
    return $id;
8005
}
8006
8007
/**
8008
 * Get home path.
8009
 *
8010
 * @return string
8011
 */
8012
function api_get_home_path()
8013
{
8014
    // FIX : Start the routing determination from central path definition
8015
    $home = api_get_path(SYS_HOME_PATH);
8016
    if (api_get_multiple_access_url()) {
8017
        $access_url_id = api_get_current_access_url_id();
8018
        $url_info = api_get_access_url($access_url_id);
8019
        $url = api_remove_trailing_slash(preg_replace('/https?:\/\//i', '', $url_info['url']));
8020
        $clean_url = api_replace_dangerous_char($url);
8021
        $clean_url = str_replace('/', '-', $clean_url);
8022
        $clean_url .= '/';
8023
        if ($clean_url != 'localhost/') {
8024
            // means that the multiple URL was not well configured we don't rename the $home variable
8025
            return "{$home}{$clean_url}";
8026
        }
8027
    }
8028
8029
    return $home;
8030
}
8031
8032
/**
8033
 * @param int Course id
8034
 * @param int tool id: TOOL_QUIZ, TOOL_FORUM, TOOL_STUDENTPUBLICATION, TOOL_LEARNPATH
8035
 * @param int the item id (tool id, exercise id, lp id)
8036
 *
8037
 * @return bool
8038
 */
8039
function api_resource_is_locked_by_gradebook($item_id, $link_type, $course_code = null)
8040
{
8041
    if (api_is_platform_admin()) {
8042
        return false;
8043
    }
8044
    if (api_get_setting('gradebook_locking_enabled') == 'true') {
8045
        if (empty($course_code)) {
8046
            $course_code = api_get_course_id();
8047
        }
8048
        $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_LINK);
8049
        $item_id = intval($item_id);
8050
        $link_type = intval($link_type);
8051
        $course_code = Database::escape_string($course_code);
8052
        $sql = "SELECT locked FROM $table
8053
                WHERE locked = 1 AND ref_id = $item_id AND type = $link_type AND course_code = '$course_code' ";
8054
        $result = Database::query($sql);
8055
        if (Database::num_rows($result)) {
8056
            return true;
8057
        }
8058
    }
8059
8060
    return false;
8061
}
8062
8063
/**
8064
 * Blocks a page if the item was added in a gradebook.
8065
 *
8066
 * @param int       exercise id, work id, thread id,
8067
 * @param int       LINK_EXERCISE, LINK_STUDENTPUBLICATION, LINK_LEARNPATH LINK_FORUM_THREAD, LINK_ATTENDANCE
8068
 * see gradebook/lib/be/linkfactory
8069
 * @param string    course code
8070
 *
8071
 * @return false|null
8072
 */
8073
function api_block_course_item_locked_by_gradebook($item_id, $link_type, $course_code = null)
8074
{
8075
    if (api_is_platform_admin()) {
8076
        return false;
8077
    }
8078
8079
    if (api_resource_is_locked_by_gradebook($item_id, $link_type, $course_code)) {
8080
        $message = Display::return_message(get_lang('ResourceLockedByGradebook'), 'warning');
8081
        api_not_allowed(true, $message);
8082
    }
8083
}
8084
8085
/**
8086
 * Checks the PHP version installed is enough to run Chamilo.
8087
 *
8088
 * @param string Include path (used to load the error page)
8089
 */
8090
function api_check_php_version($my_inc_path = null)
8091
{
8092
    if (!function_exists('version_compare') || version_compare(phpversion(), REQUIRED_PHP_VERSION, '<')) {
8093
        $global_error_code = 1;
8094
        // Incorrect PHP version
8095
        $global_page = $my_inc_path.'global_error_message.inc.php';
8096
        if (file_exists($global_page)) {
8097
            require $global_page;
8098
        }
8099
        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...
8100
    }
8101
}
8102
8103
/**
8104
 * Checks whether the Archive directory is present and writeable. If not,
8105
 * prints a warning message.
8106
 */
8107
function api_check_archive_dir()
8108
{
8109
    if (is_dir(api_get_path(SYS_ARCHIVE_PATH)) && !is_writable(api_get_path(SYS_ARCHIVE_PATH))) {
8110
        $message = Display::return_message(get_lang('ArchivesDirectoryNotWriteableContactAdmin'), 'warning');
8111
        api_not_allowed(true, $message);
8112
    }
8113
}
8114
8115
/**
8116
 * Returns an array of global configuration settings which should be ignored
8117
 * when printing the configuration settings screens.
8118
 *
8119
 * @return array Array of strings, each identifying one of the excluded settings
8120
 */
8121
function api_get_locked_settings()
8122
{
8123
    return [
8124
        'server_type',
8125
        'permanently_remove_deleted_files',
8126
        'account_valid_duration',
8127
        'service_ppt2lp',
8128
        'wcag_anysurfer_public_pages',
8129
        'upload_extensions_list_type',
8130
        'upload_extensions_blacklist',
8131
        'upload_extensions_whitelist',
8132
        'upload_extensions_skip',
8133
        'upload_extensions_replace_by',
8134
        'hide_dltt_markup',
8135
        'split_users_upload_directory',
8136
        'permissions_for_new_directories',
8137
        'permissions_for_new_files',
8138
        'platform_charset',
8139
        'ldap_description',
8140
        'cas_activate',
8141
        'cas_server',
8142
        'cas_server_uri',
8143
        'cas_port',
8144
        'cas_protocol',
8145
        'cas_add_user_activate',
8146
        'update_user_info_cas_with_ldap',
8147
        'languagePriority1',
8148
        'languagePriority2',
8149
        'languagePriority3',
8150
        'languagePriority4',
8151
        'login_is_email',
8152
        'chamilo_database_version',
8153
    ];
8154
}
8155
8156
/**
8157
 * Checks if the user is corrently logged in. Returns the user ID if he is, or
8158
 * false if he isn't. If the user ID is given and is an integer, then the same
8159
 * ID is simply returned.
8160
 *
8161
 * @param  int User ID
8162
 *
8163
 * @return bool Integer User ID is logged in, or false otherwise
8164
 */
8165
function api_user_is_login($user_id = null)
8166
{
8167
    $user_id = empty($user_id) ? api_get_user_id() : (int) $user_id;
8168
8169
    return $user_id && !api_is_anonymous();
8170
}
8171
8172
/**
8173
 * Guess the real ip for register in the database, even in reverse proxy cases.
8174
 * To be recognized, the IP has to be found in either $_SERVER['REMOTE_ADDR'] or
8175
 * in $_SERVER['HTTP_X_FORWARDED_FOR'], which is in common use with rproxies.
8176
 * Note: the result of this function is not SQL-safe. Please escape it before
8177
 * inserting in a database.
8178
 *
8179
 * @return string the user's real ip (unsafe - escape it before inserting to db)
8180
 *
8181
 * @author Jorge Frisancho Jibaja <[email protected]>, USIL - Some changes to allow the use of real IP using reverse proxy
8182
 *
8183
 * @version CEV CHANGE 24APR2012
8184
 */
8185
function api_get_real_ip()
8186
{
8187
    $ip = trim($_SERVER['REMOTE_ADDR']);
8188
    if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
8189
        if (preg_match('/,/', $_SERVER['HTTP_X_FORWARDED_FOR'])) {
8190
            @list($ip1, $ip2) = @explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
8191
        } else {
8192
            $ip1 = $_SERVER['HTTP_X_FORWARDED_FOR'];
8193
        }
8194
        $ip = trim($ip1);
8195
    }
8196
8197
    return $ip;
8198
}
8199
8200
/**
8201
 * Checks whether an IP is included inside an IP range.
8202
 *
8203
 * @param string IP address
8204
 * @param string IP range
8205
 * @param string $ip
8206
 *
8207
 * @return bool True if IP is in the range, false otherwise
8208
 *
8209
 * @author claudiu at cnixs dot com  on http://www.php.net/manual/fr/ref.network.php#55230
8210
 * @author Yannick Warnier for improvements and managment of multiple ranges
8211
 *
8212
 * @todo check for IPv6 support
8213
 */
8214
function api_check_ip_in_range($ip, $range)
8215
{
8216
    if (empty($ip) or empty($range)) {
8217
        return false;
8218
    }
8219
    $ip_ip = ip2long($ip);
8220
    // divide range param into array of elements
8221
    if (strpos($range, ',') !== false) {
8222
        $ranges = explode(',', $range);
8223
    } else {
8224
        $ranges = [$range];
8225
    }
8226
    foreach ($ranges as $range) {
0 ignored issues
show
introduced by
$range is overwriting one of the parameters of this function.
Loading history...
8227
        $range = trim($range);
8228
        if (empty($range)) {
8229
            continue;
8230
        }
8231
        if (strpos($range, '/') === false) {
8232
            if (strcmp($ip, $range) === 0) {
8233
                return true; // there is a direct IP match, return OK
8234
            }
8235
            continue; //otherwise, get to the next range
8236
        }
8237
        // the range contains a "/", so analyse completely
8238
        list($net, $mask) = explode("/", $range);
8239
8240
        $ip_net = ip2long($net);
8241
        // mask binary magic
8242
        $ip_mask = ~((1 << (32 - $mask)) - 1);
8243
8244
        $ip_ip_net = $ip_ip & $ip_mask;
8245
        if ($ip_ip_net == $ip_net) {
8246
            return true;
8247
        }
8248
    }
8249
8250
    return false;
8251
}
8252
8253
function api_check_user_access_to_legal($courseInfo)
8254
{
8255
    if (empty($courseInfo)) {
8256
        return false;
8257
    }
8258
8259
    $visibility = (int) $courseInfo['visibility'];
8260
    $visibilityList = [COURSE_VISIBILITY_OPEN_WORLD, COURSE_VISIBILITY_OPEN_PLATFORM];
8261
8262
    return
8263
        in_array($visibility, $visibilityList) ||
8264
        api_is_drh() ||
8265
        (COURSE_VISIBILITY_REGISTERED === $visibility && 1 === (int) $courseInfo['subscribe']);
8266
}
8267
8268
/**
8269
 * Checks if the global chat is enabled or not.
8270
 *
8271
 * @return bool
8272
 */
8273
function api_is_global_chat_enabled()
8274
{
8275
    return
8276
        !api_is_anonymous() &&
8277
        api_get_setting('allow_global_chat') === 'true' &&
8278
        api_get_setting('allow_social_tool') === 'true';
8279
}
8280
8281
/**
8282
 * @todo Fix tool_visible_by_default_at_creation labels
8283
 *
8284
 * @param int   $item_id
8285
 * @param int   $tool_id
8286
 * @param int   $group_id   id
8287
 * @param array $courseInfo
8288
 * @param int   $sessionId
8289
 * @param int   $userId
8290
 */
8291
function api_set_default_visibility(
8292
    $item_id,
8293
    $tool_id,
8294
    $group_id = 0,
8295
    $courseInfo = [],
8296
    $sessionId = 0,
8297
    $userId = 0
8298
) {
8299
    $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
8300
    $courseId = $courseInfo['real_id'];
8301
    $courseCode = $courseInfo['code'];
8302
    $sessionId = empty($sessionId) ? api_get_session_id() : $sessionId;
8303
    $userId = empty($userId) ? api_get_user_id() : $userId;
8304
8305
    // if group is null force group_id = 0, this force is needed to create a LP folder with group = 0
8306
    if (is_null($group_id)) {
8307
        $group_id = 0;
8308
    } else {
8309
        $group_id = empty($group_id) ? api_get_group_id() : $group_id;
8310
    }
8311
8312
    $groupInfo = [];
8313
    if (!empty($group_id)) {
8314
        $groupInfo = GroupManager::get_group_properties($group_id);
8315
    }
8316
    $original_tool_id = $tool_id;
8317
8318
    switch ($tool_id) {
8319
        case TOOL_LINK:
8320
        case TOOL_LINK_CATEGORY:
8321
            $tool_id = 'links';
8322
            break;
8323
        case TOOL_DOCUMENT:
8324
            $tool_id = 'documents';
8325
            break;
8326
        case TOOL_LEARNPATH:
8327
            $tool_id = 'learning';
8328
            break;
8329
        case TOOL_ANNOUNCEMENT:
8330
            $tool_id = 'announcements';
8331
            break;
8332
        case TOOL_FORUM:
8333
        case TOOL_FORUM_CATEGORY:
8334
        case TOOL_FORUM_THREAD:
8335
            $tool_id = 'forums';
8336
            break;
8337
        case TOOL_QUIZ:
8338
            $tool_id = 'quiz';
8339
            break;
8340
    }
8341
    $setting = api_get_setting('tool_visible_by_default_at_creation');
8342
8343
    if (isset($setting[$tool_id])) {
8344
        $visibility = 'invisible';
8345
        if ($setting[$tool_id] == 'true') {
8346
            $visibility = 'visible';
8347
        }
8348
8349
        // Read the portal and course default visibility
8350
        if ($tool_id === 'documents') {
8351
            $visibility = DocumentManager::getDocumentDefaultVisibility($courseInfo);
8352
        }
8353
8354
        api_item_property_update(
8355
            $courseInfo,
8356
            $original_tool_id,
8357
            $item_id,
8358
            $visibility,
8359
            $userId,
8360
            $groupInfo,
8361
            null,
8362
            null,
8363
            null,
8364
            $sessionId
8365
        );
8366
8367
        // Fixes default visibility for tests
8368
        switch ($original_tool_id) {
8369
            case TOOL_QUIZ:
8370
                if (empty($sessionId)) {
8371
                    $objExerciseTmp = new Exercise($courseId);
8372
                    $objExerciseTmp->read($item_id);
8373
                    if ($visibility == 'visible') {
8374
                        $objExerciseTmp->enable();
8375
                        $objExerciseTmp->save();
8376
                    } else {
8377
                        $objExerciseTmp->disable();
8378
                        $objExerciseTmp->save();
8379
                    }
8380
                }
8381
                break;
8382
        }
8383
    }
8384
}
8385
8386
/**
8387
 * @return string
8388
 */
8389
function api_get_security_key()
8390
{
8391
    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...
8392
}
8393
8394
/**
8395
 * @param int $user_id
8396
 * @param int $courseId
8397
 * @param int $session_id
8398
 *
8399
 * @return array
8400
 */
8401
function api_detect_user_roles($user_id, $courseId, $session_id = 0)
8402
{
8403
    $user_roles = [];
8404
    $courseInfo = api_get_course_info_by_id($courseId);
8405
    $course_code = $courseInfo['code'];
8406
8407
    $url_id = api_get_current_access_url_id();
8408
    if (api_is_platform_admin_by_id($user_id, $url_id)) {
8409
        $user_roles[] = PLATFORM_ADMIN;
8410
    }
8411
8412
    /*if (api_is_drh()) {
8413
        $user_roles[] = DRH;
8414
    }*/
8415
8416
    if (!empty($session_id)) {
8417
        if (SessionManager::user_is_general_coach($user_id, $session_id)) {
8418
            $user_roles[] = SESSION_GENERAL_COACH;
8419
        }
8420
    }
8421
8422
    if (!empty($course_code)) {
8423
        if (empty($session_id)) {
8424
            if (CourseManager::is_course_teacher($user_id, $course_code)) {
8425
                $user_roles[] = COURSEMANAGER;
8426
            }
8427
            if (CourseManager::get_tutor_in_course_status($user_id, $courseInfo['real_id'])) {
8428
                $user_roles[] = COURSE_TUTOR;
8429
            }
8430
8431
            if (CourseManager::is_user_subscribed_in_course($user_id, $course_code)) {
8432
                $user_roles[] = COURSE_STUDENT;
8433
            }
8434
        } else {
8435
            $user_status_in_session = SessionManager::get_user_status_in_course_session(
8436
                $user_id,
8437
                $courseId,
8438
                $session_id
8439
            );
8440
8441
            if (!empty($user_status_in_session)) {
8442
                if ($user_status_in_session == 0) {
8443
                    $user_roles[] = SESSION_STUDENT;
8444
                }
8445
                if ($user_status_in_session == 2) {
8446
                    $user_roles[] = SESSION_COURSE_COACH;
8447
                }
8448
            }
8449
8450
            /*if (api_is_course_session_coach($user_id, $course_code, $session_id)) {
8451
               $user_roles[] = SESSION_COURSE_COACH;
8452
            }*/
8453
        }
8454
    }
8455
8456
    return $user_roles;
8457
}
8458
8459
/**
8460
 * @param int $courseId
8461
 * @param int $session_id
8462
 *
8463
 * @return bool
8464
 */
8465
function api_coach_can_edit_view_results($courseId = null, $session_id = null)
8466
{
8467
    if (api_is_platform_admin()) {
8468
        return true;
8469
    }
8470
8471
    $user_id = api_get_user_id();
8472
8473
    if (empty($courseId)) {
8474
        $courseId = api_get_course_int_id();
8475
    }
8476
8477
    if (empty($session_id)) {
8478
        $session_id = api_get_session_id();
8479
    }
8480
8481
    $roles = api_detect_user_roles($user_id, $courseId, $session_id);
8482
8483
    if (in_array(SESSION_COURSE_COACH, $roles)) {
8484
        //return api_get_setting('session_tutor_reports_visibility') == 'true';
8485
        return true;
8486
    } else {
8487
        if (in_array(COURSEMANAGER, $roles)) {
8488
            return true;
8489
        }
8490
8491
        return false;
8492
    }
8493
}
8494
8495
/**
8496
 * @param string $file
8497
 *
8498
 * @return string
8499
 */
8500
function api_get_js_simple($file)
8501
{
8502
    return '<script src="'.$file.'"></script>'."\n";
8503
}
8504
8505
function api_set_settings_and_plugins()
8506
{
8507
    global $_configuration;
8508
    $_setting = [];
8509
    $_plugins = [];
8510
8511
    // access_url == 1 is the default chamilo location
8512
    $settings_by_access_list = [];
8513
    $access_url_id = api_get_current_access_url_id();
8514
    if ($access_url_id != 1) {
8515
        $url_info = api_get_access_url($_configuration['access_url']);
8516
        if ($url_info['active'] == 1) {
8517
            $settings_by_access = api_get_settings(null, 'list', $_configuration['access_url'], 1);
8518
            foreach ($settings_by_access as &$row) {
8519
                if (empty($row['variable'])) {
8520
                    $row['variable'] = 0;
8521
                }
8522
                if (empty($row['subkey'])) {
8523
                    $row['subkey'] = 0;
8524
                }
8525
                if (empty($row['category'])) {
8526
                    $row['category'] = 0;
8527
                }
8528
                $settings_by_access_list[$row['variable']][$row['subkey']][$row['category']] = $row;
8529
            }
8530
        }
8531
    }
8532
8533
    $result = api_get_settings(null, 'list', 1);
8534
8535
    foreach ($result as &$row) {
8536
        if ($access_url_id != 1) {
8537
            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...
8538
                $var = empty($row['variable']) ? 0 : $row['variable'];
8539
                $subkey = empty($row['subkey']) ? 0 : $row['subkey'];
8540
                $category = empty($row['category']) ? 0 : $row['category'];
8541
            }
8542
8543
            if ($row['access_url_changeable'] == 1 && $url_info['active'] == 1) {
8544
                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...
8545
                    $settings_by_access_list[$var][$subkey][$category]['selected_value'] != '') {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $category does not seem to be defined for all execution paths leading up to this point.
Loading history...
Comprehensibility Best Practice introduced by
The variable $subkey does not seem to be defined for all execution paths leading up to this point.
Loading history...
8546
                    if ($row['subkey'] == null) {
8547
                        $_setting[$row['variable']] = $settings_by_access_list[$var][$subkey][$category]['selected_value'];
8548
                    } else {
8549
                        $_setting[$row['variable']][$row['subkey']] = $settings_by_access_list[$var][$subkey][$category]['selected_value'];
8550
                    }
8551
                } else {
8552
                    if ($row['subkey'] == null) {
8553
                        $_setting[$row['variable']] = $row['selected_value'];
8554
                    } else {
8555
                        $_setting[$row['variable']][$row['subkey']] = $row['selected_value'];
8556
                    }
8557
                }
8558
            } else {
8559
                if ($row['subkey'] == null) {
8560
                    $_setting[$row['variable']] = $row['selected_value'];
8561
                } else {
8562
                    $_setting[$row['variable']][$row['subkey']] = $row['selected_value'];
8563
                }
8564
            }
8565
        } else {
8566
            if ($row['subkey'] == null) {
8567
                $_setting[$row['variable']] = $row['selected_value'];
8568
            } else {
8569
                $_setting[$row['variable']][$row['subkey']] = $row['selected_value'];
8570
            }
8571
        }
8572
    }
8573
8574
    $result = api_get_settings('Plugins', 'list', $access_url_id);
8575
    $_plugins = [];
8576
    foreach ($result as &$row) {
8577
        $key = &$row['variable'];
8578
        if (is_string($_setting[$key])) {
8579
            $_setting[$key] = [];
8580
        }
8581
        $_setting[$key][] = $row['selected_value'];
8582
        $_plugins[$key][] = $row['selected_value'];
8583
    }
8584
8585
    $_SESSION['_setting'] = $_setting;
8586
    $_SESSION['_plugins'] = $_plugins;
8587
}
8588
8589
/**
8590
 * Modify default memory_limit and max_execution_time limits
8591
 * Needed when processing long tasks.
8592
 */
8593
function api_set_more_memory_and_time_limits()
8594
{
8595
    if (function_exists('ini_set')) {
8596
        api_set_memory_limit('2048M');
8597
        ini_set('max_execution_time', 3600);
8598
    }
8599
}
8600
8601
/**
8602
 * Tries to set memory limit, if authorized and new limit is higher than current.
8603
 *
8604
 * @param string $mem New memory limit
8605
 *
8606
 * @return bool True on success, false on failure or current is higher than suggested
8607
 * @assert (null) === false
8608
 * @assert (-1) === false
8609
 * @assert (0) === true
8610
 * @assert ('1G') === true
8611
 */
8612
function api_set_memory_limit($mem)
8613
{
8614
    //if ini_set() not available, this function is useless
8615
    if (!function_exists('ini_set') || is_null($mem) || $mem == -1) {
8616
        return false;
8617
    }
8618
8619
    $memory_limit = ini_get('memory_limit');
8620
    if (api_get_bytes_memory_limit($mem) > api_get_bytes_memory_limit($memory_limit)) {
8621
        ini_set('memory_limit', $mem);
8622
8623
        return true;
8624
    }
8625
8626
    return false;
8627
}
8628
8629
/**
8630
 * Gets memory limit in bytes.
8631
 *
8632
 * @param string The memory size (128M, 1G, 1000K, etc)
8633
 *
8634
 * @return int
8635
 * @assert (null) === false
8636
 * @assert ('1t')  === 1099511627776
8637
 * @assert ('1g')  === 1073741824
8638
 * @assert ('1m')  === 1048576
8639
 * @assert ('100k') === 102400
8640
 */
8641
function api_get_bytes_memory_limit($mem)
8642
{
8643
    $size = strtolower(substr($mem, -1));
8644
8645
    switch ($size) {
8646
        case 't':
8647
            $mem = intval(substr($mem, -1)) * 1024 * 1024 * 1024 * 1024;
8648
            break;
8649
        case 'g':
8650
            $mem = intval(substr($mem, 0, -1)) * 1024 * 1024 * 1024;
8651
            break;
8652
        case 'm':
8653
            $mem = intval(substr($mem, 0, -1)) * 1024 * 1024;
8654
            break;
8655
        case 'k':
8656
            $mem = intval(substr($mem, 0, -1)) * 1024;
8657
            break;
8658
        default:
8659
            // we assume it's integer only
8660
            $mem = intval($mem);
8661
            break;
8662
    }
8663
8664
    return $mem;
8665
}
8666
8667
/**
8668
 * Finds all the information about a user from username instead of user id.
8669
 *
8670
 * @param string $officialCode
8671
 *
8672
 * @return array $user_info user_id, lastname, firstname, username, email, ...
8673
 *
8674
 * @author Yannick Warnier <[email protected]>
8675
 */
8676
function api_get_user_info_from_official_code($officialCode)
8677
{
8678
    if (empty($officialCode)) {
8679
        return false;
8680
    }
8681
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
8682
            WHERE official_code ='".Database::escape_string($officialCode)."'";
8683
    $result = Database::query($sql);
8684
    if (Database::num_rows($result) > 0) {
8685
        $result_array = Database::fetch_array($result);
8686
8687
        return _api_format_user($result_array);
8688
    }
8689
8690
    return false;
8691
}
8692
8693
/**
8694
 * @param string $usernameInputId
8695
 * @param string $passwordInputId
8696
 *
8697
 * @return string|null
8698
 */
8699
function api_get_password_checker_js($usernameInputId, $passwordInputId)
8700
{
8701
    $checkPass = api_get_setting('allow_strength_pass_checker');
8702
    $useStrengthPassChecker = $checkPass === 'true';
8703
8704
    if ($useStrengthPassChecker === false) {
8705
        return null;
8706
    }
8707
8708
    $minRequirements = Security::getPasswordRequirements()['min'];
8709
8710
    $options = [
8711
        'rules' => [],
8712
    ];
8713
8714
    if ($minRequirements['length'] > 0) {
8715
        $options['rules'][] = [
8716
            'minChar' => $minRequirements['length'],
8717
            'pattern' => '.',
8718
            'helpText' => sprintf(
8719
                get_lang('NewPasswordRequirementMinXLength'),
8720
                $minRequirements['length']
8721
            ),
8722
        ];
8723
    }
8724
8725
    if ($minRequirements['lowercase'] > 0) {
8726
        $options['rules'][] = [
8727
            'minChar' => $minRequirements['lowercase'],
8728
            'pattern' => '[a-z]',
8729
            'helpText' => sprintf(
8730
                get_lang('NewPasswordRequirementMinXLowercase'),
8731
                $minRequirements['lowercase']
8732
            ),
8733
        ];
8734
    }
8735
8736
    if ($minRequirements['uppercase'] > 0) {
8737
        $options['rules'][] = [
8738
            'minChar' => $minRequirements['uppercase'],
8739
            'pattern' => '[A-Z]',
8740
            'helpText' => sprintf(
8741
                get_lang('NewPasswordRequirementMinXUppercase'),
8742
                $minRequirements['uppercase']
8743
            ),
8744
        ];
8745
    }
8746
8747
    if ($minRequirements['numeric'] > 0) {
8748
        $options['rules'][] = [
8749
            'minChar' => $minRequirements['numeric'],
8750
            'pattern' => '[0-9]',
8751
            'helpText' => sprintf(
8752
                get_lang('NewPasswordRequirementMinXNumeric'),
8753
                $minRequirements['numeric']
8754
            ),
8755
        ];
8756
    }
8757
8758
    if ($minRequirements['specials'] > 0) {
8759
        $options['rules'][] = [
8760
            'minChar' => $minRequirements['specials'],
8761
            'pattern' => '[!"#$%&\'()*+,\-./\\\:;<=>?@[\\]^_`{|}~]',
8762
            'helpText' => sprintf(
8763
                get_lang('NewPasswordRequirementMinXSpecials'),
8764
                $minRequirements['specials']
8765
            ),
8766
        ];
8767
    }
8768
8769
    $js = api_get_js('password-checker/password-checker.js');
8770
    $js .= "<script>
8771
    $(function() {
8772
        $('".$passwordInputId."').passwordChecker(".json_encode($options).");
8773
    });
8774
    </script>";
8775
8776
    return $js;
8777
}
8778
8779
/**
8780
 * create an user extra field called 'captcha_blocked_until_date'.
8781
 *
8782
 * @param string $username
8783
 *
8784
 * @return bool
8785
 */
8786
function api_block_account_captcha($username)
8787
{
8788
    $userInfo = api_get_user_info_from_username($username);
8789
    if (empty($userInfo)) {
8790
        return false;
8791
    }
8792
    $minutesToBlock = api_get_setting('captcha_time_to_block');
8793
    $time = time() + $minutesToBlock * 60;
8794
    UserManager::update_extra_field_value(
8795
        $userInfo['user_id'],
8796
        'captcha_blocked_until_date',
8797
        api_get_utc_datetime($time)
8798
    );
8799
8800
    return true;
8801
}
8802
8803
/**
8804
 * @param string $username
8805
 *
8806
 * @return bool
8807
 */
8808
function api_clean_account_captcha($username)
8809
{
8810
    $userInfo = api_get_user_info_from_username($username);
8811
    if (empty($userInfo)) {
8812
        return false;
8813
    }
8814
    Session::erase('loginFailedCount');
8815
    UserManager::update_extra_field_value(
8816
        $userInfo['user_id'],
8817
        'captcha_blocked_until_date',
8818
        null
8819
    );
8820
8821
    return true;
8822
}
8823
8824
/**
8825
 * @param string $username
8826
 *
8827
 * @return bool
8828
 */
8829
function api_get_user_blocked_by_captcha($username)
8830
{
8831
    $userInfo = api_get_user_info_from_username($username);
8832
    if (empty($userInfo)) {
8833
        return false;
8834
    }
8835
    $data = UserManager::get_extra_user_data_by_field(
8836
        $userInfo['user_id'],
8837
        'captcha_blocked_until_date'
8838
    );
8839
    if (isset($data) && isset($data['captcha_blocked_until_date'])) {
8840
        return $data['captcha_blocked_until_date'];
8841
    }
8842
8843
    return false;
8844
}
8845
8846
/**
8847
 * Remove tags from HTML anf return the $in_number_char first non-HTML char
8848
 * Postfix the text with "..." if it has been truncated.
8849
 *
8850
 * @param string $text
8851
 * @param int    $number
8852
 *
8853
 * @return string
8854
 *
8855
 * @author hubert borderiou
8856
 */
8857
function api_get_short_text_from_html($text, $number)
8858
{
8859
    // Delete script and style tags
8860
    $text = preg_replace('/(<(script|style)\b[^>]*>).*?(<\/\2>)/is', "$1$3", $text);
8861
    $text = api_html_entity_decode($text);
8862
    $out_res = api_remove_tags_with_space($text, false);
8863
    $postfix = "...";
8864
    if (strlen($out_res) > $number) {
8865
        $out_res = substr($out_res, 0, $number).$postfix;
8866
    }
8867
8868
    return $out_res;
8869
}
8870
8871
/**
8872
 * Replace tags with a space in a text.
8873
 * If $in_double_quote_replace, replace " with '' (for HTML attribute purpose, for exemple).
8874
 *
8875
 * @return string
8876
 *
8877
 * @author hubert borderiou
8878
 */
8879
function api_remove_tags_with_space($in_html, $in_double_quote_replace = true)
8880
{
8881
    $out_res = $in_html;
8882
    if ($in_double_quote_replace) {
8883
        $out_res = str_replace('"', "''", $out_res);
8884
    }
8885
    // avoid text stuck together when tags are removed, adding a space after >
8886
    $out_res = str_replace(">", "> ", $out_res);
8887
    $out_res = strip_tags($out_res);
8888
8889
    return $out_res;
8890
}
8891
8892
/**
8893
 * If true, the drh can access all content (courses, users) inside a session.
8894
 *
8895
 * @return bool
8896
 */
8897
function api_drh_can_access_all_session_content()
8898
{
8899
    return api_get_setting('drh_can_access_all_session_content') === 'true';
8900
}
8901
8902
/**
8903
 * @param string $tool
8904
 * @param string $setting
8905
 * @param int    $defaultValue
8906
 *
8907
 * @return string
8908
 */
8909
function api_get_default_tool_setting($tool, $setting, $defaultValue)
8910
{
8911
    global $_configuration;
8912
    if (isset($_configuration[$tool]) &&
8913
        isset($_configuration[$tool]['default_settings']) &&
8914
        isset($_configuration[$tool]['default_settings'][$setting])
8915
    ) {
8916
        return $_configuration[$tool]['default_settings'][$setting];
8917
    }
8918
8919
    return $defaultValue;
8920
}
8921
8922
/**
8923
 * Checks if user can login as another user.
8924
 *
8925
 * @param int $loginAsUserId the user id to log in
8926
 * @param int $userId        my user id
8927
 *
8928
 * @return bool
8929
 */
8930
function api_can_login_as($loginAsUserId, $userId = null)
8931
{
8932
    if (empty($userId)) {
8933
        $userId = api_get_user_id();
8934
    }
8935
    if ($loginAsUserId == $userId) {
8936
        return false;
8937
    }
8938
8939
    if (empty($loginAsUserId)) {
8940
        return false;
8941
    }
8942
8943
    if ($loginAsUserId != strval(intval($loginAsUserId))) {
8944
        return false;
8945
    }
8946
8947
    // Check if the user to login is an admin
8948
    if (api_is_platform_admin_by_id($loginAsUserId)) {
8949
        // Only super admins can login to admin accounts
8950
        if (!api_global_admin_can_edit_admin($loginAsUserId)) {
8951
            return false;
8952
        }
8953
    }
8954
8955
    $userInfo = api_get_user_info($loginAsUserId);
8956
    $isDrh = function () use ($loginAsUserId) {
8957
        if (api_is_drh()) {
8958
            if (api_drh_can_access_all_session_content()) {
8959
                $users = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus(
8960
                    'drh_all',
8961
                    api_get_user_id()
8962
                );
8963
                $userList = [];
8964
                if (is_array($users)) {
8965
                    foreach ($users as $user) {
8966
                        $userList[] = $user['user_id'];
8967
                    }
8968
                }
8969
                if (in_array($loginAsUserId, $userList)) {
8970
                    return true;
8971
                }
8972
            } else {
8973
                if (api_is_drh() &&
8974
                    UserManager::is_user_followed_by_drh($loginAsUserId, api_get_user_id())
8975
                ) {
8976
                    return true;
8977
                }
8978
            }
8979
        }
8980
8981
        return false;
8982
    };
8983
8984
    $loginAsStatusForSessionAdmins = [STUDENT];
8985
8986
    if (api_get_configuration_value('allow_session_admin_login_as_teacher')) {
8987
        $loginAsStatusForSessionAdmins[] = COURSEMANAGER;
8988
    }
8989
8990
    return api_is_platform_admin() ||
8991
        (api_is_session_admin() && in_array($userInfo['status'], $loginAsStatusForSessionAdmins)) ||
8992
        $isDrh();
8993
}
8994
8995
/**
8996
 * @return bool
8997
 */
8998
function api_is_allowed_in_course()
8999
{
9000
    if (api_is_platform_admin()) {
9001
        return true;
9002
    }
9003
9004
    return Session::read('is_allowed_in_course');
9005
}
9006
9007
function api_set_cookie($name, $value, $expires = 0)
9008
{
9009
    $expires = (int) $expires;
9010
    setcookie($name, $value, $expires, '', '', api_is_https(), true);
9011
}
9012
9013
/**
9014
 * Set the cookie to go directly to the course code $in_firstpage
9015
 * after login.
9016
 *
9017
 * @param string $value is the course code of the course to go
9018
 */
9019
function api_set_firstpage_parameter($value)
9020
{
9021
    api_set_cookie('GotoCourse', $value);
9022
}
9023
9024
/**
9025
 * Delete the cookie to go directly to the course code $in_firstpage
9026
 * after login.
9027
 */
9028
function api_delete_firstpage_parameter()
9029
{
9030
    api_set_cookie('GotoCourse', '', time() - 3600);
9031
}
9032
9033
/**
9034
 * @return bool if course_code for direct course access after login is set
9035
 */
9036
function exist_firstpage_parameter()
9037
{
9038
    return isset($_COOKIE['GotoCourse']) && $_COOKIE['GotoCourse'] != '';
9039
}
9040
9041
/**
9042
 * @return string return the course_code of the course where user login
9043
 */
9044
function api_get_firstpage_parameter()
9045
{
9046
    return $_COOKIE['GotoCourse'];
9047
}
9048
9049
/**
9050
 * Return true on https install.
9051
 *
9052
 * @return bool
9053
 */
9054
function api_is_https()
9055
{
9056
    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...
9057
        $_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...
9058
    ) {
9059
        $isSecured = true;
9060
    } else {
9061
        if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') {
9062
            $isSecured = true;
9063
        } else {
9064
            $isSecured = false;
9065
            // last chance
9066
            if (!empty($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443) {
9067
                $isSecured = true;
9068
            }
9069
        }
9070
    }
9071
9072
    return $isSecured;
9073
}
9074
9075
/**
9076
 * Return protocol (http or https).
9077
 *
9078
 * @return string
9079
 */
9080
function api_get_protocol()
9081
{
9082
    return api_is_https() ? 'https' : 'http';
9083
}
9084
9085
/**
9086
 * Return a string where " are replaced with 2 '
9087
 * It is useful when you pass a PHP variable in a Javascript browser dialog
9088
 * e.g. : alert("<?php get_lang('Message') ?>");
9089
 * and message contains character ".
9090
 *
9091
 * @param string $in_text
9092
 *
9093
 * @return string
9094
 */
9095
function convert_double_quote_to_single($in_text)
9096
{
9097
    return api_preg_replace('/"/', "''", $in_text);
9098
}
9099
9100
/**
9101
 * Get origin.
9102
 *
9103
 * @param string
9104
 *
9105
 * @return string
9106
 */
9107
function api_get_origin()
9108
{
9109
    return isset($_REQUEST['origin']) ? urlencode(Security::remove_XSS(urlencode($_REQUEST['origin']))) : '';
9110
}
9111
9112
/**
9113
 * Warns an user that the portal reach certain limit.
9114
 *
9115
 * @param string $limitName
9116
 */
9117
function api_warn_hosting_contact($limitName)
9118
{
9119
    $hostingParams = api_get_configuration_value(1);
9120
    $email = null;
9121
9122
    if (!empty($hostingParams)) {
9123
        if (isset($hostingParams['hosting_contact_mail'])) {
9124
            $email = $hostingParams['hosting_contact_mail'];
9125
        }
9126
    }
9127
9128
    if (!empty($email)) {
9129
        $subject = get_lang('HostingWarningReached');
9130
        $body = get_lang('PortalName').': '.api_get_path(WEB_PATH)." \n ";
9131
        $body .= get_lang('PortalLimitType').': '.$limitName." \n ";
9132
        if (isset($hostingParams[$limitName])) {
9133
            $body .= get_lang('Value').': '.$hostingParams[$limitName];
9134
        }
9135
        api_mail_html(null, $email, $subject, $body);
9136
    }
9137
}
9138
9139
/**
9140
 * Gets value of a variable from app/config/configuration.php
9141
 * Variables that are not set in the configuration.php file but set elsewhere:
9142
 * - virtual_css_theme_folder (vchamilo plugin)
9143
 * - access_url (global.inc.php)
9144
 * - apc/apc_prefix (global.inc.php).
9145
 *
9146
 * @param string $variable
9147
 *
9148
 * @return bool|mixed
9149
 */
9150
function api_get_configuration_value($variable)
9151
{
9152
    global $_configuration;
9153
    // Check the current url id, id = 1 by default
9154
    $urlId = isset($_configuration['access_url']) ? (int) $_configuration['access_url'] : 1;
9155
9156
    $variable = trim($variable);
9157
9158
    // Check if variable exists
9159
    if (isset($_configuration[$variable])) {
9160
        if (is_array($_configuration[$variable]) && api_is_multiple_url_enabled() && is_int(array_keys($_configuration[$variable])[0])) {
9161
            // It has been configured for at least one sub URL, so we will not return the complete variable
9162
            /*
9163
             * The idea is that if the first level key of the configuration variable is an int
9164
             * then it is a multiURL configuration and if it's a string then it's a configuration that is not multiURL.
9165
             * For example if in app/config/configuration.php you have set :
9166
             * $_configuration['ticket_project_user_roles'] = [
9167
             *     'permissions' => [
9168
             *         1 => [17] // project_id = 1, STUDENT_BOSS = 17
9169
             *     ]
9170
             * ];
9171
             * You do not want to enter this block even if multiURL is activated because the option is configured globally
9172
             * and you want to return the full array.
9173
             * The is_int is to consider only the option that are array and configured for multiURL
9174
             * which means there is an int as the first level key of the array.
9175
             */
9176
            // Check if it exists for the sub portal
9177
            if (array_key_exists($urlId, $_configuration[$variable])) {
9178
                return $_configuration[$variable][$urlId];
9179
            } else {
9180
                // Try to found element with id = 1 (master portal)
9181
                if (array_key_exists(1, $_configuration[$variable])) {
9182
                    return $_configuration[$variable][1];
9183
                } else {
9184
                    // The value was there for other URLs but not the main URL nor the current URL
9185
                    return null;
9186
                }
9187
            }
9188
        }
9189
9190
        return $_configuration[$variable];
9191
    }
9192
9193
    return false;
9194
}
9195
9196
/**
9197
 * Gets value of a variable from app/config/mail.conf.php.
9198
 *
9199
 * @param string $variable
9200
 *
9201
 * @return bool|mixed
9202
 */
9203
function api_get_mail_configuration_value($variable)
9204
{
9205
    global $_configuration;
9206
    global $platform_email;
9207
9208
    // Check the current url id, id = 1 by default
9209
    $urlId = isset($_configuration['access_url']) ? (int) $_configuration['access_url'] : 1;
9210
9211
    $variable = trim($variable);
9212
9213
    // Check if variable exists for the sub portal
9214
    if (api_is_multiple_url_enabled() && isset($platform_email[$urlId]) && isset($platform_email[$urlId][$variable])) {
9215
        return $platform_email[$urlId][$variable];
9216
    } elseif (isset($platform_email[1]) && isset($platform_email[1][$variable])) {
9217
        // Try to find element with id = 1 (master portal)
9218
        return $platform_email[1][$variable];
9219
    } elseif (isset($platform_email[$variable])) {
9220
        // If variable is not found for the sub portal or master portal, try to find the default element
9221
        return $platform_email[$variable];
9222
    }
9223
9224
    return false;
9225
}
9226
9227
/**
9228
 * Retreives and returns a value in a hierarchical configuration array
9229
 * api_get_configuration_sub_value('a/b/c') returns api_get_configuration_value('a')['b']['c'].
9230
 *
9231
 * @param string $path      the successive array keys, separated by the separator
9232
 * @param mixed  $default   value to be returned if not found, null by default
9233
 * @param string $separator '/' by default
9234
 * @param array  $array     the active configuration array by default
9235
 *
9236
 * @return mixed the found value or $default
9237
 */
9238
function api_get_configuration_sub_value($path, $default = null, $separator = '/', $array = null)
9239
{
9240
    $pos = strpos($path, $separator);
9241
    if (false === $pos) {
9242
        if (is_null($array)) {
9243
            return api_get_configuration_value($path);
9244
        }
9245
        if (is_array($array) && array_key_exists($path, $array)) {
9246
            return $array[$path];
9247
        }
9248
9249
        return $default;
9250
    }
9251
    $key = substr($path, 0, $pos);
9252
    if (is_null($array)) {
9253
        $newArray = api_get_configuration_value($key);
9254
    } elseif (is_array($array) && array_key_exists($key, $array)) {
9255
        $newArray = $array[$key];
9256
    } else {
9257
        return $default;
9258
    }
9259
    if (is_array($newArray)) {
9260
        $newPath = substr($path, $pos + 1);
9261
9262
        return api_get_configuration_sub_value($newPath, $default, $separator, $newArray);
9263
    }
9264
9265
    return $default;
9266
}
9267
9268
/**
9269
 * Retrieves and returns a value in a hierarchical configuration array
9270
 * api_array_sub_value($array, 'a/b/c') returns $array['a']['b']['c'].
9271
 *
9272
 * @param array  $array     the recursive array that contains the value to be returned (or not)
9273
 * @param string $path      the successive array keys, separated by the separator
9274
 * @param mixed  $default   the value to be returned if not found
9275
 * @param string $separator the separator substring
9276
 *
9277
 * @return mixed the found value or $default
9278
 */
9279
function api_array_sub_value($array, $path, $default = null, $separator = '/')
9280
{
9281
    $pos = strpos($path, $separator);
9282
    if (false === $pos) {
9283
        if (is_array($array) && array_key_exists($path, $array)) {
9284
            return $array[$path];
9285
        }
9286
9287
        return $default;
9288
    }
9289
    $key = substr($path, 0, $pos);
9290
    if (is_array($array) && array_key_exists($key, $array)) {
9291
        $newArray = $array[$key];
9292
    } else {
9293
        return $default;
9294
    }
9295
    if (is_array($newArray)) {
9296
        $newPath = substr($path, $pos + 1);
9297
9298
        return api_array_sub_value($newArray, $newPath, $default);
9299
    }
9300
9301
    return $default;
9302
}
9303
9304
/**
9305
 * Returns supported image extensions in the portal.
9306
 *
9307
 * @param bool $supportVectors Whether vector images should also be accepted or not
9308
 *
9309
 * @return array Supported image extensions in the portal
9310
 */
9311
function api_get_supported_image_extensions($supportVectors = true)
9312
{
9313
    // jpg can also be called jpeg, jpe, jfif and jif. See https://en.wikipedia.org/wiki/JPEG#JPEG_filename_extensions
9314
    $supportedImageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'jpe', 'jfif', 'jif'];
9315
    if ($supportVectors) {
9316
        array_push($supportedImageExtensions, 'svg');
9317
    }
9318
    if (version_compare(PHP_VERSION, '5.5.0', '>=')) {
9319
        array_push($supportedImageExtensions, 'webp');
9320
    }
9321
9322
    return $supportedImageExtensions;
9323
}
9324
9325
/**
9326
 * This setting changes the registration status for the campus.
9327
 *
9328
 * @author Patrick Cool <[email protected]>, Ghent University
9329
 *
9330
 * @version August 2006
9331
 *
9332
 * @param bool $listCampus Whether we authorize
9333
 *
9334
 * @todo the $_settings should be reloaded here. => write api function for this and use this in global.inc.php also.
9335
 */
9336
function api_register_campus($listCampus = true)
9337
{
9338
    $tbl_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
9339
9340
    $sql = "UPDATE $tbl_settings SET selected_value='true' WHERE variable='registered'";
9341
    Database::query($sql);
9342
9343
    if (!$listCampus) {
9344
        $sql = "UPDATE $tbl_settings SET selected_value='true' WHERE variable='donotlistcampus'";
9345
        Database::query($sql);
9346
    }
9347
}
9348
9349
/**
9350
 * Checks whether current user is a student boss.
9351
 *
9352
 * @global array $_user
9353
 *
9354
 * @return bool
9355
 */
9356
function api_is_student_boss()
9357
{
9358
    $_user = api_get_user_info();
9359
9360
    return isset($_user['status']) && $_user['status'] == STUDENT_BOSS;
9361
}
9362
9363
/**
9364
 * Check whether the user type should be exclude.
9365
 * Such as invited or anonymous users.
9366
 *
9367
 * @param bool $checkDB Optional. Whether check the user status
9368
 * @param int  $userId  Options. The user id
9369
 *
9370
 * @return bool
9371
 */
9372
function api_is_excluded_user_type($checkDB = false, $userId = 0)
9373
{
9374
    if ($checkDB) {
9375
        $userId = empty($userId) ? api_get_user_id() : (int) $userId;
9376
9377
        if ($userId == 0) {
9378
            return true;
9379
        }
9380
9381
        $userInfo = api_get_user_info($userId);
9382
9383
        switch ($userInfo['status']) {
9384
            case INVITEE:
9385
            case ANONYMOUS:
9386
                return true;
9387
            default:
9388
                return false;
9389
        }
9390
    }
9391
9392
    $isInvited = api_is_invitee();
9393
    $isAnonymous = api_is_anonymous();
9394
9395
    if ($isInvited || $isAnonymous) {
9396
        return true;
9397
    }
9398
9399
    return false;
9400
}
9401
9402
/**
9403
 * Get the user status to ignore in reports.
9404
 *
9405
 * @param string $format Optional. The result type (array or string)
9406
 *
9407
 * @return array|string
9408
 */
9409
function api_get_users_status_ignored_in_reports($format = 'array')
9410
{
9411
    $excludedTypes = [
9412
        INVITEE,
9413
        ANONYMOUS,
9414
    ];
9415
9416
    if ($format == 'string') {
9417
        return implode(', ', $excludedTypes);
9418
    }
9419
9420
    return $excludedTypes;
9421
}
9422
9423
/**
9424
 * Set the Site Use Cookie Warning for 1 year.
9425
 */
9426
function api_set_site_use_cookie_warning_cookie()
9427
{
9428
    api_set_cookie('ChamiloUsesCookies', 'ok', time() + 31556926);
9429
}
9430
9431
/**
9432
 * Return true if the Site Use Cookie Warning Cookie warning exists.
9433
 *
9434
 * @return bool
9435
 */
9436
function api_site_use_cookie_warning_cookie_exist()
9437
{
9438
    return isset($_COOKIE['ChamiloUsesCookies']);
9439
}
9440
9441
/**
9442
 * Given a number of seconds, format the time to show hours, minutes and seconds.
9443
 *
9444
 * @param int    $time         The time in seconds
9445
 * @param string $originFormat Optional.
9446
 *                             PHP (used for scorm)
9447
 *                             JS (used in most cases and understood by excel)
9448
 *                             LANG (used to present unit in the user language)
9449
 *
9450
 * @return string (00h00'00")
9451
 */
9452
function api_format_time($time, $originFormat = 'php')
9453
{
9454
    $h = get_lang('h');
9455
    $hours = $time / 3600;
9456
    $mins = ($time % 3600) / 60;
9457
    $secs = ($time % 60);
9458
9459
    if ($time < 0) {
9460
        $hours = 0;
9461
        $mins = 0;
9462
        $secs = 0;
9463
    }
9464
9465
    if ($originFormat == 'js') {
9466
        $formattedTime = trim(sprintf("%02d : %02d : %02d", $hours, $mins, $secs));
9467
    } elseif ($originFormat == 'lang') {
9468
        $formattedTime = trim(sprintf(get_lang('HoursMinutesSeconds'), $hours, $mins, $secs));
9469
    } else {
9470
        $formattedTime = trim(sprintf("%02d$h%02d'%02d\"", $hours, $mins, $secs));
9471
    }
9472
9473
    return $formattedTime;
9474
}
9475
9476
/**
9477
 * Create a new empty directory with index.html file.
9478
 *
9479
 * @param string $name            The new directory name
9480
 * @param string $parentDirectory Directory parent directory name
9481
 *
9482
 * @return bool Return true if the directory was create. Otherwise return false
9483
 */
9484
function api_create_protected_dir($name, $parentDirectory)
9485
{
9486
    $isCreated = false;
9487
9488
    if (!is_writable($parentDirectory)) {
9489
        return false;
9490
    }
9491
9492
    $fullPath = $parentDirectory.api_replace_dangerous_char($name);
9493
9494
    if (mkdir($fullPath, api_get_permissions_for_new_directories(), true)) {
9495
        $fp = fopen($fullPath.'/index.html', 'w');
9496
9497
        if ($fp) {
0 ignored issues
show
introduced by
$fp is of type resource, thus it always evaluated to false.
Loading history...
9498
            if (fwrite($fp, '<html><head><title></title></head><body></body></html>')) {
9499
                $isCreated = true;
9500
            }
9501
        }
9502
9503
        fclose($fp);
9504
    }
9505
9506
    return $isCreated;
9507
}
9508
9509
/**
9510
 * Sends an HTML email using the phpmailer class (and multipart/alternative to downgrade gracefully)
9511
 * Sender name and email can be specified, if not specified
9512
 * name and email of the platform admin are used.
9513
 *
9514
 * @author Bert Vanderkimpen ICT&O UGent
9515
 * @author Yannick Warnier <[email protected]>
9516
 *
9517
 * @param string    name of recipient
9518
 * @param string    email of recipient
9519
 * @param string    email subject
9520
 * @param string    email body
9521
 * @param string    sender name
9522
 * @param string    sender e-mail
9523
 * @param array  $extra_headers        in form $headers = array($name => $value) to allow parsing
9524
 * @param array  $data_file            (path and filename)
9525
 * @param bool   $embedded_image       True for attaching a embedded file inside content html (optional)
9526
 * @param array  $additionalParameters
9527
 * @param string $sendErrorTo          If there's an error while sending the email, $sendErrorTo will receive a notification
9528
 *
9529
 * @return int true if mail was sent
9530
 *
9531
 * @see             PHPMailer.php
9532
 */
9533
function api_mail_html(
9534
    $recipient_name,
9535
    $recipient_email,
9536
    $subject,
9537
    $message,
9538
    $senderName = '',
9539
    $senderEmail = '',
9540
    $extra_headers = [],
9541
    $data_file = [],
9542
    $embedded_image = false,
9543
    $additionalParameters = [],
9544
    $sendErrorTo = ''
9545
) {
9546
    if (true === api_get_configuration_value('disable_send_mail')) {
9547
        return true;
9548
    }
9549
9550
    $mail = new PHPMailer();
9551
9552
    if (!empty(api_get_mail_configuration_value('XOAUTH2_METHOD'))) {
9553
        $provider = new GenericProvider([
9554
            'clientId' => api_get_mail_configuration_value('XOAUTH2_CLIENT_ID'),
9555
            'clientSecret' => api_get_mail_configuration_value('XOAUTH2_CLIENT_SECRET'),
9556
            'urlAuthorize' => api_get_mail_configuration_value('XOAUTH2_URL_AUTHORIZE'),
9557
            'urlAccessToken' => api_get_mail_configuration_value('XOAUTH2_URL_ACCES_TOKEN'),
9558
            'urlResourceOwnerDetails' => api_get_mail_configuration_value('XOAUTH2_URL_RESOURCE_OWNER_DETAILS'),
9559
            'scopes' => api_get_mail_configuration_value('XOAUTH2_SCOPES'),
9560
        ]);
9561
        $mail->AuthType = 'XOAUTH2';
9562
        $mail->setOAuth(
9563
            new OAuth([
9564
                'provider' => $provider,
9565
                'clientId' => api_get_mail_configuration_value('XOAUTH2_CLIENT_ID'),
9566
                'clientSecret' => api_get_mail_configuration_value('XOAUTH2_CLIENT_SECRET'),
9567
                'refreshToken' => api_get_mail_configuration_value('XOAUTH2_REFRESH_TOKEN'),
9568
                'userName' => api_get_mail_configuration_value('SMTP_USER'),
9569
            ])
9570
        );
9571
    }
9572
9573
    $mail->Mailer = api_get_mail_configuration_value('SMTP_MAILER');
9574
    $mail->Host = api_get_mail_configuration_value('SMTP_HOST');
9575
    $mail->Port = api_get_mail_configuration_value('SMTP_PORT');
9576
    $mail->CharSet = api_get_mail_configuration_value('SMTP_CHARSET') ?: 'UTF-8';
9577
    // Stay far below SMTP protocol 980 chars limit.
9578
    $mail->WordWrap = 200;
9579
    $mail->SMTPOptions = api_get_mail_configuration_value('SMTPOptions') ?: [];
9580
9581
    if (api_get_mail_configuration_value('SMTP_AUTH')) {
9582
        $mail->SMTPAuth = 1;
9583
        $mail->Username = api_get_mail_configuration_value('SMTP_USER');
9584
        $mail->Password = api_get_mail_configuration_value('SMTP_PASS');
9585
        if (api_get_mail_configuration_value('SMTP_SECURE')) {
9586
            $mail->SMTPSecure = api_get_mail_configuration_value('SMTP_SECURE');
9587
        }
9588
    }
9589
    $mail->SMTPDebug = api_get_mail_configuration_value('SMTP_DEBUG') ?: 0;
9590
9591
    // 5 = low, 1 = high
9592
    $mail->Priority = 3;
9593
    $mail->SMTPKeepAlive = true;
9594
9595
    api_set_noreply_and_from_address_to_mailer(
9596
        $mail,
9597
        ['name' => $senderName, 'email' => $senderEmail],
9598
        !empty($extra_headers['reply_to']) ? $extra_headers['reply_to'] : []
9599
    );
9600
9601
    if (!empty($sendErrorTo) && PHPMailer::ValidateAddress($sendErrorTo)) {
9602
        $mail->AddCustomHeader('Errors-To', $sendErrorTo);
9603
    }
9604
9605
    unset($extra_headers['reply_to']);
9606
9607
    $mail->Subject = $subject;
9608
    $mail->AltBody = strip_tags(
9609
        str_replace('<br />', "\n", api_html_entity_decode($message))
9610
    );
9611
9612
    $list = api_get_configuration_value('send_all_emails_to');
9613
    if (!empty($list) && isset($list['emails'])) {
9614
        foreach ($list['emails'] as $email) {
9615
            $mail->AddAddress($email);
9616
        }
9617
    }
9618
9619
    // Send embedded image.
9620
    if ($embedded_image) {
9621
        // Get all images html inside content.
9622
        preg_match_all("/<img\s+.*?src=[\"\']?([^\"\' >]*)[\"\']?[^>]*>/i", $message, $m);
9623
        // Prepare new tag images.
9624
        $new_images_html = [];
9625
        $i = 1;
9626
        if (!empty($m[1])) {
9627
            foreach ($m[1] as $image_path) {
9628
                $real_path = realpath($image_path);
9629
                $filename = basename($image_path);
9630
                $image_cid = $filename.'_'.$i;
9631
                $encoding = 'base64';
9632
                $image_type = mime_content_type($real_path);
9633
                $mail->AddEmbeddedImage(
9634
                    $real_path,
9635
                    $image_cid,
9636
                    $filename,
9637
                    $encoding,
9638
                    $image_type
9639
                );
9640
                $new_images_html[] = '<img src="cid:'.$image_cid.'" />';
9641
                $i++;
9642
            }
9643
        }
9644
9645
        // Replace origin image for new embedded image html.
9646
        $x = 0;
9647
        if (!empty($m[0])) {
9648
            foreach ($m[0] as $orig_img) {
9649
                $message = str_replace($orig_img, $new_images_html[$x], $message);
9650
                $x++;
9651
            }
9652
        }
9653
    }
9654
9655
    $extendedFooterMessageConfig = api_get_configuration_value('notifications_extended_footer_message');
9656
    if ($extendedFooterMessageConfig) {
9657
        $platformLanguage = api_get_interface_language();
9658
        $extendedFooterMessage = api_get_configuration_value('notifications_extended_footer_message')[$platformLanguage];
9659
9660
        if ($extendedFooterMessage) {
9661
            $message .= '<br /><hr><i>'.'<p>'.implode('<br/><br/>', $extendedFooterMessage['paragraphs']).'</p>';
9662
        }
9663
    }
9664
9665
    $mailView = new Template(null, false, false, false, false, false, false);
9666
9667
    $noReply = api_get_setting('noreply_email_address');
9668
    if (!empty($noReply)) {
9669
        $message .= '<br />'.get_lang('ThisIsAutomaticEmailNoReply');
9670
    }
9671
    $mailView->assign('content', $message);
9672
9673
    if (isset($additionalParameters['link'])) {
9674
        $mailView->assign('link', $additionalParameters['link']);
9675
    }
9676
    if (isset($additionalParameters['logo'])) {
9677
        $mailView->assign('logo', $additionalParameters['logo']);
9678
    } elseif (api_get_configuration_value('email_logo') == true) {
9679
        $logoSubPath = 'themes/'.api_get_visual_theme().'/images/email-logo.png';
9680
        $logoSysPath = api_get_path(SYS_PATH).'web/css/'.$logoSubPath;
9681
        if (file_exists($logoSysPath)) {
9682
            $logoWebPath = api_get_path(WEB_CSS_PATH).$logoSubPath;
9683
            $imgTag = \Display::img(
9684
                $logoWebPath,
9685
                api_get_setting('siteName'),
9686
                [
9687
                    'id' => 'header-logo',
9688
                    'class' => 'img-responsive',
9689
                ]
9690
            );
9691
            $logoTag = \Display::url($imgTag, api_get_path(WEB_PATH));
9692
            $mailView->assign('logo', $logoTag);
9693
        }
9694
    }
9695
    $mailView->assign('mail_header_style', api_get_configuration_value('mail_header_style'));
9696
    $mailView->assign('mail_content_style', api_get_configuration_value('mail_content_style'));
9697
    $mailView->assign('include_ldjson', (empty(api_get_mail_configuration_value('EXCLUDE_JSON')) ? true : false));
9698
    $layout = $mailView->get_template('mail/mail.tpl');
9699
    $mail->Body = $mailView->fetch($layout);
9700
9701
    if (isset($additionalParameters['checkUrls'])) {
9702
        $useMultipleUrl = api_get_configuration_value('multiple_access_urls');
9703
        if ($useMultipleUrl) {
9704
            $accessConfig = [];
9705
            $accessUrls = api_get_access_url_from_user($additionalParameters['userId'], $additionalParameters['courseId']);
9706
            if (!empty($accessUrls)) {
9707
                $accessConfig['multiple_access_urls'] = true;
9708
                $accessConfig['access_url'] = (int) $accessUrls[0];
9709
                $params = ['variable = ? AND access_url = ?' => ['stylesheets', $accessConfig['access_url']]];
9710
                $settings = api_get_settings_params_simple($params);
9711
                if (!empty($settings['selected_value'])) {
9712
                    $accessConfig['theme_dir'] = \Template::getThemeDir($settings['selected_value']);
9713
                }
9714
            }
9715
            // To replace the current urls by access url user
9716
            $mail->Body = str_replace(api_get_path(WEB_PATH), api_get_path(WEB_PATH, $accessConfig), $mail->Body);
9717
            if (!empty($accessConfig['theme_dir'])) {
9718
                $mail->Body = str_replace('themes/chamilo/', $accessConfig['theme_dir'], $mail->Body);
9719
            }
9720
        }
9721
    }
9722
    // Attachment.
9723
    if (!empty($data_file)) {
9724
        foreach ($data_file as $file_attach) {
9725
            if (!empty($file_attach['path']) && !empty($file_attach['filename'])) {
9726
                $mail->AddAttachment($file_attach['path'], $file_attach['filename']);
9727
            }
9728
        }
9729
    }
9730
9731
    // Only valid addresses are accepted.
9732
    if (is_array($recipient_email)) {
9733
        foreach ($recipient_email as $dest) {
9734
            if (api_valid_email($dest)) {
9735
                if (UserManager::isEmailingAllowed($dest)) {
9736
                    // Do not send if user is not active = 1
9737
                    $mail->AddAddress($dest, $recipient_name);
9738
                }
9739
            } else {
9740
                // error_log('e-mail recipient '.$dest.' is not valid.');
9741
                return 0;
9742
            }
9743
        }
9744
    } else {
9745
        if (api_valid_email($recipient_email)) {
9746
            if (UserManager::isEmailingAllowed($recipient_email)) {
9747
                // Do not send if user is not active = 1
9748
                $mail->AddAddress($recipient_email, $recipient_name);
9749
            }
9750
        } else {
9751
            // error_log('e-mail recipient '.$recipient_email.' is not valid.');
9752
            return 0;
9753
        }
9754
    }
9755
    if (empty($mail->getAllRecipientAddresses())) {
9756
        // error_log('No valid and active destination e-mail in api_mail_html() with address '.print_r($recipient_email, 1).'. Not sending.');
9757
        return 0;
9758
    }
9759
9760
    if (is_array($extra_headers) && count($extra_headers) > 0) {
9761
        foreach ($extra_headers as $key => $value) {
9762
            switch (strtolower($key)) {
9763
                case 'encoding':
9764
                case 'content-transfer-encoding':
9765
                    $mail->Encoding = $value;
9766
                    break;
9767
                case 'charset':
9768
                    $mail->CharSet = $value;
9769
                    break;
9770
                case 'contenttype':
9771
                case 'content-type':
9772
                    $mail->ContentType = $value;
9773
                    break;
9774
                default:
9775
                    $mail->AddCustomHeader($key, $value);
9776
                    break;
9777
            }
9778
        }
9779
    } else {
9780
        if (!empty($extra_headers)) {
9781
            $mail->AddCustomHeader($extra_headers);
9782
        }
9783
    }
9784
9785
    // WordWrap the html body (phpMailer only fixes AltBody) FS#2988
9786
    $mail->Body = $mail->WrapText($mail->Body, $mail->WordWrap);
9787
9788
    if (!empty(api_get_mail_configuration_value('DKIM')) &&
9789
        !empty(api_get_mail_configuration_value('DKIM_SELECTOR')) &&
9790
        !empty(api_get_mail_configuration_value('DKIM_DOMAIN')) &&
9791
        (!empty(api_get_mail_configuration_value('DKIM_PRIVATE_KEY_STRING')) || !empty(api_get_mail_configuration_value('DKIM_PRIVATE_KEY')))) {
9792
        $mail->DKIM_selector = api_get_mail_configuration_value('DKIM_SELECTOR');
9793
        $mail->DKIM_domain = api_get_mail_configuration_value('DKIM_DOMAIN');
9794
        if (!empty(api_get_mail_configuration_value('SMTP_UNIQUE_SENDER'))) {
9795
            $mail->DKIM_identity = api_get_mail_configuration_value('SMTP_FROM_EMAIL');
9796
        }
9797
        $mail->DKIM_private_string = api_get_mail_configuration_value('DKIM_PRIVATE_KEY_STRING');
9798
        $mail->DKIM_private = api_get_mail_configuration_value('DKIM_PRIVATE_KEY');
9799
        if (!empty(api_get_mail_configuration_value['DKIM_PASSPHRASE'])) {
0 ignored issues
show
Bug introduced by
The constant api_get_mail_configuration_value was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
9800
            $mail->DKIM_passphrase = api_get_mail_configuration_value['DKIM_PASSPHRASE'];
9801
        }
9802
    }
9803
9804
    // Send the mail message.
9805
    $sent = $mail->Send();
9806
    if (!$sent) {
9807
        error_log('ERROR: mail not sent to '.$recipient_name.' ('.$recipient_email.') because of '.$mail->ErrorInfo.'<br />');
9808
    }
9809
9810
    if ($mail->SMTPDebug >= 1) {
9811
        error_log(
9812
            "Mail debug:: ".
9813
            "Protocol: ".$mail->Mailer.' :: '.
9814
            "Host/Port: ".$mail->Host.':'.$mail->Port.' :: '.
9815
            "Authent/Open: ".($mail->SMTPAuth ? 'Authent' : 'Open').' :: '.
9816
            ($mail->SMTPAuth ? "  User/Pass: ".$mail->Username.':'.$mail->Password : '').' :: '.
9817
            "Sender: ".$mail->Sender.
9818
            "Recipient email: ".$recipient_email.
9819
            "Subject: ".$subject
9820
        );
9821
    }
9822
9823
    if (!$sent) {
9824
        return 0;
9825
    }
9826
9827
    if (!empty($additionalParameters)) {
9828
        $plugin = new AppPlugin();
9829
        $smsPlugin = $plugin->getSMSPluginLibrary();
9830
        if ($smsPlugin) {
0 ignored issues
show
introduced by
$smsPlugin is of type SmsPluginLibraryInterface, thus it always evaluated to true.
Loading history...
9831
            $smsPlugin->send($additionalParameters);
9832
        }
9833
    }
9834
9835
    // Clear all the addresses.
9836
    $mail->ClearAddresses();
9837
9838
    // Clear all attachments
9839
    $mail->ClearAttachments();
9840
9841
    return 1;
9842
}
9843
9844
/**
9845
 * Checks access to a course group.
9846
 *
9847
 * @param string $tool       Possible values: GroupManager::GROUP_TOOL_*
9848
 * @param bool   $showHeader
9849
 */
9850
function api_protect_course_group($tool, $showHeader = true)
9851
{
9852
    $groupId = api_get_group_id();
9853
    if (!empty($groupId)) {
9854
        if (api_is_platform_admin()) {
9855
            return true;
9856
        }
9857
9858
        if (api_is_allowed_to_edit(false, true, true)) {
9859
            return true;
9860
        }
9861
9862
        $userId = api_get_user_id();
9863
        $sessionId = api_get_session_id();
9864
        if (!empty($sessionId)) {
9865
            if (api_is_coach($sessionId, api_get_course_int_id())) {
9866
                return true;
9867
            }
9868
9869
            if (api_is_drh()) {
9870
                if (SessionManager::isUserSubscribedAsHRM($sessionId, $userId)) {
9871
                    return true;
9872
                }
9873
            }
9874
        }
9875
9876
        $groupInfo = GroupManager::get_group_properties($groupId);
9877
9878
        // Group doesn't exists
9879
        if (empty($groupInfo)) {
9880
            api_not_allowed($showHeader);
9881
        }
9882
9883
        // Check group access
9884
        $allow = GroupManager::user_has_access(
9885
            $userId,
9886
            $groupInfo['iid'],
9887
            $tool
9888
        );
9889
9890
        if (!$allow) {
9891
            api_not_allowed($showHeader);
9892
        }
9893
    }
9894
9895
    return false;
9896
}
9897
9898
/**
9899
 * Check if a date is in a date range.
9900
 *
9901
 * @param datetime $startDate
9902
 * @param datetime $endDate
9903
 * @param datetime $currentDate
9904
 *
9905
 * @return bool true if date is in rage, false otherwise
9906
 */
9907
function api_is_date_in_date_range($startDate, $endDate, $currentDate = null)
9908
{
9909
    $startDate = strtotime(api_get_local_time($startDate));
9910
    $endDate = strtotime(api_get_local_time($endDate));
9911
    $currentDate = strtotime(api_get_local_time($currentDate));
9912
9913
    if ($currentDate >= $startDate && $currentDate <= $endDate) {
9914
        return true;
9915
    }
9916
9917
    return false;
9918
}
9919
9920
/**
9921
 * Eliminate the duplicates of a multidimensional array by sending the key.
9922
 *
9923
 * @param array $array multidimensional array
9924
 * @param int   $key   key to find to compare
9925
 *
9926
 * @return array
9927
 */
9928
function api_unique_multidim_array($array, $key)
9929
{
9930
    $temp_array = [];
9931
    $i = 0;
9932
    $key_array = [];
9933
9934
    foreach ($array as $val) {
9935
        if (!in_array($val[$key], $key_array)) {
9936
            $key_array[$i] = $val[$key];
9937
            $temp_array[$i] = $val;
9938
        }
9939
        $i++;
9940
    }
9941
9942
    return $temp_array;
9943
}
9944
9945
/**
9946
 * Limit the access to Session Admins when the limit_session_admin_role
9947
 * configuration variable is set to true.
9948
 */
9949
function api_protect_limit_for_session_admin()
9950
{
9951
    $limitAdmin = api_get_setting('limit_session_admin_role');
9952
    if (api_is_session_admin() && $limitAdmin === 'true') {
9953
        api_not_allowed(true);
9954
    }
9955
}
9956
9957
/**
9958
 * Limits that a session admin has access to list users.
9959
 * When limit_session_admin_list_users configuration variable is set to true.
9960
 */
9961
function api_protect_session_admin_list_users()
9962
{
9963
    $limitAdmin = api_get_configuration_value('limit_session_admin_list_users');
9964
9965
    if (api_is_session_admin() && true === $limitAdmin) {
9966
        api_not_allowed(true);
9967
    }
9968
}
9969
9970
/**
9971
 * @return bool
9972
 */
9973
function api_is_student_view_active()
9974
{
9975
    $studentView = Session::read('studentview');
9976
9977
    return $studentView == 'studentview';
9978
}
9979
9980
/**
9981
 * Adds a file inside the upload/$type/id.
9982
 *
9983
 * @param string $type
9984
 * @param array  $file
9985
 * @param int    $itemId
9986
 * @param string $cropParameters
9987
 *
9988
 * @return array|bool
9989
 */
9990
function api_upload_file($type, $file, $itemId, $cropParameters = '')
9991
{
9992
    $upload = process_uploaded_file($file);
9993
    if ($upload) {
9994
        $name = api_replace_dangerous_char($file['name']);
9995
9996
        // No "dangerous" files
9997
        $name = disable_dangerous_file($name);
9998
9999
        $pathId = '/'.substr((string) $itemId, 0, 1).'/'.$itemId.'/';
10000
        $path = api_get_path(SYS_UPLOAD_PATH).$type.$pathId;
10001
10002
        if (!is_dir($path)) {
10003
            mkdir($path, api_get_permissions_for_new_directories(), true);
10004
        }
10005
10006
        $pathToSave = $path.$name;
10007
        $result = moveUploadedFile($file, $pathToSave);
10008
10009
        if ($result) {
10010
            if (!empty($cropParameters)) {
10011
                $image = new Image($pathToSave);
10012
                $image->crop($cropParameters);
10013
            }
10014
10015
            return ['path_to_save' => $pathId.$name];
10016
        }
10017
    }
10018
10019
    return false;
10020
}
10021
10022
/**
10023
 * @param string $type
10024
 * @param int    $itemId
10025
 * @param string $file
10026
 *
10027
 * @return bool
10028
 */
10029
function api_get_uploaded_web_url($type, $itemId, $file)
10030
{
10031
    return api_get_uploaded_file($type, $itemId, $file, true);
10032
}
10033
10034
/**
10035
 * @param string $type
10036
 * @param int    $itemId
10037
 * @param string $file
10038
 * @param bool   $getUrl
10039
 *
10040
 * @return bool
10041
 */
10042
function api_get_uploaded_file($type, $itemId, $file, $getUrl = false)
10043
{
10044
    $itemId = (int) $itemId;
10045
    $pathId = '/'.substr((string) $itemId, 0, 1).'/'.$itemId.'/';
10046
    $path = api_get_path(SYS_UPLOAD_PATH).$type.$pathId;
10047
    $file = basename($file);
10048
    $file = $path.'/'.$file;
10049
    if (Security::check_abs_path($file, $path) && is_file($file) && file_exists($file)) {
10050
        if ($getUrl) {
10051
            return str_replace(api_get_path(SYS_UPLOAD_PATH), api_get_path(WEB_UPLOAD_PATH), $file);
10052
        }
10053
10054
        return $file;
10055
    }
10056
10057
    return false;
10058
}
10059
10060
/**
10061
 * @param string $type
10062
 * @param int    $itemId
10063
 * @param string $file
10064
 * @param string $title
10065
 */
10066
function api_download_uploaded_file($type, $itemId, $file, $title = '')
10067
{
10068
    $file = api_get_uploaded_file($type, $itemId, $file);
10069
    if ($file) {
10070
        if (Security::check_abs_path($file, api_get_path(SYS_UPLOAD_PATH).$type)) {
10071
            DocumentManager::file_send_for_download($file, true, $title);
10072
            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...
10073
        }
10074
    }
10075
    api_not_allowed(true);
10076
}
10077
10078
/**
10079
 * @param string $type
10080
 * @param string $file
10081
 */
10082
function api_remove_uploaded_file($type, $file)
10083
{
10084
    $typePath = api_get_path(SYS_UPLOAD_PATH).$type;
10085
    $path = $typePath.'/'.$file;
10086
    if (Security::check_abs_path($path, $typePath) && file_exists($path) && is_file($path)) {
10087
        unlink($path);
10088
    }
10089
}
10090
10091
/**
10092
 * @param string $type
10093
 * @param int    $itemId
10094
 * @param string $file
10095
 *
10096
 * @return bool
10097
 */
10098
function api_remove_uploaded_file_by_id($type, $itemId, $file)
10099
{
10100
    $file = api_get_uploaded_file($type, $itemId, $file, false);
10101
    $typePath = api_get_path(SYS_UPLOAD_PATH).$type;
10102
    if (Security::check_abs_path($file, $typePath) && file_exists($file) && is_file($file)) {
10103
        unlink($file);
10104
10105
        return true;
10106
    }
10107
10108
    return false;
10109
}
10110
10111
/**
10112
 * Converts string value to float value.
10113
 *
10114
 * 3.141516 => 3.141516
10115
 * 3,141516 => 3.141516
10116
 *
10117
 * @todo WIP
10118
 *
10119
 * @param string $number
10120
 *
10121
 * @return float
10122
 */
10123
function api_float_val($number)
10124
{
10125
    $number = (float) str_replace(',', '.', trim($number));
10126
10127
    return $number;
10128
}
10129
10130
/**
10131
 * Converts float values
10132
 * Example if $decimals = 2.
10133
 *
10134
 * 3.141516 => 3.14
10135
 * 3,141516 => 3,14
10136
 *
10137
 * @param string $number            number in iso code
10138
 * @param int    $decimals
10139
 * @param string $decimalSeparator
10140
 * @param string $thousandSeparator
10141
 *
10142
 * @return bool|string
10143
 */
10144
function api_number_format($number, $decimals = 0, $decimalSeparator = '.', $thousandSeparator = ',')
10145
{
10146
    $number = api_float_val($number);
10147
10148
    return number_format($number, $decimals, $decimalSeparator, $thousandSeparator);
10149
}
10150
10151
/**
10152
 * Set location url with a exit break by default.
10153
 *
10154
 * @param string $url
10155
 * @param bool   $exit
10156
 */
10157
function api_location($url, $exit = true)
10158
{
10159
    header('Location: '.$url);
10160
10161
    if ($exit) {
10162
        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...
10163
    }
10164
}
10165
10166
/**
10167
 * @return string
10168
 */
10169
function api_get_web_url()
10170
{
10171
    if (api_get_setting('server_type') === 'test') {
10172
        return api_get_path(WEB_PATH).'web/app_dev.php/';
10173
    } else {
10174
        return api_get_path(WEB_PATH).'web/';
10175
    }
10176
}
10177
10178
/**
10179
 * @param string $from
10180
 * @param string $to
10181
 *
10182
 * @return string
10183
 */
10184
function api_get_relative_path($from, $to)
10185
{
10186
    // some compatibility fixes for Windows paths
10187
    $from = is_dir($from) ? rtrim($from, '\/').'/' : $from;
10188
    $to = is_dir($to) ? rtrim($to, '\/').'/' : $to;
10189
    $from = str_replace('\\', '/', $from);
10190
    $to = str_replace('\\', '/', $to);
10191
10192
    $from = explode('/', $from);
10193
    $to = explode('/', $to);
10194
    $relPath = $to;
10195
10196
    foreach ($from as $depth => $dir) {
10197
        // find first non-matching dir
10198
        if ($dir === $to[$depth]) {
10199
            // ignore this directory
10200
            array_shift($relPath);
10201
        } else {
10202
            // get number of remaining dirs to $from
10203
            $remaining = count($from) - $depth;
10204
            if ($remaining > 1) {
10205
                // add traversals up to first matching dir
10206
                $padLength = (count($relPath) + $remaining - 1) * -1;
10207
                $relPath = array_pad($relPath, $padLength, '..');
10208
                break;
10209
            } else {
10210
                $relPath[0] = './'.$relPath[0];
10211
            }
10212
        }
10213
    }
10214
10215
    return implode('/', $relPath);
10216
}
10217
10218
/**
10219
 * Unserialize content using Brummann\Polyfill\Unserialize.
10220
 *
10221
 * @param string $type
10222
 * @param string $serialized
10223
 *
10224
 * @return mixed
10225
 */
10226
function api_unserialize_content($type, $serialized, $ignoreErrors = false)
10227
{
10228
    switch ($type) {
10229
        case 'career':
10230
        case 'sequence_graph':
10231
            $allowedClasses = [Graph::class, VerticesMap::class, Vertices::class, Edges::class];
10232
            break;
10233
        case 'lp':
10234
            $allowedClasses = [
10235
                learnpath::class,
10236
                learnpathItem::class,
10237
                aicc::class,
10238
                aiccBlock::class,
10239
                aiccItem::class,
10240
                aiccObjective::class,
10241
                aiccResource::class,
10242
                scorm::class,
10243
                scormItem::class,
10244
                scormMetadata::class,
10245
                scormOrganization::class,
10246
                scormResource::class,
10247
                Link::class,
10248
                LpItem::class,
10249
            ];
10250
            break;
10251
        case 'course':
10252
            $allowedClasses = [
10253
                Course::class,
10254
                Announcement::class,
10255
                Attendance::class,
10256
                CalendarEvent::class,
10257
                CourseCopyLearnpath::class,
10258
                CourseCopyTestCategory::class,
10259
                CourseDescription::class,
10260
                CourseSession::class,
10261
                Document::class,
10262
                Forum::class,
10263
                ForumCategory::class,
10264
                ForumPost::class,
10265
                ForumTopic::class,
10266
                Glossary::class,
10267
                GradeBookBackup::class,
10268
                Link::class,
10269
                LinkCategory::class,
10270
                Quiz::class,
10271
                QuizQuestion::class,
10272
                QuizQuestionOption::class,
10273
                ScormDocument::class,
10274
                Survey::class,
10275
                SurveyInvitation::class,
10276
                SurveyQuestion::class,
10277
                Thematic::class,
10278
                ToolIntro::class,
10279
                Wiki::class,
10280
                Work::class,
10281
                stdClass::class,
10282
            ];
10283
            break;
10284
        case 'not_allowed_classes':
10285
        default:
10286
            $allowedClasses = false;
10287
    }
10288
10289
    if ($ignoreErrors) {
10290
        return @Unserialize::unserialize(
10291
            $serialized,
10292
            ['allowed_classes' => $allowedClasses]
10293
        );
10294
    }
10295
10296
    return Unserialize::unserialize(
10297
        $serialized,
10298
        ['allowed_classes' => $allowedClasses]
10299
    );
10300
}
10301
10302
/**
10303
 * Set the From and ReplyTo properties to PHPMailer instance.
10304
 *
10305
 * @throws \PHPMailer\PHPMailer\Exception
10306
 */
10307
function api_set_noreply_and_from_address_to_mailer(PHPMailer $mailer, array $sender, array $replyToAddress = [])
10308
{
10309
    $noReplyAddress = api_get_setting('noreply_email_address');
10310
    $avoidReplyToAddress = false;
10311
10312
    if (!empty($noReplyAddress)) {
10313
        $avoidReplyToAddress = api_get_configuration_value('mail_no_reply_avoid_reply_to');
10314
    }
10315
10316
    $notification = new Notification();
10317
    // If the parameter is set don't use the admin.
10318
    $senderName = !empty($sender['name']) ? $sender['name'] : $notification->getDefaultPlatformSenderName();
10319
    $senderEmail = !empty($sender['email']) ? $sender['email'] : $notification->getDefaultPlatformSenderEmail();
10320
10321
    // Send errors to the platform admin
10322
    $adminEmail = api_get_setting('emailAdministrator');
10323
    if (PHPMailer::ValidateAddress($adminEmail)) {
10324
        $mailer->AddCustomHeader('Errors-To: '.$adminEmail);
10325
    }
10326
10327
    // Reply to first
10328
    if (!$avoidReplyToAddress) {
10329
        if (
10330
            !empty($replyToAddress) &&
10331
            PHPMailer::ValidateAddress($replyToAddress['mail'])
10332
        ) {
10333
            $mailer->AddReplyTo($replyToAddress['mail'], $replyToAddress['name']);
10334
            //$mailer->Sender = $replyToAddress['mail'];
10335
        }
10336
    }
10337
10338
    //If the SMTP configuration only accept one sender
10339
    if (
10340
        !empty(api_get_mail_configuration_value('SMTP_UNIQUE_SENDER')) &&
10341
        api_get_mail_configuration_value('SMTP_UNIQUE_SENDER')
10342
    ) {
10343
        $senderName = $notification->getDefaultPlatformSenderName();
10344
        $senderEmail = $notification->getDefaultPlatformSenderEmail();
10345
10346
        if (PHPMailer::ValidateAddress($senderEmail)) {
10347
            //force-set Sender to $senderEmail, otherwise SetFrom only does it if it is currently empty
10348
            $mailer->Sender = $senderEmail;
10349
        }
10350
    }
10351
10352
    $mailer->SetFrom($senderEmail, $senderName, !$avoidReplyToAddress);
10353
}
10354
10355
/**
10356
 * @param string $template
10357
 *
10358
 * @return string
10359
 */
10360
function api_find_template($template)
10361
{
10362
    return Template::findTemplateFilePath($template);
10363
}
10364
10365
/**
10366
 * Returns an array of languages (English names like "english", "french", etc)
10367
 * to ISO 639-1 codes (fr, es, etc) for use (for example) to show flags
10368
 * Note: 'english' is returned as 'gb'.
10369
 *
10370
 * @return array
10371
 */
10372
function api_get_language_list_for_flag()
10373
{
10374
    $table = Database::get_main_table(TABLE_MAIN_LANGUAGE);
10375
    $sql = "SELECT english_name, isocode FROM $table
10376
            ORDER BY original_name ASC";
10377
    static $languages = [];
10378
    if (empty($languages)) {
10379
        $result = Database::query($sql);
10380
        while ($row = Database::fetch_array($result)) {
10381
            $languages[$row['english_name']] = $row['isocode'];
10382
        }
10383
        $languages['english'] = 'gb';
10384
    }
10385
10386
    return $languages;
10387
}
10388
10389
/**
10390
 * Generate the Javascript required for the on-page translation of
10391
 * multi-language strings.
10392
 *
10393
 * @throws Exception
10394
 *
10395
 * @return string
10396
 */
10397
function api_get_language_translate_html()
10398
{
10399
    $translate = api_get_configuration_value('translate_html');
10400
10401
    if (!$translate) {
10402
        return '';
10403
    }
10404
10405
    $languageList = api_get_languages();
10406
    $hideAll = '';
10407
    foreach ($languageList['all'] as $language) {
10408
        $hideAll .= '
10409
        $("span:lang('.$language['isocode'].')").filter(
10410
            function(e, val) {
10411
                // Only find the spans if they have set the lang
10412
                if ($(this).attr("lang") == null) {
10413
                    return false;
10414
                }
10415
10416
                // Ignore ckeditor classes
10417
                return !this.className.match(/cke(.*)/);
10418
        }).hide();'."\n";
10419
    }
10420
10421
    $userInfo = api_get_user_info();
10422
    $languageId = 0;
10423
    if (!empty($userInfo['language'])) {
10424
        $languageId = api_get_language_id($userInfo['language']);
10425
    } elseif (!empty($_GET['language'])) {
10426
        $languageId = api_get_language_id($_GET['language']);
10427
    }
10428
    $languageInfo = api_get_language_info($languageId);
10429
    $isoCode = 'en';
10430
10431
    if (!empty($languageInfo)) {
10432
        $isoCode = $languageInfo['isocode'];
10433
    }
10434
10435
    return '
10436
            $(function() {
10437
                '.$hideAll.'
10438
                var defaultLanguageFromUser = "'.$isoCode.'";
10439
10440
                $("span:lang('.$isoCode.')").filter(
10441
                    function() {
10442
                        // Ignore ckeditor classes
10443
                        return !this.className.match(/cke(.*)/);
10444
                }).show();
10445
10446
                var defaultLanguage = "";
10447
                var langFromUserFound = false;
10448
10449
                $(this).find("span").filter(
10450
                    function() {
10451
                        // Ignore ckeditor classes
10452
                        return !this.className.match(/cke(.*)/);
10453
                }).each(function() {
10454
                    defaultLanguage = $(this).attr("lang");
10455
                    if (defaultLanguage) {
10456
                        $(this).before().next("br").remove();
10457
                        if (defaultLanguageFromUser == defaultLanguage) {
10458
                            langFromUserFound = true;
10459
                        }
10460
                    }
10461
                });
10462
10463
                // Show default language
10464
                if (langFromUserFound == false && defaultLanguage) {
10465
                    $("span:lang("+defaultLanguage+")").filter(
10466
                    function() {
10467
                            // Ignore ckeditor classes
10468
                            return !this.className.match(/cke(.*)/);
10469
                    }).show();
10470
                }
10471
            });
10472
    ';
10473
}
10474
10475
/**
10476
 * Filter a multi-language HTML string (for the multi-language HTML
10477
 * feature) into the given language (strip the rest).
10478
 *
10479
 * @param string $htmlString The HTML string to "translate". Usually <p><span lang="en">Some string</span></p><p><span lang="fr">Une chaîne</span></p>
10480
 * @param string $language   The language in which we want to get the
10481
 *
10482
 * @throws Exception
10483
 *
10484
 * @return string The filtered string in the given language, or the full string if no translated string was identified
10485
 */
10486
function api_get_filtered_multilingual_HTML_string($htmlString, $language = null)
10487
{
10488
    if (api_get_configuration_value('translate_html') != true) {
10489
        return $htmlString;
10490
    }
10491
    $userInfo = api_get_user_info();
10492
    $languageId = 0;
10493
    if (!empty($language)) {
10494
        $languageId = api_get_language_id($language);
10495
    } elseif (!empty($userInfo['language'])) {
10496
        $languageId = api_get_language_id($userInfo['language']);
10497
    }
10498
    $languageInfo = api_get_language_info($languageId);
10499
    $isoCode = 'en';
10500
10501
    if (!empty($languageInfo)) {
10502
        $isoCode = $languageInfo['isocode'];
10503
    }
10504
10505
    // Split HTML in the separate language strings
10506
    // Note: some strings might look like <p><span ..>...</span></p> but others might be like combine 2 <span> in 1 <p>
10507
    if (!preg_match('/<span.*?lang="(\w\w)">/is', $htmlString)) {
10508
        return $htmlString;
10509
    }
10510
    $matches = [];
10511
    preg_match_all('/<span.*?lang="(\w\w)">(.*?)<\/span>/is', $htmlString, $matches);
10512
    if (!empty($matches)) {
10513
        // matches[0] are the full string
10514
        // matches[1] are the languages
10515
        // matches[2] are the strings
10516
        foreach ($matches[1] as $id => $match) {
10517
            if ($match == $isoCode) {
10518
                return $matches[2][$id];
10519
            }
10520
        }
10521
        // Could find the pattern but could not find our language. Return the first language found.
10522
        return $matches[2][0];
10523
    }
10524
    // Could not find pattern. Just return the whole string. We shouldn't get here.
10525
    return $htmlString;
10526
}
10527
10528
/**
10529
 * Get the print.css file for current theme.
10530
 * Only the file path or the file contents when $getFileContents is true.
10531
 */
10532
function api_get_print_css(bool $getFileContents = true, bool $useWebPath = false): string
10533
{
10534
    $sysCssPath = api_get_path(SYS_CSS_PATH);
10535
    $cssFile = $sysCssPath.'themes/'.api_get_visual_theme().'/print.css';
10536
10537
    if (!file_exists($cssFile)) {
10538
        $cssFile = $sysCssPath.'print.css';
10539
    }
10540
10541
    if ($getFileContents) {
10542
        return file_get_contents($cssFile);
10543
    }
10544
10545
    if ($useWebPath) {
10546
        return str_replace($sysCssPath, api_get_path(WEB_CSS_PATH), $cssFile);
10547
    }
10548
10549
    return $cssFile;
10550
}
10551
10552
function api_protect_webservices()
10553
{
10554
    if (api_get_configuration_value('disable_webservices')) {
10555
        echo "Webservices are disabled. \n";
10556
        echo "To enable, add \$_configuration['disable_webservices'] = false; in configuration.php";
10557
        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...
10558
    }
10559
}
10560
10561
function api_filename_has_blacklisted_stream_wrapper(string $filename)
10562
{
10563
    if (strpos($filename, '://') > 0) {
10564
        $wrappers = stream_get_wrappers();
10565
        $allowedWrappers = ['http', 'https', 'file'];
10566
10567
        foreach ($wrappers as $wrapper) {
10568
            if (in_array($wrapper, $allowedWrappers)) {
10569
                continue;
10570
            }
10571
10572
            if (stripos($filename, $wrapper.'://') === 0) {
10573
                return true;
10574
            }
10575
        }
10576
    }
10577
10578
    return false;
10579
}
10580
10581
/**
10582
 * Calculate the percent between two numbers.
10583
 *
10584
 * @return string
10585
 */
10586
function api_calculate_increment_percent(int $newValue, int $oldValue)
10587
{
10588
    if ($oldValue <= 0) {
10589
        $result = " - ";
10590
    } else {
10591
        $result = ' '.round(100 * (($newValue / $oldValue) - 1), 2).' %';
10592
    }
10593
10594
    return $result;
10595
}
10596
10597
/**
10598
 * Erase settings from cache (because of some update) if applicable.
10599
 *
10600
 * @param int $url_id The ID of the present URL
10601
 */
10602
function api_flush_settings_cache(int $url_id): bool
10603
{
10604
    global $_configuration;
10605
    $cacheAvailable = api_get_configuration_value('apc');
10606
    if (!$cacheAvailable) {
10607
        return false;
10608
    }
10609
    $apcRootVarName = api_get_configuration_value('apc_prefix');
10610
    // Delete the APCu-stored settings array, if present
10611
    $apcVarName = $apcRootVarName.'settings';
10612
    apcu_delete($apcVarName);
10613
    if (api_is_multiple_url_enabled() && $url_id === 1) {
10614
        // if we are on the main URL of a multi-url portal, we must
10615
        // invalidate the cache for all other URLs as well as some
10616
        // main settings span multiple URLs
10617
        $urls = api_get_access_urls();
10618
        foreach ($urls as $i => $row) {
10619
            if ($row['id'] == 1) {
10620
                continue;
10621
            }
10622
            $apcVarName = $_configuration['main_database'].'_'.$row['id'].'_settings';
10623
            apcu_delete($apcVarName);
10624
        }
10625
    }
10626
10627
    return true;
10628
}
10629
10630
/**
10631
 * Decrypt sent data with encoded secret defined in app/config/configuration.php
10632
 * in the variable $_configuration['ldap_admin_password_salt'].
10633
 *
10634
 * @param $encryptedText The text to be decrypted
10635
 */
10636
function api_decrypt_ldap_password(string $encryptedText): string
10637
{
10638
    if (!empty(api_get_configuration_value('ldap_admin_password_salt'))) {
10639
        $secret = api_get_configuration_value('ldap_admin_password_salt');
10640
    } else {
10641
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the type-hinted return string.
Loading history...
10642
    }
10643
10644
    return api_decrypt_hash($encryptedText, $secret);
10645
}
10646
10647
/**
10648
 * Decrypt sent hash encoded with secret.
10649
 *
10650
 * @param $encryptedText The hash text to be decrypted
10651
 * @param $secret        The secret used to encoded the hash
10652
 *
10653
 * @return string The decrypted text or false
10654
 */
10655
function api_decrypt_hash(string $encryptedHash, string $secret): string
10656
{
10657
    $iv = base64_decode(substr($encryptedHash, 0, 16), true);
10658
    $data = base64_decode(substr($encryptedHash, 16), true);
10659
    $tag = substr($data, strlen($data) - 16);
10660
    $data = substr($data, 0, strlen($data) - 16);
10661
10662
    try {
10663
        return openssl_decrypt(
10664
        $data,
10665
        'aes-256-gcm',
10666
        $secret,
10667
        OPENSSL_RAW_DATA,
10668
        $iv,
10669
        $tag
10670
      );
10671
    } catch (\Exception $e) {
10672
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the type-hinted return string.
Loading history...
10673
    }
10674
}
10675
10676
/**
10677
 * Encrypt sent data with secret.
10678
 *
10679
 * @param $data   The text to be encrypted
10680
 * @param $secret The secret to use encode data
10681
 *
10682
 * @return string The encrypted text or false
10683
 */
10684
function api_encrypt_hash($data, $secret)
10685
{
10686
    $iv = random_bytes(12);
10687
    $tag = '';
10688
10689
    $encrypted = openssl_encrypt(
10690
    $data,
10691
    'aes-256-gcm',
10692
    $secret,
10693
    OPENSSL_RAW_DATA,
10694
    $iv,
10695
    $tag,
10696
    '',
10697
    16
10698
  );
10699
10700
    return base64_encode($iv).base64_encode($encrypted.$tag);
10701
}
10702