Passed
Push — master ( efc6d8...ea9271 )
by Julito
11:57
created

api_get_url_entity()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

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

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

1134
function api_protect_course_script($print_headers = false, $allow_session_admins = false, /** @scrutinizer ignore-unused */ $allow_drh = false)

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

Loading history...
1135
{
1136
    $is_allowed_in_course = api_is_allowed_in_course();
1137
1138
    $is_visible = false;
1139
    $course_info = api_get_course_info();
1140
1141
    if (empty($course_info)) {
1142
        api_not_allowed($print_headers);
1143
1144
        return false;
1145
    }
1146
1147
    if (api_is_drh()) {
1148
        return true;
1149
    }
1150
1151
    // Session admin has access to course
1152
    $sessionAccess = api_get_configuration_value('session_admins_access_all_content');
1153
    if ($sessionAccess) {
1154
        $allow_session_admins = true;
1155
    }
1156
1157
    if (api_is_platform_admin($allow_session_admins)) {
1158
        return true;
1159
    }
1160
1161
    if (isset($course_info) && isset($course_info['visibility'])) {
1162
        switch ($course_info['visibility']) {
1163
            default:
1164
            case COURSE_VISIBILITY_CLOSED:
1165
                // Completely closed: the course is only accessible to the teachers. - 0
1166
                if (api_get_user_id() && !api_is_anonymous() && $is_allowed_in_course) {
1167
                    $is_visible = true;
1168
                }
1169
                break;
1170
            case COURSE_VISIBILITY_REGISTERED:
1171
                // Private - access authorized to course members only - 1
1172
                if (api_get_user_id() && !api_is_anonymous() && $is_allowed_in_course) {
1173
                    $is_visible = true;
1174
                }
1175
                break;
1176
            case COURSE_VISIBILITY_OPEN_PLATFORM:
1177
                // Open - access allowed for users registered on the platform - 2
1178
                if (api_get_user_id() && !api_is_anonymous() && $is_allowed_in_course) {
1179
                    $is_visible = true;
1180
                }
1181
                break;
1182
            case COURSE_VISIBILITY_OPEN_WORLD:
1183
                //Open - access allowed for the whole world - 3
1184
                $is_visible = true;
1185
                break;
1186
            case COURSE_VISIBILITY_HIDDEN:
1187
                //Completely closed: the course is only accessible to the teachers. - 0
1188
                if (api_is_platform_admin()) {
1189
                    $is_visible = true;
1190
                }
1191
                break;
1192
        }
1193
1194
        //If password is set and user is not registered to the course then the course is not visible
1195
        if ($is_allowed_in_course == false &&
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

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

Loading history...
1196
            isset($course_info['registration_code']) &&
1197
            !empty($course_info['registration_code'])
1198
        ) {
1199
            $is_visible = false;
1200
        }
1201
    }
1202
1203
    // Check session visibility
1204
    $session_id = api_get_session_id();
1205
1206
    if (!empty($session_id)) {
1207
        //$is_allowed_in_course was set in local.inc.php
1208
        if (!$is_allowed_in_course) {
1209
            $is_visible = false;
1210
        }
1211
    }
1212
1213
    if (!$is_visible) {
1214
        api_not_allowed($print_headers);
1215
1216
        return false;
1217
    }
1218
1219
    return true;
1220
}
1221
1222
/**
1223
 * Function used to protect an admin script.
1224
 *
1225
 * The function blocks access when the user has no platform admin rights
1226
 * with an error message printed on default output
1227
 *
1228
 * @param bool Whether to allow session admins as well
1229
 * @param bool Whether to allow HR directors as well
1230
 * @param string An optional message (already passed through get_lang)
1231
 *
1232
 * @return bool True if user is allowed, false otherwise.
1233
 *              The function also outputs an error message in case not allowed
1234
 *
1235
 * @author Roan Embrechts (original author)
1236
 */
1237
function api_protect_admin_script($allow_sessions_admins = false, $allow_drh = false, $message = null)
1238
{
1239
    if (!api_is_platform_admin($allow_sessions_admins, $allow_drh)) {
1240
        api_not_allowed(true, $message);
1241
1242
        return false;
1243
    }
1244
1245
    return true;
1246
}
1247
1248
/**
1249
 * Function used to protect a teacher script.
1250
 * The function blocks access when the user has no teacher rights.
1251
 *
1252
 * @author Yoselyn Castillo
1253
 */
1254
function api_protect_teacher_script($allow_sessions_admins = false)
0 ignored issues
show
Unused Code introduced by
The parameter $allow_sessions_admins is not used and could be removed. ( Ignorable by Annotation )

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

1254
function api_protect_teacher_script(/** @scrutinizer ignore-unused */ $allow_sessions_admins = false)

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

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

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

1391
function api_get_user_courses($userId, /** @scrutinizer ignore-unused */ $fetch_session = true)

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

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

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

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

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

Loading history...
2032
{
2033
    if (!empty($course_code)) {
2034
        $course_code = Database::escape_string($course_code);
2035
        $courseId = api_get_course_int_id($course_code);
2036
2037
        if (empty($courseId)) {
2038
            return [];
2039
        }
2040
2041
        $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
2042
        $course_cat_table = Database::get_main_table(TABLE_MAIN_CATEGORY);
2043
        $sql = "SELECT
2044
                    course.*,
2045
                    course_category.code faCode,
2046
                    course_category.name faName
2047
                FROM $course_table
2048
                LEFT JOIN $course_cat_table
2049
                ON course.category_code = course_category.code
2050
                WHERE course.id = $courseId";
2051
        $result = Database::query($sql);
2052
        $courseInfo = [];
2053
        if (Database::num_rows($result) > 0) {
2054
            $data = Database::fetch_array($result);
2055
            $courseInfo = api_format_course_array($data);
2056
        }
2057
2058
        return $courseInfo;
2059
    }
2060
2061
    $_course = Session::read('_course');
2062
    if ($_course == '-1') {
2063
        $_course = [];
2064
    }
2065
2066
    return $_course;
2067
}
2068
2069
/**
2070
 * @param int $courseId
2071
 *
2072
 * @return \Chamilo\CoreBundle\Entity\Course
2073
 */
2074
function api_get_course_entity($courseId = 0)
2075
{
2076
    if (empty($courseId)) {
2077
        $courseId = api_get_course_int_id();
2078
    }
2079
2080
    return CourseManager::getManager()->find($courseId);
2081
}
2082
2083
/**
2084
 * @param int $id
2085
 *
2086
 * @return \Chamilo\CoreBundle\Entity\Session
2087
 */
2088
function api_get_session_entity($id = 0)
2089
{
2090
    if (empty($id)) {
2091
        $id = api_get_session_id();
2092
    }
2093
2094
    return Database::getManager()->getRepository('ChamiloCoreBundle:Session')->find($id);
2095
}
2096
2097
/**
2098
 * @param int $id
2099
 *
2100
 * @return \Chamilo\CoreBundle\Entity\AccessUrl
2101
 */
2102
function api_get_url_entity($id = 0)
2103
{
2104
    if (empty($id)) {
2105
        $id = api_get_current_access_url_id();
2106
    }
2107
2108
    return Database::getManager()->getRepository('ChamiloCoreBundle:AccessUrl')->find($id);
2109
}
2110
2111
2112
/**
2113
 * Returns the current course info array.
2114
2115
 * Now if the course_code is given, the returned array gives info about that
2116
 * particular course, not specially the current one.
2117
 *
2118
 * @param int $id Numeric ID of the course
2119
 *
2120
 * @return array The course info as an array formatted by api_format_course_array, including category.name
2121
 */
2122
function api_get_course_info_by_id($id = null)
2123
{
2124
    if (!empty($id)) {
2125
        $id = (int) $id;
2126
        $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
2127
        $course_cat_table = Database::get_main_table(TABLE_MAIN_CATEGORY);
2128
        $sql = "SELECT
2129
                    course.*,
2130
                    course_category.code faCode,
2131
                    course_category.name faName
2132
                FROM $course_table
2133
                LEFT JOIN $course_cat_table
2134
                ON course.category_code = course_category.code
2135
                WHERE course.id = $id";
2136
        $result = Database::query($sql);
2137
        $_course = [];
2138
        if (Database::num_rows($result) > 0) {
2139
            $row = Database::fetch_array($result);
2140
            $_course = api_format_course_array($row);
2141
        }
2142
2143
        return $_course;
2144
    }
2145
2146
    global $_course;
2147
    if ($_course == '-1') {
2148
        $_course = [];
2149
    }
2150
2151
    return $_course;
2152
}
2153
2154
/**
2155
 * Reformat the course array (output by api_get_course_info()) in order, mostly,
2156
 * to switch from 'code' to 'id' in the array. This is a legacy feature and is
2157
 * now possibly causing massive confusion as a new "id" field has been added to
2158
 * the course table in 1.9.0.
2159
 *
2160
 * @param $course_data
2161
 *
2162
 * @return array
2163
 *
2164
 * @todo eradicate the false "id"=code field of the $_course array and use the int id
2165
 */
2166
function api_format_course_array($course_data)
2167
{
2168
    if (empty($course_data)) {
2169
        return [];
2170
    }
2171
2172
    $_course = [];
2173
    $_course['id'] = $course_data['code'];
2174
    $_course['real_id'] = $course_data['id'];
2175
2176
    // Added
2177
    $_course['code'] = $course_data['code'];
2178
    $_course['name'] = $course_data['title'];
2179
    $_course['title'] = $course_data['title'];
2180
    $_course['official_code'] = $course_data['visual_code'];
2181
    $_course['visual_code'] = $course_data['visual_code'];
2182
    $_course['sysCode'] = $course_data['code'];
2183
    $_course['path'] = $course_data['directory']; // Use as key in path.
2184
    $_course['directory'] = $course_data['directory'];
2185
    $_course['creation_date'] = $course_data['creation_date'];
2186
    $_course['titular'] = $course_data['tutor_name'];
2187
    $_course['language'] = $course_data['course_language'];
2188
    $_course['extLink']['url'] = $course_data['department_url'];
2189
    $_course['extLink']['name'] = $course_data['department_name'];
2190
    $_course['categoryCode'] = $course_data['faCode'];
2191
    $_course['categoryName'] = $course_data['faName'];
2192
    $_course['visibility'] = $course_data['visibility'];
2193
    $_course['subscribe_allowed'] = $course_data['subscribe'];
2194
    $_course['subscribe'] = $course_data['subscribe'];
2195
    $_course['unsubscribe'] = $course_data['unsubscribe'];
2196
    $_course['course_language'] = $course_data['course_language'];
2197
    $_course['activate_legal'] = isset($course_data['activate_legal']) ? $course_data['activate_legal'] : false;
2198
    $_course['legal'] = $course_data['legal'];
2199
    $_course['show_score'] = $course_data['show_score']; //used in the work tool
2200
    $_course['department_name'] = $course_data['department_name'];
2201
    $_course['department_url'] = $course_data['department_url'];
2202
2203
    $courseSys = api_get_path(SYS_COURSE_PATH).$course_data['directory'];
2204
    $webCourseHome = api_get_path(WEB_COURSE_PATH).$course_data['directory'];
2205
2206
    // Course password
2207
    $_course['registration_code'] = !empty($course_data['registration_code']) ? sha1($course_data['registration_code']) : null;
2208
    $_course['disk_quota'] = $course_data['disk_quota'];
2209
    $_course['course_public_url'] = $webCourseHome.'/index.php';
2210
2211
    if (array_key_exists('add_teachers_to_sessions_courses', $course_data)) {
2212
        $_course['add_teachers_to_sessions_courses'] = $course_data['add_teachers_to_sessions_courses'];
2213
    }
2214
2215
    // Course image
2216
    $_course['course_image_source'] = '';
2217
    if (file_exists($courseSys.'/course-pic85x85.png')) {
2218
        $url_image = $webCourseHome.'/course-pic85x85.png';
2219
        $_course['course_image_source'] = $courseSys.'/course-pic85x85.png';
2220
    } else {
2221
        $url_image = Display::return_icon(
2222
            'course.png',
2223
            null,
2224
            null,
2225
            ICON_SIZE_BIG,
2226
            null,
2227
            true,
2228
            false
2229
        );
2230
    }
2231
    $_course['course_image'] = $url_image;
2232
2233
    // Course large image
2234
    $_course['course_image_large_source'] = '';
2235
    if (file_exists($courseSys.'/course-pic.png')) {
2236
        $url_image = $webCourseHome.'/course-pic.png';
2237
        $_course['course_image_large_source'] = $courseSys.'/course-pic.png';
2238
    } else {
2239
        $url_image = Display::return_icon(
2240
            'session_default.png',
2241
            null,
2242
            null,
2243
            null,
2244
            null,
2245
            true,
2246
            false
2247
        );
2248
    }
2249
    $_course['course_image_large'] = $url_image;
2250
2251
    return $_course;
2252
}
2253
2254
/**
2255
 * Returns a difficult to guess password.
2256
 *
2257
 * @param int $length the length of the password
2258
 *
2259
 * @return string the generated password
2260
 */
2261
function api_generate_password($length = 8)
2262
{
2263
    if ($length < 2) {
2264
        $length = 2;
2265
    }
2266
2267
    $charactersLowerCase = 'abcdefghijkmnopqrstuvwxyz';
2268
    $charactersUpperCase = 'ABCDEFGHJKLMNPQRSTUVWXYZ';
2269
    $minNumbers = 2;
2270
    $length = $length - $minNumbers;
2271
    $minLowerCase = round($length / 2);
2272
    $minUpperCase = $length - $minLowerCase;
2273
2274
    $password = '';
2275
    $passwordRequirements = api_get_configuration_value('password_requirements');
2276
2277
    $factory = new RandomLib\Factory();
2278
    $generator = $factory->getGenerator(new SecurityLib\Strength(SecurityLib\Strength::MEDIUM));
2279
2280
    if (!empty($passwordRequirements)) {
2281
        $length = $passwordRequirements['min']['length'];
2282
        $minNumbers = $passwordRequirements['min']['numeric'];
2283
        $minLowerCase = $passwordRequirements['min']['lowercase'];
2284
        $minUpperCase = $passwordRequirements['min']['uppercase'];
2285
2286
        $rest = $length - $minNumbers - $minLowerCase - $minUpperCase;
2287
        // Add the rest to fill the length requirement
2288
        if ($rest > 0) {
2289
            $password .= $generator->generateString($rest, $charactersLowerCase.$charactersUpperCase);
2290
        }
2291
    }
2292
2293
    // Min digits default 2
2294
    for ($i = 0; $i < $minNumbers; $i++) {
2295
        $password .= $generator->generateInt(2, 9);
2296
    }
2297
2298
    // Min lowercase
2299
    $password .= $generator->generateString($minLowerCase, $charactersLowerCase);
2300
2301
    // Min uppercase
2302
    $password .= $generator->generateString($minUpperCase, $charactersUpperCase);
2303
    $password = str_shuffle($password);
2304
2305
    return $password;
2306
}
2307
2308
/**
2309
 * Checks a password to see wether it is OK to use.
2310
 *
2311
 * @param string $password
2312
 *
2313
 * @return bool if the password is acceptable, false otherwise
2314
 *              Notes about what a password "OK to use" is:
2315
 *              1. The password should be at least 5 characters long.
2316
 *              2. Only English letters (uppercase or lowercase, it doesn't matter) and digits are allowed.
2317
 *              3. The password should contain at least 3 letters.
2318
 *              4. It should contain at least 2 digits.
2319
 *              Settings will change if the configuration value is set: password_requirements
2320
 */
2321
function api_check_password($password)
2322
{
2323
    $passwordRequirements = Security::getPasswordRequirements();
2324
2325
    $minLength = $passwordRequirements['min']['length'];
2326
    $minNumbers = $passwordRequirements['min']['numeric'];
2327
    // Optional
2328
    $minLowerCase = $passwordRequirements['min']['lowercase'];
2329
    $minUpperCase = $passwordRequirements['min']['uppercase'];
2330
2331
    $minLetters = $minLowerCase + $minUpperCase;
2332
    $passwordLength = api_strlen($password);
2333
2334
    $conditions = [
2335
        'min_length' => $passwordLength >= $minLength,
2336
    ];
2337
2338
    $digits = 0;
2339
    $lowerCase = 0;
2340
    $upperCase = 0;
2341
2342
    for ($i = 0; $i < $passwordLength; $i++) {
2343
        $currentCharacterCode = api_ord(api_substr($password, $i, 1));
2344
        if ($currentCharacterCode >= 65 && $currentCharacterCode <= 90) {
2345
            $upperCase++;
2346
        }
2347
2348
        if ($currentCharacterCode >= 97 && $currentCharacterCode <= 122) {
2349
            $lowerCase++;
2350
        }
2351
        if ($currentCharacterCode >= 48 && $currentCharacterCode <= 57) {
2352
            $digits++;
2353
        }
2354
    }
2355
2356
    // Min number of digits
2357
    $conditions['min_numeric'] = $digits >= $minNumbers;
2358
2359
    if (!empty($minUpperCase)) {
2360
        // Uppercase
2361
        $conditions['min_uppercase'] = $upperCase >= $minUpperCase;
2362
    }
2363
2364
    if (!empty($minLowerCase)) {
2365
        // Lowercase
2366
        $conditions['min_lowercase'] = $upperCase >= $minLowerCase;
2367
    }
2368
2369
    // Min letters
2370
    $letters = $upperCase + $lowerCase;
2371
    $conditions['min_letters'] = $letters >= $minLetters;
2372
2373
    $isPasswordOk = true;
2374
    foreach ($conditions as $condition) {
2375
        if ($condition === false) {
2376
            $isPasswordOk = false;
2377
            break;
2378
        }
2379
    }
2380
2381
    if ($isPasswordOk === false) {
2382
        $output = get_lang('NewPasswordRequirementsNotMatched').'<br />';
2383
        $output .= Security::getPasswordRequirementsToString($conditions);
2384
2385
        Display::addFlash(Display::return_message($output, 'warning', false));
2386
    }
2387
2388
    return $isPasswordOk;
2389
}
2390
2391
/**
2392
 * Clears the user ID from the session if it was the anonymous user. Generally
2393
 * used on out-of-tools pages to remove a user ID that could otherwise be used
2394
 * in the wrong context.
2395
 * This function is to be used in conjunction with the api_set_anonymous()
2396
 * function to simulate the user existence in case of an anonymous visit.
2397
 *
2398
 * @param bool      database check switch - passed to api_is_anonymous()
2399
 *
2400
 * @return bool true if succesfully unregistered, false if not anonymous
2401
 */
2402
function api_clear_anonymous($db_check = false)
2403
{
2404
    global $_user;
2405
    if (api_is_anonymous($_user['user_id'], $db_check)) {
2406
        unset($_user['user_id']);
2407
        Session::erase('_uid');
2408
2409
        return true;
2410
    }
2411
2412
    return false;
2413
}
2414
2415
/**
2416
 * Returns the status string corresponding to the status code.
2417
 *
2418
 * @author Noel Dieschburg
2419
 *
2420
 * @param the int status code
2421
 *
2422
 * @return string
2423
 */
2424
function get_status_from_code($status_code)
2425
{
2426
    switch ($status_code) {
2427
        case STUDENT:
2428
            return get_lang('Student', '');
2429
        case COURSEMANAGER:
2430
            return get_lang('Teacher', '');
2431
        case SESSIONADMIN:
2432
            return get_lang('SessionsAdmin', '');
2433
        case DRH:
2434
            return get_lang('Drh', '');
2435
    }
2436
}
2437
2438
/**
2439
 * Sets the current user as anonymous if it hasn't been identified yet. This
2440
 * function should be used inside a tool only. The function api_clear_anonymous()
2441
 * acts in the opposite direction by clearing the anonymous user's data every
2442
 * time we get on a course homepage or on a neutral page (index, admin, my space).
2443
 *
2444
 * @return bool true if set user as anonymous, false if user was already logged in or anonymous id could not be found
2445
 */
2446
function api_set_anonymous()
2447
{
2448
    return false;
2449
2450
    global $_user;
0 ignored issues
show
Unused Code introduced by
GlobalNode is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
2451
2452
    if (!empty($_user['user_id'])) {
2453
        return false;
2454
    }
2455
2456
    $user_id = api_get_anonymous_id();
2457
    if ($user_id == 0) {
2458
        return false;
2459
    }
2460
2461
    if (isset($_user['is_anonymous'])) {
2462
        return false;
2463
    }
2464
2465
    Session::erase('_user');
2466
    $_user['user_id'] = $user_id;
2467
    $_user['is_anonymous'] = true;
2468
    $GLOBALS['_user'] = $_user;
2469
    Session::write('_user', $_user);
2470
2471
    return true;
2472
}
2473
2474
/**
2475
 * Gets the current Chamilo (not PHP/cookie) session ID.
2476
 *
2477
 * @return int O if no active session, the session ID otherwise
2478
 */
2479
function api_get_session_id()
2480
{
2481
    return (int) Session::read('id_session', 0);
2482
}
2483
2484
/**
2485
 * Gets the current Chamilo (not social network) group ID.
2486
 *
2487
 * @return int O if no active session, the session ID otherwise
2488
 */
2489
function api_get_group_id()
2490
{
2491
    return Session::read('_gid', 0);
2492
}
2493
2494
/**
2495
 * Gets the current or given session name.
2496
 *
2497
 * @param   int     Session ID (optional)
2498
 *
2499
 * @return string The session name, or null if not found
2500
 */
2501
function api_get_session_name($session_id = 0)
2502
{
2503
    if (empty($session_id)) {
2504
        $session_id = api_get_session_id();
2505
        if (empty($session_id)) {
2506
            return null;
2507
        }
2508
    }
2509
    $t = Database::get_main_table(TABLE_MAIN_SESSION);
2510
    $s = "SELECT name FROM $t WHERE id = ".(int) $session_id;
2511
    $r = Database::query($s);
2512
    $c = Database::num_rows($r);
2513
    if ($c > 0) {
2514
        //technically, there can be only one, but anyway we take the first
2515
        $rec = Database::fetch_array($r);
2516
2517
        return $rec['name'];
2518
    }
2519
2520
    return null;
2521
}
2522
2523
/**
2524
 * Gets the session info by id.
2525
 *
2526
 * @param int $id Session ID
2527
 *
2528
 * @return array information of the session
2529
 */
2530
function api_get_session_info($id)
2531
{
2532
    return SessionManager::fetch($id);
2533
}
2534
2535
/**
2536
 * Gets the session visibility by session id.
2537
 *
2538
 * @param int  $session_id
2539
 * @param int  $courseId
2540
 * @param bool $ignore_visibility_for_admins
2541
 *
2542
 * @return int
2543
 *             0 = session still available,
2544
 *             SESSION_VISIBLE_READ_ONLY = 1,
2545
 *             SESSION_VISIBLE = 2,
2546
 *             SESSION_INVISIBLE = 3
2547
 */
2548
function api_get_session_visibility(
2549
    $session_id,
2550
    $courseId = null,
2551
    $ignore_visibility_for_admins = true
2552
) {
2553
    if (api_is_platform_admin()) {
2554
        if ($ignore_visibility_for_admins) {
2555
            return SESSION_AVAILABLE;
2556
        }
2557
    }
2558
2559
    $now = time();
2560
2561
    if (empty($session_id)) {
2562
        return 0; // Means that the session is still available.
2563
    }
2564
2565
    $session_id = (int) $session_id;
2566
    $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
2567
2568
    $result = Database::query("SELECT * FROM $tbl_session WHERE id = $session_id");
2569
2570
    if (Database::num_rows($result) <= 0) {
2571
        return SESSION_INVISIBLE;
2572
    }
2573
2574
    $row = Database::fetch_array($result, 'ASSOC');
2575
    $visibility = $original_visibility = $row['visibility'];
2576
2577
    // I don't care the session visibility.
2578
    if (empty($row['access_start_date']) && empty($row['access_end_date'])) {
2579
        // Session duration per student.
2580
        if (isset($row['duration']) && !empty($row['duration'])) {
2581
            $duration = $row['duration'] * 24 * 60 * 60;
2582
            $courseAccess = CourseManager::getFirstCourseAccessPerSessionAndUser($session_id, api_get_user_id());
2583
2584
            // If there is a session duration but there is no previous
2585
            // access by the user, then the session is still available
2586
            if (count($courseAccess) == 0) {
2587
                return SESSION_AVAILABLE;
2588
            }
2589
2590
            $currentTime = time();
2591
            $firstAccess = isset($courseAccess['login_course_date'])
2592
                ? api_strtotime($courseAccess['login_course_date'], 'UTC')
2593
                : 0;
2594
            $userDurationData = SessionManager::getUserSession(
2595
                api_get_user_id(),
2596
                $session_id
2597
            );
2598
            $userDuration = isset($userDurationData['duration'])
2599
                ? (intval($userDurationData['duration']) * 24 * 60 * 60)
2600
                : 0;
2601
2602
            $totalDuration = $firstAccess + $duration + $userDuration;
2603
2604
            return $totalDuration > $currentTime ? SESSION_AVAILABLE : SESSION_VISIBLE_READ_ONLY;
2605
        }
2606
2607
        return SESSION_AVAILABLE;
2608
    }
2609
2610
    // If start date was set.
2611
    if (!empty($row['access_start_date'])) {
2612
        $visibility = $now > api_strtotime($row['access_start_date'], 'UTC') ? SESSION_AVAILABLE : SESSION_INVISIBLE;
2613
    }
2614
2615
    // If the end date was set.
2616
    if (!empty($row['access_end_date'])) {
2617
        // Only if date_start said that it was ok
2618
        if ($visibility === SESSION_AVAILABLE) {
2619
            $visibility = $now < api_strtotime($row['access_end_date'], 'UTC')
2620
                ? SESSION_AVAILABLE // Date still available
2621
                : $row['visibility']; // Session ends
2622
        }
2623
    }
2624
2625
    // If I'm a coach the visibility can change in my favor depending in the coach dates.
2626
    $isCoach = api_is_coach($session_id, $courseId);
2627
2628
    if ($isCoach) {
2629
        // Test start date.
2630
        if (!empty($row['coach_access_start_date'])) {
2631
            $start = api_strtotime($row['coach_access_start_date'], 'UTC');
2632
            $visibility = $start < $now ? SESSION_AVAILABLE : SESSION_INVISIBLE;
2633
        }
2634
2635
        // Test end date.
2636
        if (!empty($row['coach_access_end_date'])) {
2637
            if ($visibility === SESSION_AVAILABLE) {
2638
                $endDateCoach = api_strtotime($row['coach_access_end_date'], 'UTC');
2639
                $visibility = $endDateCoach >= $now ? SESSION_AVAILABLE : $row['visibility'];
2640
            }
2641
        }
2642
    }
2643
2644
    return $visibility;
2645
}
2646
2647
/**
2648
 * This function returns a (star) session icon if the session is not null and
2649
 * the user is not a student.
2650
 *
2651
 * @param int $session_id
2652
 * @param int $status_id  User status id - if 5 (student), will return empty
2653
 *
2654
 * @return string Session icon
2655
 */
2656
function api_get_session_image($session_id, $status_id)
2657
{
2658
    $session_id = (int) $session_id;
2659
    $session_img = '';
2660
    if ((int) $status_id != 5) { //check whether is not a student
2661
        if ($session_id > 0) {
2662
            $session_img = "&nbsp;&nbsp;".Display::return_icon(
2663
                'star.png',
2664
                get_lang('SessionSpecificResource'),
2665
                ['align' => 'absmiddle'],
2666
                ICON_SIZE_SMALL
2667
            );
2668
        }
2669
    }
2670
2671
    return $session_img;
2672
}
2673
2674
/**
2675
 * This function add an additional condition according to the session of the course.
2676
 *
2677
 * @param int    $session_id        session id
2678
 * @param bool   $and               optional, true if more than one condition false if the only condition in the query
2679
 * @param bool   $with_base_content optional, true to accept content with session=0 as well,
2680
 *                                  false for strict session condition
2681
 * @param string $session_field
2682
 *
2683
 * @return string condition of the session
2684
 */
2685
function api_get_session_condition(
2686
    $session_id,
2687
    $and = true,
2688
    $with_base_content = false,
2689
    $session_field = 'session_id'
2690
) {
2691
    $session_id = (int) $session_id;
2692
2693
    if (empty($session_field)) {
2694
        $session_field = "session_id";
2695
    }
2696
    // Condition to show resources by session
2697
    $condition_add = $and ? " AND " : " WHERE ";
2698
2699
    if ($with_base_content) {
2700
        $condition_session = $condition_add." ( $session_field = $session_id OR $session_field = 0 OR $session_field IS NULL) ";
2701
    } else {
2702
        if (empty($session_id)) {
2703
            $condition_session = $condition_add." ($session_field = $session_id OR $session_field IS NULL)";
2704
        } else {
2705
            $condition_session = $condition_add." $session_field = $session_id ";
2706
        }
2707
    }
2708
2709
    return $condition_session;
2710
}
2711
2712
/**
2713
 * Returns the value of a setting from the web-adjustable admin config settings.
2714
 *
2715
 * WARNING true/false are stored as string, so when comparing you need to check e.g.
2716
 * if (api_get_setting('show_navigation_menu') == 'true') //CORRECT
2717
 * instead of
2718
 * if (api_get_setting('show_navigation_menu') == true) //INCORRECT
2719
 *
2720
 * @param string $variable The variable name
2721
 *
2722
 * @return string
2723
 */
2724
function api_get_setting($variable)
2725
{
2726
    $settingsManager = Container::getSettingsManager();
2727
    if (empty($settingsManager)) {
2728
        return '';
2729
    }
2730
    $variable = trim($variable);
2731
2732
    switch ($variable) {
2733
        case 'header_extra_content':
2734
            $filename = api_get_path(SYS_PATH).api_get_home_path().'header_extra_content.txt';
2735
            if (file_exists($filename)) {
2736
                $value = file_get_contents($filename);
2737
2738
                return $value;
2739
            } else {
2740
                return '';
2741
            }
2742
            break;
2743
        case 'footer_extra_content':
2744
            $filename = api_get_path(SYS_PATH).api_get_home_path().'footer_extra_content.txt';
2745
            if (file_exists($filename)) {
2746
                $value = file_get_contents($filename);
2747
2748
                return $value;
2749
            } else {
2750
                return '';
2751
            }
2752
            break;
2753
        case 'server_type':
2754
            $test = ['dev', 'test'];
2755
            $environment = Container::getEnvironment();
2756
            if (in_array($environment, $test)) {
2757
                return 'test';
2758
            }
2759
2760
            return 'prod';
2761
        case 'stylesheets':
2762
            $variable = 'platform.theme';
2763
        // deprecated settings
2764
        // no break
2765
        case 'openid_authentication':
2766
        case 'sso_authentication':
2767
        case 'service_ppt2lp':
2768
        case 'add_cas_login_button_cas_button_label':
2769
        case 'add_cas_login_button_cas_button_comment':
2770
        case 'add_cas_login_button_cas_image_url':
2771
        case 'add_cas_logout_button_cas_logout_label':
2772
        case 'add_cas_logout_button_cas_logout_comment':
2773
        case 'add_cas_logout_button_cas_logout_image_url':
2774
        case 'add_facebook_login_button_facebook_button_url':
2775
        case 'add_shibboleth_login_button_shibboleth_button_label':
2776
        case 'add_shibboleth_login_button_shibboleth_button_comment':
2777
        case 'add_shibboleth_login_button_shibboleth_image_url':
2778
        case 'formLogin_hide_unhide_label':
2779
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type string.
Loading history...
2780
            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...
2781
        case 'tool_visible_by_default_at_creation':
2782
            $values = $settingsManager->getSetting($variable);
2783
            $newResult = [];
2784
            foreach ($values as $parameter) {
2785
                $newResult[$parameter] = 'true';
2786
            }
2787
2788
            return $newResult;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $newResult returns the type array which is incompatible with the documented return type string.
Loading history...
2789
            break;
2790
        default:
2791
            return $settingsManager->getSetting($variable);
2792
            break;
2793
    }
2794
2795
    global $_setting;
0 ignored issues
show
Unused Code introduced by
GlobalNode is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
2796
    if ($variable == 'header_extra_content') {
2797
        $filename = api_get_home_path().'header_extra_content.txt';
2798
        if (file_exists($filename)) {
2799
            $value = file_get_contents($filename);
2800
2801
            return $value;
2802
        } else {
2803
            return '';
2804
        }
2805
    }
2806
    if ($variable == 'footer_extra_content') {
2807
        $filename = api_get_home_path().'footer_extra_content.txt';
2808
        if (file_exists($filename)) {
2809
            $value = file_get_contents($filename);
2810
2811
            return $value;
2812
        } else {
2813
            return '';
2814
        }
2815
    }
2816
    $value = null;
2817
    if (is_null($key)) {
2818
        $value = ((isset($_setting[$variable]) && $_setting[$variable] != '') ? $_setting[$variable] : null);
2819
    } else {
2820
        if (isset($_setting[$variable][$key])) {
2821
            $value = $_setting[$variable][$key];
2822
        }
2823
    }
2824
2825
    return $value;
2826
}
2827
2828
/**
2829
 * @param string $variable
2830
 * @param string $option
2831
 *
2832
 * @return bool
2833
 */
2834
function api_get_setting_in_list($variable, $option)
2835
{
2836
    $value = api_get_setting($variable);
2837
2838
    return in_array($option, $value);
2839
}
2840
2841
/**
2842
 * @param string $plugin
2843
 * @param string $variable
2844
 *
2845
 * @return string
2846
 */
2847
function api_get_plugin_setting($plugin, $variable)
2848
{
2849
    $variableName = $plugin.'_'.$variable;
2850
2851
    $params = [
2852
        'category = ? AND subkey = ? AND variable = ?' => [
2853
            'Plugins',
2854
            $plugin,
2855
            $variableName,
2856
        ],
2857
    ];
2858
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2859
    $result = Database::select(
2860
        'selected_value',
2861
        $table,
2862
        ['where' => $params],
2863
        'one'
2864
    );
2865
    if ($result) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $result of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
2866
        $value = $result['selected_value'];
2867
        $serializedValue = @unserialize($result['selected_value'], []);
2868
        if ($serializedValue !== false) {
2869
            $value = $serializedValue;
2870
        }
2871
2872
        return $value;
2873
    }
2874
2875
    return null;
2876
    /// Old code
2877
2878
    $variableName = $plugin.'_'.$variable;
0 ignored issues
show
Unused Code introduced by
$variableName = $plugin . '_' . $variable is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
2879
    $result = api_get_setting($variableName);
2880
2881
    if (isset($result[$plugin])) {
2882
        $value = $result[$plugin];
2883
        if (@unserialize($value) !== false) {
2884
            $value = unserialize($value);
2885
        }
2886
2887
        return $value;
2888
    }
2889
2890
    return null;
2891
}
2892
2893
/**
2894
 * Returns the value of a setting from the web-adjustable admin config settings.
2895
 */
2896
function api_get_settings_params($params)
2897
{
2898
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2899
    $result = Database::select('*', $table, ['where' => $params]);
2900
2901
    return $result;
2902
}
2903
2904
/**
2905
 * @param array $params example: [id = ? => '1']
2906
 *
2907
 * @return array
2908
 */
2909
function api_get_settings_params_simple($params)
2910
{
2911
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2912
    $result = Database::select('*', $table, ['where' => $params], 'one');
2913
2914
    return $result;
2915
}
2916
2917
/**
2918
 * Returns the value of a setting from the web-adjustable admin config settings.
2919
 */
2920
function api_delete_settings_params($params)
2921
{
2922
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2923
    $result = Database::delete($table, $params);
2924
2925
    return $result;
2926
}
2927
2928
/**
2929
 * Returns an escaped version of $_SERVER['PHP_SELF'] to avoid XSS injection.
2930
 *
2931
 * @return string Escaped version of $_SERVER['PHP_SELF']
2932
 */
2933
function api_get_self()
2934
{
2935
    return htmlentities($_SERVER['PHP_SELF']);
2936
}
2937
2938
/* USER PERMISSIONS */
2939
2940
/**
2941
 * Checks whether current user is a platform administrator.
2942
 *
2943
 * @param bool $allowSessionAdmins Whether session admins should be considered admins or not
2944
 * @param bool $allowDrh           Whether HR directors should be considered admins or not
2945
 *
2946
 * @return bool true if the user has platform admin rights,
2947
 *              false otherwise
2948
 *
2949
 * @see usermanager::is_admin(user_id) for a user-id specific function
2950
 */
2951
function api_is_platform_admin($allowSessionAdmins = false, $allowDrh = false)
2952
{
2953
    $isAdmin = Session::read('is_platformAdmin');
2954
    if ($isAdmin) {
2955
        return true;
2956
    }
2957
    $user = api_get_user_info();
2958
2959
    return
2960
        isset($user['status']) &&
2961
        (
2962
            ($allowSessionAdmins && $user['status'] == SESSIONADMIN) ||
2963
            ($allowDrh && $user['status'] == DRH)
2964
        );
2965
}
2966
2967
/**
2968
 * Checks whether the user given as user id is in the admin table.
2969
 *
2970
 * @param int $user_id If none provided, will use current user
2971
 * @param int $url     URL ID. If provided, also check if the user is active on given URL
2972
 *
2973
 * @return bool True if the user is admin, false otherwise
2974
 */
2975
function api_is_platform_admin_by_id($user_id = null, $url = null)
2976
{
2977
    $user_id = (int) $user_id;
2978
    if (empty($user_id)) {
2979
        $user_id = api_get_user_id();
2980
    }
2981
    $admin_table = Database::get_main_table(TABLE_MAIN_ADMIN);
2982
    $sql = "SELECT * FROM $admin_table WHERE user_id = $user_id";
2983
    $res = Database::query($sql);
2984
    $is_admin = Database::num_rows($res) === 1;
2985
    if (!$is_admin || !isset($url)) {
2986
        return $is_admin;
2987
    }
2988
    // We get here only if $url is set
2989
    $url = (int) $url;
2990
    $url_user_table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
2991
    $sql = "SELECT * FROM $url_user_table
2992
            WHERE access_url_id = $url AND user_id = $user_id";
2993
    $res = Database::query($sql);
2994
    $result = Database::num_rows($res) === 1;
2995
2996
    return $result;
2997
}
2998
2999
/**
3000
 * Returns the user's numeric status ID from the users table.
3001
 *
3002
 * @param int $user_id If none provided, will use current user
3003
 *
3004
 * @return int User's status (1 for teacher, 5 for student, etc)
3005
 */
3006
function api_get_user_status($user_id = null)
3007
{
3008
    $user_id = (int) $user_id;
3009
    if (empty($user_id)) {
3010
        $user_id = api_get_user_id();
3011
    }
3012
    $table = Database::get_main_table(TABLE_MAIN_USER);
3013
    $sql = "SELECT status FROM $table WHERE user_id = $user_id ";
3014
    $result = Database::query($sql);
3015
    $status = null;
3016
    if (Database::num_rows($result)) {
3017
        $row = Database::fetch_array($result);
3018
        $status = $row['status'];
3019
    }
3020
3021
    return $status;
3022
}
3023
3024
/**
3025
 * Checks whether current user is allowed to create courses.
3026
 *
3027
 * @return bool true if the user has course creation rights,
3028
 *              false otherwise
3029
 */
3030
function api_is_allowed_to_create_course()
3031
{
3032
    if (api_is_platform_admin()) {
3033
        return true;
3034
    }
3035
3036
    // Teachers can only create courses
3037
    if (api_is_teacher()) {
3038
        if (api_get_setting('allow_users_to_create_courses') === 'true') {
3039
            return true;
3040
        } else {
3041
            return false;
3042
        }
3043
    }
3044
3045
    return Session::read('is_allowedCreateCourse');
3046
}
3047
3048
/**
3049
 * Checks whether the current user is a course administrator.
3050
 *
3051
 * @return bool True if current user is a course administrator
3052
 */
3053
function api_is_course_admin()
3054
{
3055
    if (api_is_platform_admin()) {
3056
        return true;
3057
    }
3058
3059
    return Session::read('is_courseAdmin');
3060
}
3061
3062
/**
3063
 * Checks whether the current user is a course coach
3064
 * Based on the presence of user in session.id_coach (session general coach).
3065
 *
3066
 * @return bool True if current user is a course coach
3067
 */
3068
function api_is_session_general_coach()
3069
{
3070
    return Session::read('is_session_general_coach');
3071
}
3072
3073
/**
3074
 * Checks whether the current user is a course tutor
3075
 * Based on the presence of user in session_rel_course_rel_user.user_id with status = 2.
3076
 *
3077
 * @return bool True if current user is a course tutor
3078
 */
3079
function api_is_course_tutor()
3080
{
3081
    return Session::read('is_courseTutor');
3082
}
3083
3084
/**
3085
 * @param int $user_id
3086
 * @param int $courseId
3087
 * @param int $session_id
3088
 *
3089
 * @return bool
3090
 */
3091
function api_is_course_session_coach($user_id, $courseId, $session_id)
3092
{
3093
    $session_table = Database::get_main_table(TABLE_MAIN_SESSION);
3094
    $session_rel_course_rel_user_table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3095
3096
    $user_id = (int) $user_id;
3097
    $session_id = (int) $session_id;
3098
    $courseId = (int) $courseId;
3099
3100
    $sql = "SELECT DISTINCT session.id
3101
            FROM $session_table
3102
            INNER JOIN $session_rel_course_rel_user_table session_rc_ru
3103
            ON session.id = session_rc_ru.session_id
3104
            WHERE
3105
                session_rc_ru.user_id = '".$user_id."'  AND
3106
                session_rc_ru.c_id = '$courseId' AND
3107
                session_rc_ru.status = 2 AND
3108
                session_rc_ru.session_id = '$session_id'";
3109
    $result = Database::query($sql);
3110
3111
    return Database::num_rows($result) > 0;
3112
}
3113
3114
/**
3115
 * Checks whether the current user is a course or session coach.
3116
 *
3117
 * @param int $session_id
3118
 * @param int $courseId
3119
 * @param bool  Check whether we are in student view and, if we are, return false
3120
 *
3121
 * @return bool True if current user is a course or session coach
3122
 */
3123
function api_is_coach($session_id = 0, $courseId = null, $check_student_view = true)
3124
{
3125
    $userId = api_get_user_id();
3126
3127
    if (!empty($session_id)) {
3128
        $session_id = (int) $session_id;
3129
    } else {
3130
        $session_id = api_get_session_id();
3131
    }
3132
3133
    // The student preview was on
3134
    if ($check_student_view && api_is_student_view_active()) {
3135
        return false;
3136
    }
3137
3138
    if (!empty($courseId)) {
3139
        $courseId = (int) $courseId;
3140
    } else {
3141
        $courseId = api_get_course_int_id();
3142
    }
3143
3144
    $session_table = Database::get_main_table(TABLE_MAIN_SESSION);
3145
    $session_rel_course_rel_user_table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3146
    $sessionIsCoach = [];
3147
3148
    if (!empty($courseId)) {
3149
        $sql = "SELECT DISTINCT s.id, name, access_start_date, access_end_date
3150
                FROM $session_table s
3151
                INNER JOIN $session_rel_course_rel_user_table session_rc_ru
3152
                ON session_rc_ru.session_id = s.id AND session_rc_ru.user_id = '".$userId."'
3153
                WHERE
3154
                    session_rc_ru.c_id = '$courseId' AND
3155
                    session_rc_ru.status = 2 AND
3156
                    session_rc_ru.session_id = '$session_id'";
3157
        $result = Database::query($sql);
3158
        $sessionIsCoach = Database::store_result($result);
3159
    }
3160
3161
    if (!empty($session_id)) {
3162
        $sql = "SELECT DISTINCT id, name, access_start_date, access_end_date
3163
                FROM $session_table
3164
                WHERE session.id_coach = $userId AND id = $session_id
3165
                ORDER BY access_start_date, access_end_date, name";
3166
        $result = Database::query($sql);
3167
        if (!empty($sessionIsCoach)) {
3168
            $sessionIsCoach = array_merge(
3169
                $sessionIsCoach,
3170
                Database::store_result($result)
3171
            );
3172
        } else {
3173
            $sessionIsCoach = Database::store_result($result);
3174
        }
3175
    }
3176
3177
    return count($sessionIsCoach) > 0;
3178
}
3179
3180
/**
3181
 * Checks whether the current user is a session administrator.
3182
 *
3183
 * @return bool True if current user is a course administrator
3184
 */
3185
function api_is_session_admin()
3186
{
3187
    $user = api_get_user_info();
3188
3189
    return isset($user['status']) && $user['status'] == SESSIONADMIN;
3190
}
3191
3192
/**
3193
 * Checks whether the current user is a human resources manager.
3194
 *
3195
 * @return bool True if current user is a human resources manager
3196
 */
3197
function api_is_drh()
3198
{
3199
    $user = api_get_user_info();
3200
3201
    return isset($user['status']) && $user['status'] == DRH;
3202
}
3203
3204
/**
3205
 * Checks whether the current user is a student.
3206
 *
3207
 * @return bool True if current user is a human resources manager
3208
 */
3209
function api_is_student()
3210
{
3211
    $user = api_get_user_info();
3212
3213
    return isset($user['status']) && $user['status'] == STUDENT;
3214
}
3215
3216
/**
3217
 * Checks whether the current user has the status 'teacher'.
3218
 *
3219
 * @return bool True if current user is a human resources manager
3220
 */
3221
function api_is_teacher()
3222
{
3223
    $user = api_get_user_info();
3224
3225
    return isset($user['status']) && $user['status'] == COURSEMANAGER;
3226
}
3227
3228
/**
3229
 * Checks whether the current user is a invited user.
3230
 *
3231
 * @return bool
3232
 */
3233
function api_is_invitee()
3234
{
3235
    $user = api_get_user_info();
3236
3237
    return isset($user['status']) && $user['status'] == INVITEE;
3238
}
3239
3240
/**
3241
 * This function checks whether a session is assigned into a category.
3242
 *
3243
 * @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...
3244
 * @param string    - category name
3245
 *
3246
 * @return bool - true if is found, otherwise false
3247
 */
3248
function api_is_session_in_category($session_id, $category_name)
3249
{
3250
    $session_id = (int) $session_id;
3251
    $category_name = Database::escape_string($category_name);
3252
    $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
3253
    $tbl_session_category = Database::get_main_table(TABLE_MAIN_SESSION_CATEGORY);
3254
3255
    $sql = "SELECT 1
3256
            FROM $tbl_session
3257
            WHERE $session_id IN (
3258
                SELECT s.id FROM $tbl_session s, $tbl_session_category sc
3259
                WHERE
3260
                  s.session_category_id = sc.id AND
3261
                  sc.name LIKE '%$category_name'
3262
            )";
3263
    $rs = Database::query($sql);
3264
3265
    if (Database::num_rows($rs) > 0) {
3266
        return true;
3267
    } else {
3268
        return false;
3269
    }
3270
}
3271
3272
/**
3273
 * Displays the title of a tool.
3274
 * Normal use: parameter is a string:
3275
 * api_display_tool_title("My Tool").
3276
 *
3277
 * Optionally, there can be a subtitle below
3278
 * the normal title, and / or a supra title above the normal title.
3279
 *
3280
 * e.g. supra title:
3281
 * group
3282
 * GROUP PROPERTIES
3283
 *
3284
 * e.g. subtitle:
3285
 * AGENDA
3286
 * calender & events tool
3287
 *
3288
 * @author Hugues Peeters <[email protected]>
3289
 *
3290
 * @param mixed $title_element - it could either be a string or an array
3291
 *                             containing 'supraTitle', 'mainTitle',
3292
 *                             'subTitle'
3293
 */
3294
function api_display_tool_title($title_element)
3295
{
3296
    if (is_string($title_element)) {
3297
        $tit = $title_element;
3298
        unset($title_element);
3299
        $title_element['mainTitle'] = $tit;
3300
    }
3301
    echo '<h3>';
3302
    if (!empty($title_element['supraTitle'])) {
3303
        echo '<small>'.$title_element['supraTitle'].'</small><br />';
3304
    }
3305
    if (!empty($title_element['mainTitle'])) {
3306
        echo $title_element['mainTitle'];
3307
    }
3308
    if (!empty($title_element['subTitle'])) {
3309
        echo '<br /><small>'.$title_element['subTitle'].'</small>';
3310
    }
3311
    echo '</h3>';
3312
}
3313
3314
/**
3315
 * Displays options for switching between student view and course manager view.
3316
 *
3317
 * Changes in version 1.2 (Patrick Cool)
3318
 * Student view switch now behaves as a real switch. It maintains its current state until the state
3319
 * is changed explicitly
3320
 *
3321
 * Changes in version 1.1 (Patrick Cool)
3322
 * student view now works correctly in subfolders of the document tool
3323
 * student view works correctly in the new links tool
3324
 *
3325
 * Example code for using this in your tools:
3326
 * //if ($is_courseAdmin && api_get_setting('student_view_enabled') == 'true') {
3327
 * //   display_tool_view_option($isStudentView);
3328
 * //}
3329
 * //and in later sections, use api_is_allowed_to_edit()
3330
 *
3331
 * @author Roan Embrechts
3332
 * @author Patrick Cool
3333
 * @author Julio Montoya, changes added in Chamilo
3334
 *
3335
 * @version 1.2
3336
 *
3337
 * @todo rewrite code so it is easier to understand
3338
 */
3339
function api_display_tool_view_option()
3340
{
3341
    if (api_get_setting('student_view_enabled') != 'true') {
3342
        return '';
3343
    }
3344
3345
    $sourceurl = '';
3346
    $is_framed = false;
3347
    // Exceptions apply for all multi-frames pages
3348
    if (strpos($_SERVER['REQUEST_URI'], 'chat/chat_banner.php') !== false) {
3349
        // The chat is a multiframe bit that doesn't work too well with the student_view, so do not show the link
3350
        return '';
3351
    }
3352
3353
    // Uncomment to remove student view link from document view page
3354
    if (strpos($_SERVER['REQUEST_URI'], 'lp/lp_header.php') !== false) {
3355
        if (empty($_GET['lp_id'])) {
3356
            return '';
3357
        }
3358
        $sourceurl = substr($_SERVER['REQUEST_URI'], 0, strpos($_SERVER['REQUEST_URI'], '?'));
3359
        $sourceurl = str_replace(
3360
            'lp/lp_header.php',
3361
            'lp/lp_controller.php?'.api_get_cidreq().'&action=view&lp_id='.intval($_GET['lp_id']).'&isStudentView='.($_SESSION['studentview'] == 'studentview' ? 'false' : 'true'),
3362
            $sourceurl
3363
        );
3364
        //showinframes doesn't handle student view anyway...
3365
        //return '';
3366
        $is_framed = true;
3367
    }
3368
3369
    // Check whether the $_SERVER['REQUEST_URI'] contains already url parameters (thus a questionmark)
3370
    if (!$is_framed) {
3371
        if (strpos($_SERVER['REQUEST_URI'], '?') === false) {
3372
            $sourceurl = api_get_self().'?'.api_get_cidreq();
3373
        } else {
3374
            $sourceurl = $_SERVER['REQUEST_URI'];
3375
        }
3376
    }
3377
3378
    $output_string = '';
3379
    if (!empty($_SESSION['studentview'])) {
3380
        if ($_SESSION['studentview'] == 'studentview') {
3381
            // We have to remove the isStudentView=true from the $sourceurl
3382
            $sourceurl = str_replace('&isStudentView=true', '', $sourceurl);
3383
            $sourceurl = str_replace('&isStudentView=false', '', $sourceurl);
3384
            $output_string .= '<a class="btn btn-primary btn-sm" href="'.$sourceurl.'&isStudentView=false" target="_self">'.
3385
                Display::returnFontAwesomeIcon('eye').' '.get_lang('SwitchToTeacherView').'</a>';
3386
        } elseif ($_SESSION['studentview'] == 'teacherview') {
3387
            // Switching to teacherview
3388
            $sourceurl = str_replace('&isStudentView=true', '', $sourceurl);
3389
            $sourceurl = str_replace('&isStudentView=false', '', $sourceurl);
3390
            $output_string .= '<a class="btn btn-default btn-sm" href="'.$sourceurl.'&isStudentView=true" target="_self">'.
3391
                Display::returnFontAwesomeIcon('eye').' '.get_lang('SwitchToStudentView').'</a>';
3392
        }
3393
    } else {
3394
        $output_string .= '<a class="btn btn-default btn-sm" href="'.$sourceurl.'&isStudentView=true" target="_self">'.
3395
            Display::returnFontAwesomeIcon('eye').' '.get_lang('SwitchToStudentView').'</a>';
3396
    }
3397
    $html = Display::tag('div', $output_string, ['class' => 'view-options']);
3398
3399
    return $html;
3400
}
3401
3402
// TODO: This is for the permission section.
3403
/**
3404
 * Function that removes the need to directly use is_courseAdmin global in
3405
 * tool scripts. It returns true or false depending on the user's rights in
3406
 * this particular course.
3407
 * Optionally checking for tutor and coach roles here allows us to use the
3408
 * student_view feature altogether with these roles as well.
3409
 *
3410
 * @param bool  Whether to check if the user has the tutor role
3411
 * @param bool  Whether to check if the user has the coach role
3412
 * @param bool  Whether to check if the user has the session coach role
3413
 * @param bool  check the student view or not
3414
 *
3415
 * @author Roan Embrechts
3416
 * @author Patrick Cool
3417
 * @author Julio Montoya
3418
 *
3419
 * @version 1.1, February 2004
3420
 *
3421
 * @return bool true: the user has the rights to edit, false: he does not
3422
 */
3423
function api_is_allowed_to_edit(
3424
    $tutor = false,
3425
    $coach = false,
3426
    $session_coach = false,
3427
    $check_student_view = true
3428
) {
3429
    // Admins can edit anything.
3430
    if (api_is_platform_admin(false)) {
3431
        //The student preview was on
3432
        if ($check_student_view && api_is_student_view_active()) {
3433
            return false;
3434
        } else {
3435
            return true;
3436
        }
3437
    }
3438
3439
    $sessionId = api_get_session_id();
3440
3441
    if ($sessionId && api_get_configuration_value('session_courses_read_only_mode')) {
3442
        $efv = new ExtraFieldValue('course');
3443
        $lockExrafieldField = $efv->get_values_by_handler_and_field_variable(
3444
            api_get_course_int_id(),
3445
            'session_courses_read_only_mode'
3446
        );
3447
3448
        if (!empty($lockExrafieldField['value'])) {
3449
            return false;
3450
        }
3451
    }
3452
3453
    $is_allowed_coach_to_edit = api_is_coach(null, null, $check_student_view);
3454
    $session_visibility = api_get_session_visibility($sessionId);
3455
    $is_courseAdmin = api_is_course_admin();
3456
3457
    if (!$is_courseAdmin && $tutor) {
3458
        // If we also want to check if the user is a tutor...
3459
        $is_courseAdmin = $is_courseAdmin || api_is_course_tutor();
3460
    }
3461
3462
    if (!$is_courseAdmin && $coach) {
3463
        // If we also want to check if the user is a coach...';
3464
        // Check if session visibility is read only for coaches.
3465
        if ($session_visibility == SESSION_VISIBLE_READ_ONLY) {
3466
            $is_allowed_coach_to_edit = false;
3467
        }
3468
3469
        if (api_get_setting('allow_coach_to_edit_course_session') == 'true') {
3470
            // Check if coach is allowed to edit a course.
3471
            $is_courseAdmin = $is_courseAdmin || $is_allowed_coach_to_edit;
3472
        }
3473
    }
3474
3475
    if (!$is_courseAdmin && $session_coach) {
3476
        $is_courseAdmin = $is_courseAdmin || $is_allowed_coach_to_edit;
3477
    }
3478
3479
    // Check if the student_view is enabled, and if so, if it is activated.
3480
    if (api_get_setting('student_view_enabled') == 'true') {
3481
        if (!empty($sessionId)) {
3482
            // Check if session visibility is read only for coaches.
3483
            if ($session_visibility == SESSION_VISIBLE_READ_ONLY) {
3484
                $is_allowed_coach_to_edit = false;
3485
            }
3486
3487
            if (api_get_setting('allow_coach_to_edit_course_session') == 'true') {
3488
                // Check if coach is allowed to edit a course.
3489
                $is_allowed = $is_allowed_coach_to_edit;
3490
            } else {
3491
                $is_allowed = false;
3492
            }
3493
            if ($check_student_view) {
3494
                $is_allowed = $is_allowed && $_SESSION['studentview'] != 'studentview';
3495
            }
3496
        } else {
3497
            if ($check_student_view) {
3498
                $is_allowed = $is_courseAdmin && $_SESSION['studentview'] != 'studentview';
3499
            } else {
3500
                $is_allowed = $is_courseAdmin;
3501
            }
3502
        }
3503
3504
        return $is_allowed;
3505
    } else {
3506
        return $is_courseAdmin;
3507
    }
3508
}
3509
3510
/**
3511
 * Returns true if user is a course coach of at least one course in session.
3512
 *
3513
 * @param int $sessionId
3514
 *
3515
 * @return bool
3516
 */
3517
function api_is_coach_of_course_in_session($sessionId)
3518
{
3519
    if (api_is_platform_admin()) {
3520
        return true;
3521
    }
3522
3523
    $userId = api_get_user_id();
3524
    $courseList = UserManager::get_courses_list_by_session(
3525
        $userId,
3526
        $sessionId
3527
    );
3528
3529
    // Session visibility.
3530
    $visibility = api_get_session_visibility(
3531
        $sessionId,
3532
        null,
3533
        false
3534
    );
3535
3536
    if ($visibility != SESSION_VISIBLE && !empty($courseList)) {
3537
        // Course Coach session visibility.
3538
        $blockedCourseCount = 0;
3539
        $closedVisibilityList = [
3540
            COURSE_VISIBILITY_CLOSED,
3541
            COURSE_VISIBILITY_HIDDEN,
3542
        ];
3543
3544
        foreach ($courseList as $course) {
3545
            // Checking session visibility
3546
            $sessionCourseVisibility = api_get_session_visibility(
3547
                $sessionId,
3548
                $course['real_id']
3549
            );
3550
3551
            $courseIsVisible = !in_array(
3552
                $course['visibility'],
3553
                $closedVisibilityList
3554
            );
3555
            if ($courseIsVisible === false || $sessionCourseVisibility == SESSION_INVISIBLE) {
3556
                $blockedCourseCount++;
3557
            }
3558
        }
3559
3560
        // If all courses are blocked then no show in the list.
3561
        if ($blockedCourseCount === count($courseList)) {
3562
            $visibility = SESSION_INVISIBLE;
3563
        } else {
3564
            $visibility = SESSION_VISIBLE;
3565
        }
3566
    }
3567
3568
    switch ($visibility) {
3569
        case SESSION_VISIBLE_READ_ONLY:
3570
        case SESSION_VISIBLE:
3571
        case SESSION_AVAILABLE:
3572
            return true;
3573
            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...
3574
        case SESSION_INVISIBLE:
3575
            return false;
3576
    }
3577
3578
    return false;
3579
}
3580
3581
/**
3582
 * Checks if a student can edit contents in a session depending
3583
 * on the session visibility.
3584
 *
3585
 * @param bool $tutor Whether to check if the user has the tutor role
3586
 * @param bool $coach Whether to check if the user has the coach role
3587
 *
3588
 * @return bool true: the user has the rights to edit, false: he does not
3589
 */
3590
function api_is_allowed_to_session_edit($tutor = false, $coach = false)
3591
{
3592
    if (api_is_allowed_to_edit($tutor, $coach)) {
3593
        // If I'm a teacher, I will return true in order to not affect the normal behaviour of Chamilo tools.
3594
        return true;
3595
    } else {
3596
        $sessionId = api_get_session_id();
3597
3598
        if ($sessionId == 0) {
3599
            // I'm not in a session so i will return true to not affect the normal behaviour of Chamilo tools.
3600
            return true;
3601
        } else {
3602
            // I'm in a session and I'm a student
3603
            // Get the session visibility
3604
            $session_visibility = api_get_session_visibility($sessionId);
3605
            // if 5 the session is still available
3606
            switch ($session_visibility) {
3607
                case SESSION_VISIBLE_READ_ONLY: // 1
3608
                    return false;
3609
                case SESSION_VISIBLE:           // 2
3610
                    return true;
3611
                case SESSION_INVISIBLE:         // 3
3612
                    return false;
3613
                case SESSION_AVAILABLE:         //5
3614
                    return true;
3615
            }
3616
        }
3617
    }
3618
}
3619
3620
/**
3621
 * Checks whether the user is allowed in a specific tool for a specific action.
3622
 *
3623
 * @param string $tool   the tool we are checking if the user has a certain permission
3624
 * @param string $action the action we are checking (add, edit, delete, move, visibility)
3625
 *
3626
 * @return bool
3627
 *
3628
 * @author Patrick Cool <[email protected]>, Ghent University
3629
 * @author Julio Montoya
3630
 *
3631
 * @version 1.0
3632
 */
3633
function api_is_allowed($tool, $action, $task_id = 0)
3634
{
3635
    $_user = api_get_user_info();
3636
    $_course = api_get_course_info();
3637
3638
    if (api_is_course_admin()) {
3639
        return true;
3640
    }
3641
3642
    if (is_array($_course) and count($_course) > 0) {
3643
        require_once api_get_path(SYS_CODE_PATH).'permissions/permissions_functions.inc.php';
3644
3645
        // Getting the permissions of this user.
3646
        if ($task_id == 0) {
3647
            $user_permissions = get_permissions('user', $_user['user_id']);
3648
            $_SESSION['total_permissions'][$_course['code']] = $user_permissions;
3649
        }
3650
3651
        // Getting the permissions of the task.
3652
        if ($task_id != 0) {
3653
            $task_permissions = get_permissions('task', $task_id);
3654
            /* !!! */$_SESSION['total_permissions'][$_course['code']] = $task_permissions;
3655
        }
3656
        //print_r($_SESSION['total_permissions']);
3657
3658
        // Getting the permissions of the groups of the user
3659
        //$groups_of_user = GroupManager::get_group_ids($_course['db_name'], $_user['user_id']);
3660
3661
        //foreach($groups_of_user as $group)
3662
        //   $this_group_permissions = get_permissions('group', $group);
3663
3664
        // Getting the permissions of the courseroles of the user
3665
        $user_courserole_permissions = get_roles_permissions('user', $_user['user_id']);
3666
3667
        // Getting the permissions of the platformroles of the user
3668
        //$user_platformrole_permissions = get_roles_permissions('user', $_user['user_id'], ', platform');
3669
3670
        // Getting the permissions of the roles of the groups of the user
3671
        //foreach($groups_of_user as $group)
3672
        //    $this_group_courserole_permissions = get_roles_permissions('group', $group);
3673
3674
        // Getting the permissions of the platformroles of the groups of the user
3675
        //foreach($groups_of_user as $group)
3676
        //    $this_group_platformrole_permissions = get_roles_permissions('group', $group, 'platform');
3677
    }
3678
3679
    // If the permissions are limited, we have to map the extended ones to the limited ones.
3680
    if (api_get_setting('permissions') == 'limited') {
3681
        if ($action == 'Visibility') {
3682
            $action = 'Edit';
3683
        }
3684
        if ($action == 'Move') {
3685
            $action = 'Edit';
3686
        }
3687
    }
3688
3689
    // The session that contains all the permissions already exists for this course
3690
    // so there is no need to requery everything.
3691
    //my_print_r($_SESSION['total_permissions'][$_course['code']][$tool]);
3692
    if (is_array($_SESSION['total_permissions'][$_course['code']][$tool])) {
3693
        if (in_array($action, $_SESSION['total_permissions'][$_course['code']][$tool])) {
3694
            return true;
3695
        } else {
3696
            return false;
3697
        }
3698
    }
3699
}
3700
3701
/**
3702
 * Tells whether this user is an anonymous user.
3703
 *
3704
 * @param int  $user_id  User ID (optional, will take session ID if not provided)
3705
 * @param bool $db_check Whether to check in the database (true) or simply in
3706
 *                       the session (false) to see if the current user is the anonymous user
3707
 *
3708
 * @return bool true if this user is anonymous, false otherwise
3709
 */
3710
function api_is_anonymous($user_id = null, $db_check = false)
3711
{
3712
    if ($db_check) {
3713
        if (!isset($user_id)) {
3714
            $user_id = api_get_user_id();
3715
        }
3716
3717
        $info = api_get_user_info($user_id);
3718
3719
        if ($info['status'] == 6 || $user_id == 0 || empty($info)) {
3720
            return true;
3721
        }
3722
    }
3723
3724
    return !Container::getAuthorizationChecker()->isGranted('IS_AUTHENTICATED_FULLY');
3725
}
3726
3727
/**
3728
 * Displays message "You are not allowed here..." and exits the entire script.
3729
 *
3730
 * @param bool   $print_headers Whether or not to print headers (default = false -> does not print them)
3731
 * @param string $message
3732
 * @param int    $responseCode
3733
 */
3734
function api_not_allowed(
3735
    $print_headers = false,
0 ignored issues
show
Unused Code introduced by
The parameter $print_headers is not used and could be removed. ( Ignorable by Annotation )

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

3735
    /** @scrutinizer ignore-unused */ $print_headers = false,

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

Loading history...
3736
    $message = null,
3737
    $responseCode = 0
3738
) {
3739
    $debug = api_get_setting('server_type') == 'test';
3740
3741
    // Default code is 403 forbidden
3742
    $responseCode = empty($responseCode) ? 403 : $responseCode;
3743
    $message = empty($message) ? get_lang('NotAuthorized') : $message;
3744
3745
    // Create new exception rendered by template:
3746
    // src/ThemeBundle/Resources/views/Exception/error.html.twig
3747
3748
    // if error is 404 then the template is:
3749
    // src/ThemeBundle/Resources/views/Exception/error404.html.twig
3750
    $exception = new Exception($message);
3751
    $request = Container::getRequest();
3752
    $exception = \Symfony\Component\Debug\Exception\FlattenException::create($exception, $responseCode);
3753
    $controller = new \Chamilo\ThemeBundle\Controller\ExceptionController(Container::getTwig(), $debug);
3754
    $response = $controller->showAction($request, $exception);
3755
    $response->send();
3756
    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...
3757
3758
    if (api_get_setting('sso_authentication') === 'true') {
0 ignored issues
show
Unused Code introduced by
IfNode is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

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

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

5419
            $files = copyr("$source/$entry", "$dest/$entry", $exclude, /** @scrutinizer ignore-type */ $copied_files);
Loading history...
5420
        }
5421
    }
5422
    // Clean up.
5423
    $dir->close();
5424
5425
    return true;
5426
}
5427
5428
/**
5429
 * @todo: Using DIRECTORY_SEPARATOR is not recommended, this is an obsolete approach.
5430
 * Documentation header to be added here.
5431
 *
5432
 * @param string $pathname
5433
 * @param string $base_path_document
5434
 * @param int    $session_id
5435
 *
5436
 * @return mixed True if directory already exists, false if a file already exists at
5437
 *               the destination and null if everything goes according to plan
5438
 */
5439
function copy_folder_course_session(
5440
    $pathname,
5441
    $base_path_document,
5442
    $session_id,
5443
    $course_info,
5444
    $document,
5445
    $source_course_id
5446
) {
5447
    $table = Database::get_course_table(TABLE_DOCUMENT);
5448
    $session_id = intval($session_id);
5449
    $source_course_id = intval($source_course_id);
5450
5451
    // Check whether directory already exists.
5452
    if (is_dir($pathname) || empty($pathname)) {
5453
        return true;
5454
    }
5455
5456
    // Ensure that a file with the same name does not already exist.
5457
    if (is_file($pathname)) {
5458
        trigger_error('copy_folder_course_session(): File exists', E_USER_WARNING);
5459
5460
        return false;
5461
    }
5462
5463
    $course_id = $course_info['real_id'];
5464
    $folders = explode(DIRECTORY_SEPARATOR, str_replace($base_path_document.DIRECTORY_SEPARATOR, '', $pathname));
5465
    $new_pathname = $base_path_document;
5466
    $path = '';
5467
5468
    foreach ($folders as $folder) {
5469
        $new_pathname .= DIRECTORY_SEPARATOR.$folder;
5470
        $path .= DIRECTORY_SEPARATOR.$folder;
5471
5472
        if (!file_exists($new_pathname)) {
5473
            $path = Database::escape_string($path);
5474
5475
            $sql = "SELECT * FROM $table
5476
                    WHERE
5477
                        c_id = $source_course_id AND
5478
                        path = '$path' AND
5479
                        filetype = 'folder' AND
5480
                        session_id = '$session_id'";
5481
            $rs1 = Database::query($sql);
5482
            $num_rows = Database::num_rows($rs1);
5483
5484
            if ($num_rows == 0) {
5485
                mkdir($new_pathname, api_get_permissions_for_new_directories());
5486
5487
                // Insert new folder with destination session_id.
5488
                $params = [
5489
                    'c_id' => $course_id,
5490
                    'path' => $path,
5491
                    'comment' => $document->comment,
5492
                    'title' => basename($new_pathname),
5493
                    'filetype' => 'folder',
5494
                    'size' => '0',
5495
                    'session_id' => $session_id,
5496
                ];
5497
                $document_id = Database::insert($table, $params);
5498
                if ($document_id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $document_id of type integer|false 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...
5499
                    $sql = "UPDATE $table SET id = iid WHERE iid = $document_id";
5500
                    Database::query($sql);
5501
5502
                    api_item_property_update(
5503
                        $course_info,
5504
                        TOOL_DOCUMENT,
5505
                        $document_id,
5506
                        'FolderCreated',
5507
                        api_get_user_id(),
5508
                        0,
5509
                        0,
5510
                        null,
5511
                        null,
5512
                        $session_id
5513
                    );
5514
                }
5515
            }
5516
        }
5517
    } // en foreach
5518
}
5519
5520
// TODO: chmodr() is a better name. Some corrections are needed. Documentation header to be added here.
5521
/**
5522
 * @param string $path
5523
 */
5524
function api_chmod_R($path, $filemode)
5525
{
5526
    if (!is_dir($path)) {
5527
        return chmod($path, $filemode);
5528
    }
5529
5530
    $handler = opendir($path);
5531
    while ($file = readdir($handler)) {
0 ignored issues
show
Bug introduced by
It seems like $handler can also be of type false; however, parameter $dir_handle of readdir() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

5531
    while ($file = readdir(/** @scrutinizer ignore-type */ $handler)) {
Loading history...
5532
        if ($file != '.' && $file != '..') {
5533
            $fullpath = "$path/$file";
5534
            if (!is_dir($fullpath)) {
5535
                if (!chmod($fullpath, $filemode)) {
5536
                    return false;
5537
                }
5538
            } else {
5539
                if (!api_chmod_R($fullpath, $filemode)) {
5540
                    return false;
5541
                }
5542
            }
5543
        }
5544
    }
5545
5546
    closedir($handler);
0 ignored issues
show
Bug introduced by
It seems like $handler can also be of type false; however, parameter $dir_handle of closedir() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

5546
    closedir(/** @scrutinizer ignore-type */ $handler);
Loading history...
5547
5548
    return chmod($path, $filemode);
5549
}
5550
5551
// TODO: Where the following function has been copy/pased from? There is no information about author and license. Style, coding conventions...
5552
/**
5553
 * Parse info file format. (e.g: file.info).
5554
 *
5555
 * Files should use an ini-like format to specify values.
5556
 * White-space generally doesn't matter, except inside values.
5557
 * e.g.
5558
 *
5559
 * @verbatim
5560
 *   key = value
5561
 *   key = "value"
5562
 *   key = 'value'
5563
 *   key = "multi-line
5564
 *
5565
 *   value"
5566
 *   key = 'multi-line
5567
 *
5568
 *   value'
5569
 *   key
5570
 *   =
5571
 *   'value'
5572
 * @endverbatim
5573
 *
5574
 * Arrays are created using a GET-like syntax:
5575
 *
5576
 * @verbatim
5577
 *   key[] = "numeric array"
5578
 *   key[index] = "associative array"
5579
 *   key[index][] = "nested numeric array"
5580
 *   key[index][index] = "nested associative array"
5581
 * @endverbatim
5582
 *
5583
 * PHP constants are substituted in, but only when used as the entire value:
5584
 *
5585
 * Comments should start with a semi-colon at the beginning of a line.
5586
 *
5587
 * This function is NOT for placing arbitrary module-specific settings. Use
5588
 * variable_get() and variable_set() for that.
5589
 *
5590
 * Information stored in the module.info file:
5591
 * - name: The real name of the module for display purposes.
5592
 * - description: A brief description of the module.
5593
 * - dependencies: An array of shortnames of other modules this module depends on.
5594
 * - package: The name of the package of modules this module belongs to.
5595
 *
5596
 * Example of .info file:
5597
 * <code>
5598
 * @verbatim
5599
 *   name = Forum
5600
 *   description = Enables threaded discussions about general topics.
5601
 *   dependencies[] = taxonomy
5602
 *   dependencies[] = comment
5603
 *   package = Core - optional
5604
 *   version = VERSION
5605
 * @endverbatim
5606
 * </code>
5607
 *
5608
 * @param string $filename
5609
 *                         The file we are parsing. Accepts file with relative or absolute path.
5610
 *
5611
 * @return
5612
 *   The info array
5613
 */
5614
function api_parse_info_file($filename)
5615
{
5616
    $info = [];
5617
5618
    if (!file_exists($filename)) {
5619
        return $info;
5620
    }
5621
5622
    $data = file_get_contents($filename);
5623
    if (preg_match_all('
5624
        @^\s*                           # Start at the beginning of a line, ignoring leading whitespace
5625
        ((?:
5626
          [^=;\[\]]|                    # Key names cannot contain equal signs, semi-colons or square brackets,
5627
          \[[^\[\]]*\]                  # unless they are balanced and not nested
5628
        )+?)
5629
        \s*=\s*                         # Key/value pairs are separated by equal signs (ignoring white-space)
5630
        (?:
5631
          ("(?:[^"]|(?<=\\\\)")*")|     # Double-quoted string, which may contain slash-escaped quotes/slashes
5632
          (\'(?:[^\']|(?<=\\\\)\')*\')| # Single-quoted string, which may contain slash-escaped quotes/slashes
5633
          ([^\r\n]*?)                   # Non-quoted string
5634
        )\s*$                           # Stop at the next end of a line, ignoring trailing whitespace
5635
        @msx', $data, $matches, PREG_SET_ORDER)) {
5636
        $key = $value1 = $value2 = $value3 = '';
5637
        foreach ($matches as $match) {
5638
            // Fetch the key and value string.
5639
            $i = 0;
5640
            foreach (['key', 'value1', 'value2', 'value3'] as $var) {
5641
                $$var = isset($match[++$i]) ? $match[$i] : '';
5642
            }
5643
            $value = stripslashes(substr($value1, 1, -1)).stripslashes(substr($value2, 1, -1)).$value3;
5644
5645
            // Parse array syntax.
5646
            $keys = preg_split('/\]?\[/', rtrim($key, ']'));
5647
            $last = array_pop($keys);
0 ignored issues
show
Bug introduced by
It seems like $keys can also be of type false; however, parameter $array of array_pop() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

5647
            $last = array_pop(/** @scrutinizer ignore-type */ $keys);
Loading history...
5648
            $parent = &$info;
5649
5650
            // Create nested arrays.
5651
            foreach ($keys as $key) {
5652
                if ($key == '') {
5653
                    $key = count($parent);
5654
                }
5655
                if (!isset($parent[$key]) || !is_array($parent[$key])) {
5656
                    $parent[$key] = [];
5657
                }
5658
                $parent = &$parent[$key];
5659
            }
5660
5661
            // Handle PHP constants.
5662
            if (defined($value)) {
5663
                $value = constant($value);
5664
            }
5665
5666
            // Insert actual value.
5667
            if ($last == '') {
5668
                $last = count($parent);
5669
            }
5670
            $parent[$last] = $value;
5671
        }
5672
    }
5673
5674
    return $info;
5675
}
5676
5677
/**
5678
 * Gets Chamilo version from the configuration files.
5679
 *
5680
 * @return string A string of type "1.8.4", or an empty string if the version could not be found
5681
 */
5682
function api_get_version()
5683
{
5684
    return (string) api_get_configuration_value('system_version');
5685
}
5686
5687
/**
5688
 * Gets the software name (the name/brand of the Chamilo-based customized system).
5689
 *
5690
 * @return string
5691
 */
5692
function api_get_software_name()
5693
{
5694
    $name = api_get_configuration_value('software_name');
5695
    if (!empty($name)) {
5696
        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...
5697
    } else {
5698
        return 'Chamilo';
5699
    }
5700
}
5701
5702
/**
5703
 * Checks whether status given in parameter exists in the platform.
5704
 *
5705
 * @param mixed the status (can be either int either string)
5706
 *
5707
 * @return bool if the status exists, else returns false
5708
 */
5709
function api_status_exists($status_asked)
5710
{
5711
    global $_status_list;
5712
5713
    return in_array($status_asked, $_status_list) ? true : isset($_status_list[$status_asked]);
5714
}
5715
5716
/**
5717
 * Checks whether status given in parameter exists in the platform. The function
5718
 * returns the status ID or false if it does not exist, but given the fact there
5719
 * is no "0" status, the return value can be checked against
5720
 * if(api_status_key()) to know if it exists.
5721
 *
5722
 * @param   mixed   The status (can be either int or string)
5723
 *
5724
 * @return mixed Status ID if exists, false otherwise
5725
 */
5726
function api_status_key($status)
5727
{
5728
    global $_status_list;
5729
5730
    return isset($_status_list[$status]) ? $status : array_search($status, $_status_list);
5731
}
5732
5733
/**
5734
 * Gets the status langvars list.
5735
 *
5736
 * @return string[] the list of status with their translations
5737
 */
5738
function api_get_status_langvars()
5739
{
5740
    return [
5741
        COURSEMANAGER => get_lang('Teacher', ''),
5742
        SESSIONADMIN => get_lang('SessionsAdmin', ''),
5743
        DRH => get_lang('Drh', ''),
5744
        STUDENT => get_lang('Student', ''),
5745
        ANONYMOUS => get_lang('Anonymous', ''),
5746
        STUDENT_BOSS => get_lang('RoleStudentBoss', ''),
5747
        INVITEE => get_lang('Invited'),
5748
    ];
5749
}
5750
5751
/**
5752
 * The function that retrieves all the possible settings for a certain config setting.
5753
 *
5754
 * @author Patrick Cool <[email protected]>, Ghent University
5755
 */
5756
function api_get_settings_options($var)
5757
{
5758
    $table_settings_options = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
5759
    $var = Database::escape_string($var);
5760
    $sql = "SELECT * FROM $table_settings_options
5761
            WHERE variable = '$var'
5762
            ORDER BY id";
5763
    $result = Database::query($sql);
5764
    $settings_options_array = [];
5765
    while ($row = Database::fetch_array($result, 'ASSOC')) {
5766
        $settings_options_array[] = $row;
5767
    }
5768
5769
    return $settings_options_array;
5770
}
5771
5772
/**
5773
 * @param array $params
5774
 */
5775
function api_set_setting_option($params)
5776
{
5777
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
5778
    if (empty($params['id'])) {
5779
        Database::insert($table, $params);
5780
    } else {
5781
        Database::update($table, $params, ['id = ? ' => $params['id']]);
5782
    }
5783
}
5784
5785
/**
5786
 * @param array $params
5787
 */
5788
function api_set_setting_simple($params)
5789
{
5790
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5791
    $url_id = api_get_current_access_url_id();
5792
5793
    if (empty($params['id'])) {
5794
        $params['access_url'] = $url_id;
5795
        Database::insert($table, $params);
5796
    } else {
5797
        Database::update($table, $params, ['id = ? ' => [$params['id']]]);
5798
    }
5799
}
5800
5801
/**
5802
 * @param int $id
5803
 */
5804
function api_delete_setting_option($id)
5805
{
5806
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
5807
    if (!empty($id)) {
5808
        Database::delete($table, ['id = ? ' => $id]);
5809
    }
5810
}
5811
5812
/**
5813
 * Sets a platform configuration setting to a given value.
5814
 *
5815
 * @param string    The variable we want to update
5816
 * @param string    The value we want to record
5817
 * @param string    The sub-variable if any (in most cases, this will remain null)
5818
 * @param string    The category if any (in most cases, this will remain null)
5819
 * @param int       The access_url for which this parameter is valid
5820
 * @param string $cat
5821
 *
5822
 * @return bool|null
5823
 */
5824
function api_set_setting($var, $value, $subvar = null, $cat = null, $access_url = 1)
5825
{
5826
    if (empty($var)) {
5827
        return false;
5828
    }
5829
    $t_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5830
    $var = Database::escape_string($var);
5831
    $value = Database::escape_string($value);
5832
    $access_url = (int) $access_url;
5833
    if (empty($access_url)) {
5834
        $access_url = 1;
5835
    }
5836
    $select = "SELECT id FROM $t_settings WHERE variable = '$var' ";
5837
    if (!empty($subvar)) {
5838
        $subvar = Database::escape_string($subvar);
5839
        $select .= " AND subkey = '$subvar'";
5840
    }
5841
    if (!empty($cat)) {
5842
        $cat = Database::escape_string($cat);
5843
        $select .= " AND category = '$cat'";
5844
    }
5845
    if ($access_url > 1) {
5846
        $select .= " AND access_url = $access_url";
5847
    } else {
5848
        $select .= " AND access_url = 1 ";
5849
    }
5850
5851
    $res = Database::query($select);
5852
    if (Database::num_rows($res) > 0) {
5853
        // Found item for this access_url.
5854
        $row = Database::fetch_array($res);
5855
        $sql = "UPDATE $t_settings SET selected_value = '$value'
5856
                WHERE id = ".$row['id'];
5857
        Database::query($sql);
5858
    } else {
5859
        // Item not found for this access_url, we have to check if it exist with access_url = 1
5860
        $select = "SELECT * FROM $t_settings
5861
                   WHERE variable = '$var' AND access_url = 1 ";
5862
        // Just in case
5863
        if ($access_url == 1) {
5864
            if (!empty($subvar)) {
5865
                $select .= " AND subkey = '$subvar'";
5866
            }
5867
            if (!empty($cat)) {
5868
                $select .= " AND category = '$cat'";
5869
            }
5870
            $res = Database::query($select);
5871
            if (Database::num_rows($res) > 0) {
5872
                // We have a setting for access_url 1, but none for the current one, so create one.
5873
                $row = Database::fetch_array($res);
5874
                $insert = "INSERT INTO $t_settings (variable, subkey, type,category, selected_value, title, comment, scope, subkeytext, access_url)
5875
                        VALUES
5876
                        ('".$row['variable']."',".(!empty($row['subkey']) ? "'".$row['subkey']."'" : "NULL").",".
5877
                    "'".$row['type']."','".$row['category']."',".
5878
                    "'$value','".$row['title']."',".
5879
                    "".(!empty($row['comment']) ? "'".$row['comment']."'" : "NULL").",".(!empty($row['scope']) ? "'".$row['scope']."'" : "NULL").",".
5880
                    "".(!empty($row['subkeytext']) ? "'".$row['subkeytext']."'" : "NULL").",$access_url)";
5881
                Database::query($insert);
5882
            } else {
0 ignored issues
show
Unused Code introduced by
This else statement is empty and can be removed.

This check looks for the else branches of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These else branches can be removed.

if (rand(1, 6) > 3) {
print "Check failed";
} else {
    //print "Check succeeded";
}

could be turned into

if (rand(1, 6) > 3) {
    print "Check failed";
}

This is much more concise to read.

Loading history...
5883
                // Such a setting does not exist.
5884
                //error_log(__FILE__.':'.__LINE__.': Attempting to update setting '.$var.' ('.$subvar.') which does not exist at all', 0);
5885
            }
5886
        } else {
5887
            // Other access url.
5888
            if (!empty($subvar)) {
5889
                $select .= " AND subkey = '$subvar'";
5890
            }
5891
            if (!empty($cat)) {
5892
                $select .= " AND category = '$cat'";
5893
            }
5894
            $res = Database::query($select);
5895
5896
            if (Database::num_rows($res) > 0) {
5897
                // We have a setting for access_url 1, but none for the current one, so create one.
5898
                $row = Database::fetch_array($res);
5899
                if ($row['access_url_changeable'] == 1) {
5900
                    $insert = "INSERT INTO $t_settings (variable,subkey, type,category, selected_value,title, comment,scope, subkeytext,access_url, access_url_changeable) VALUES
5901
                            ('".$row['variable']."',".
5902
                        (!empty($row['subkey']) ? "'".$row['subkey']."'" : "NULL").",".
5903
                        "'".$row['type']."','".$row['category']."',".
5904
                        "'$value','".$row['title']."',".
5905
                        "".(!empty($row['comment']) ? "'".$row['comment']."'" : "NULL").",".
5906
                        (!empty($row['scope']) ? "'".$row['scope']."'" : "NULL").",".
5907
                        "".(!empty($row['subkeytext']) ? "'".$row['subkeytext']."'" : "NULL").",$access_url,".$row['access_url_changeable'].")";
5908
                    Database::query($insert);
5909
                }
5910
            } else { // Such a setting does not exist.
0 ignored issues
show
Unused Code introduced by
This else statement is empty and can be removed.

This check looks for the else branches of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These else branches can be removed.

if (rand(1, 6) > 3) {
print "Check failed";
} else {
    //print "Check succeeded";
}

could be turned into

if (rand(1, 6) > 3) {
    print "Check failed";
}

This is much more concise to read.

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

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

7642
function api_user_is_login(/** @scrutinizer ignore-unused */ $user_id = null)

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

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

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

8462
function api_set_firstpage_parameter(/** @scrutinizer ignore-unused */ $in_firstpage)

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

Loading history...
8463
{
8464
    //setcookie('GotoCourse', $in_firstpage);
8465
}
8466
8467
/**
8468
 * Delete the cookie to go directly to the course code $in_firstpage
8469
 * after login.
8470
 */
8471
function api_delete_firstpage_parameter()
8472
{
8473
    setcookie('GotoCourse', '', time() - 3600);
8474
}
8475
8476
/**
8477
 * @return bool if course_code for direct course access after login is set
8478
 */
8479
function exist_firstpage_parameter()
8480
{
8481
    return isset($_COOKIE['GotoCourse']) && $_COOKIE['GotoCourse'] != '';
8482
}
8483
8484
/**
8485
 * @return return the course_code of the course where user login
8486
 */
8487
function api_get_firstpage_parameter()
8488
{
8489
    return $_COOKIE['GotoCourse'];
8490
}
8491
8492
/**
8493
 * Return true on https install.
8494
 *
8495
 * @return bool
8496
 */
8497
function api_is_https()
8498
{
8499
    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...
8500
        $_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...
8501
    ) {
8502
        $isSecured = true;
8503
    } else {
8504
        if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') {
8505
            $isSecured = true;
8506
        } else {
8507
            $isSecured = false;
8508
            // last chance
8509
            if (!empty($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443) {
8510
                $isSecured = true;
8511
            }
8512
        }
8513
    }
8514
8515
    return $isSecured;
8516
}
8517
8518
/**
8519
 * Return protocol (http or https).
8520
 *
8521
 * @return string
8522
 */
8523
function api_get_protocol()
8524
{
8525
    return api_is_https() ? 'https' : 'http';
8526
}
8527
8528
/**
8529
 * Return a string where " are replaced with 2 '
8530
 * It is useful when you pass a PHP variable in a Javascript browser dialog
8531
 * e.g. : alert("<?php get_lang('Message') ?>");
8532
 * and message contains character ".
8533
 *
8534
 * @param string $in_text
8535
 *
8536
 * @return string
8537
 */
8538
function convert_double_quote_to_single($in_text)
8539
{
8540
    return api_preg_replace('/"/', "''", $in_text);
8541
}
8542
8543
/**
8544
 * Get origin.
8545
 *
8546
 * @param string
8547
 *
8548
 * @return string
8549
 */
8550
function api_get_origin()
8551
{
8552
    $origin = isset($_REQUEST['origin']) ? Security::remove_XSS($_REQUEST['origin']) : '';
8553
8554
    return $origin;
8555
}
8556
8557
/**
8558
 * Warns an user that the portal reach certain limit.
8559
 *
8560
 * @param string $limitName
8561
 */
8562
function api_warn_hosting_contact($limitName)
8563
{
8564
    $hostingParams = api_get_configuration_value(1);
8565
    $email = null;
8566
8567
    if (!empty($hostingParams)) {
8568
        if (isset($hostingParams['hosting_contact_mail'])) {
8569
            $email = $hostingParams['hosting_contact_mail'];
8570
        }
8571
    }
8572
8573
    if (!empty($email)) {
8574
        $subject = get_lang('HostingWarningReached');
8575
        $body = get_lang('PortalName').': '.api_get_path(WEB_PATH)." \n ";
8576
        $body .= get_lang('PortalLimitType').': '.$limitName." \n ";
8577
        if (isset($hostingParams[$limitName])) {
8578
            $body .= get_lang('Value').': '.$hostingParams[$limitName];
8579
        }
8580
        api_mail_html(null, $email, $subject, $body);
8581
    }
8582
}
8583
8584
/**
8585
 * Gets value of a variable from app/config/configuration.php
8586
 * Variables that are not set in the configuration.php file but set elsewhere:
8587
 * - virtual_css_theme_folder (vchamilo plugin)
8588
 * - access_url (global.inc.php)
8589
 * - apc/apc_prefix (global.inc.php).
8590
 *
8591
 * @param string $variable
8592
 *
8593
 * @return bool|mixed
8594
 */
8595
function api_get_configuration_value($variable)
8596
{
8597
    global $_configuration;
8598
    // Check the current url id, id = 1 by default
8599
    $urlId = isset($_configuration['access_url']) ? (int) $_configuration['access_url'] : 1;
8600
8601
    $variable = trim($variable);
8602
8603
    // Check if variable exists
8604
    if (isset($_configuration[$variable])) {
8605
        if (is_array($_configuration[$variable])) {
8606
            // Check if it exists for the sub portal
8607
            if (array_key_exists($urlId, $_configuration[$variable])) {
8608
                return $_configuration[$variable][$urlId];
8609
            } else {
8610
                // Try to found element with id = 1 (master portal)
8611
                if (array_key_exists(1, $_configuration[$variable])) {
8612
                    return $_configuration[$variable][1];
8613
                }
8614
            }
8615
        }
8616
8617
        return $_configuration[$variable];
8618
    }
8619
8620
    return false;
8621
}
8622
8623
/**
8624
 * Returns supported image extensions in the portal.
8625
 *
8626
 * @param bool $supportVectors Whether vector images should also be accepted or not
8627
 *
8628
 * @return array Supported image extensions in the portal
8629
 */
8630
function api_get_supported_image_extensions($supportVectors = true)
8631
{
8632
    // jpg can also be called jpeg, jpe, jfif and jif. See https://en.wikipedia.org/wiki/JPEG#JPEG_filename_extensions
8633
    $supportedImageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'jpe', 'jfif', 'jif'];
8634
    if ($supportVectors) {
8635
        array_push($supportedImageExtensions, 'svg');
8636
    }
8637
    if (version_compare(PHP_VERSION, '5.5.0', '>=')) {
8638
        array_push($supportedImageExtensions, 'webp');
8639
    }
8640
8641
    return $supportedImageExtensions;
8642
}
8643
8644
/**
8645
 * This setting changes the registration status for the campus.
8646
 *
8647
 * @author Patrick Cool <[email protected]>, Ghent University
8648
 *
8649
 * @version August 2006
8650
 *
8651
 * @param bool $listCampus Whether we authorize
8652
 *
8653
 * @todo the $_settings should be reloaded here. => write api function for this and use this in global.inc.php also.
8654
 */
8655
function api_register_campus($listCampus = true)
8656
{
8657
    $tbl_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
8658
8659
    $sql = "UPDATE $tbl_settings SET selected_value='true' WHERE variable='registered'";
8660
    Database::query($sql);
8661
8662
    if (!$listCampus) {
8663
        $sql = "UPDATE $tbl_settings SET selected_value='true' WHERE variable='donotlistcampus'";
8664
        Database::query($sql);
8665
    }
8666
}
8667
8668
/**
8669
 * Checks whether current user is a student boss.
8670
 *
8671
 * @global array $_user
8672
 *
8673
 * @return bool
8674
 */
8675
function api_is_student_boss()
8676
{
8677
    $_user = api_get_user_info();
8678
8679
    return isset($_user['status']) && $_user['status'] == STUDENT_BOSS;
8680
}
8681
8682
/**
8683
 * Check whether the user type should be exclude.
8684
 * Such as invited or anonymous users.
8685
 *
8686
 * @param bool $checkDB Optional. Whether check the user status
8687
 * @param int  $userId  Options. The user id
8688
 *
8689
 * @return bool
8690
 */
8691
function api_is_excluded_user_type($checkDB = false, $userId = 0)
8692
{
8693
    if ($checkDB) {
8694
        $userId = empty($userId) ? api_get_user_id() : (int) $userId;
8695
8696
        if ($userId == 0) {
8697
            return true;
8698
        }
8699
8700
        $userInfo = api_get_user_info($userId);
8701
8702
        switch ($userInfo['status']) {
8703
            case INVITEE:
8704
            case ANONYMOUS:
8705
                return true;
8706
            default:
8707
                return false;
8708
        }
8709
    }
8710
8711
    $isInvited = api_is_invitee();
8712
    $isAnonymous = api_is_anonymous();
8713
8714
    if ($isInvited || $isAnonymous) {
8715
        return true;
8716
    }
8717
8718
    return false;
8719
}
8720
8721
/**
8722
 * Get the user status to ignore in reports.
8723
 *
8724
 * @param string $format Optional. The result type (array or string)
8725
 *
8726
 * @return array|string
8727
 */
8728
function api_get_users_status_ignored_in_reports($format = 'array')
8729
{
8730
    $excludedTypes = [
8731
        INVITEE,
8732
        ANONYMOUS,
8733
    ];
8734
8735
    if ($format == 'string') {
8736
        return implode(', ', $excludedTypes);
8737
    }
8738
8739
    return $excludedTypes;
8740
}
8741
8742
/**
8743
 * Set the Site Use Cookie Warning for 1 year.
8744
 */
8745
function api_set_site_use_cookie_warning_cookie()
8746
{
8747
    setcookie('ChamiloUsesCookies', 'ok', time() + 31556926);
8748
}
8749
8750
/**
8751
 * Return true if the Site Use Cookie Warning Cookie warning exists.
8752
 *
8753
 * @return bool
8754
 */
8755
function api_site_use_cookie_warning_cookie_exist()
8756
{
8757
    return isset($_COOKIE['ChamiloUsesCookies']);
8758
}
8759
8760
/**
8761
 * Given a number of seconds, format the time to show hours, minutes and seconds.
8762
 *
8763
 * @param int    $time         The time in seconds
8764
 * @param string $originFormat Optional. PHP o JS
8765
 *
8766
 * @return string (00h00'00")
8767
 */
8768
function api_format_time($time, $originFormat = 'php')
8769
{
8770
    $h = get_lang('h');
8771
    $hours = $time / 3600;
8772
    $mins = ($time % 3600) / 60;
8773
    $secs = ($time % 60);
8774
8775
    if ($time < 0) {
8776
        $hours = 0;
8777
        $mins = 0;
8778
        $secs = 0;
8779
    }
8780
8781
    if ($originFormat == 'js') {
8782
        $formattedTime = trim(sprintf("%02d : %02d : %02d", $hours, $mins, $secs));
8783
    } else {
8784
        $formattedTime = trim(sprintf("%02d$h%02d'%02d\"", $hours, $mins, $secs));
8785
    }
8786
8787
    return $formattedTime;
8788
}
8789
8790
/**
8791
 * Create a new empty directory with index.html file.
8792
 *
8793
 * @param string $name            The new directory name
8794
 * @param string $parentDirectory Directory parent directory name
8795
 *
8796
 * @return bool Return true if the directory was create. Otherwise return false
8797
 */
8798
function api_create_protected_dir($name, $parentDirectory)
8799
{
8800
    $isCreated = false;
8801
8802
    if (!is_writable($parentDirectory)) {
8803
        return false;
8804
    }
8805
8806
    $fullPath = $parentDirectory.api_replace_dangerous_char($name);
8807
8808
    if (mkdir($fullPath, api_get_permissions_for_new_directories(), true)) {
8809
        $fp = fopen($fullPath.'/index.html', 'w');
8810
8811
        if ($fp) {
0 ignored issues
show
introduced by
$fp is of type resource|false, thus it always evaluated to false.
Loading history...
8812
            if (fwrite($fp, '<html><head></head><body></body></html>')) {
8813
                $isCreated = true;
8814
            }
8815
        }
8816
8817
        fclose($fp);
0 ignored issues
show
Bug introduced by
It seems like $fp can also be of type false; however, parameter $handle of fclose() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

8817
        fclose(/** @scrutinizer ignore-type */ $fp);
Loading history...
8818
    }
8819
8820
    return $isCreated;
8821
}
8822
8823
/**
8824
 * Sends an HTML email using the phpmailer class (and multipart/alternative to downgrade gracefully)
8825
 * Sender name and email can be specified, if not specified
8826
 * name and email of the platform admin are used.
8827
 *
8828
 * @author Bert Vanderkimpen ICT&O UGent
8829
 * @author Yannick Warnier <[email protected]>
8830
 *
8831
 * @param string    name of recipient
8832
 * @param string    email of recipient
8833
 * @param string    email subject
8834
 * @param string    email body
8835
 * @param string    sender name
8836
 * @param string    sender e-mail
8837
 * @param array     extra headers in form $headers = array($name => $value) to allow parsing
8838
 * @param array     data file (path and filename)
8839
 * @param bool      True for attaching a embedded file inside content html (optional)
8840
 * @param array     Additional parameters
8841
 *
8842
 * @return int true if mail was sent
8843
 *
8844
 * @see             class.phpmailer.php
8845
 */
8846
function api_mail_html(
8847
    $recipient_name,
0 ignored issues
show
Unused Code introduced by
The parameter $recipient_name is not used and could be removed. ( Ignorable by Annotation )

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

8847
    /** @scrutinizer ignore-unused */ $recipient_name,

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

Loading history...
8848
    $recipient_email,
0 ignored issues
show
Unused Code introduced by
The parameter $recipient_email is not used and could be removed. ( Ignorable by Annotation )

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

8848
    /** @scrutinizer ignore-unused */ $recipient_email,

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

Loading history...
8849
    $subject,
0 ignored issues
show
Unused Code introduced by
The parameter $subject is not used and could be removed. ( Ignorable by Annotation )

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

8849
    /** @scrutinizer ignore-unused */ $subject,

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

Loading history...
8850
    $message,
0 ignored issues
show
Unused Code introduced by
The parameter $message is not used and could be removed. ( Ignorable by Annotation )

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

8850
    /** @scrutinizer ignore-unused */ $message,

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

Loading history...
8851
    $senderName = '',
0 ignored issues
show
Unused Code introduced by
The parameter $senderName is not used and could be removed. ( Ignorable by Annotation )

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

8851
    /** @scrutinizer ignore-unused */ $senderName = '',

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

Loading history...
8852
    $senderEmail = '',
0 ignored issues
show
Unused Code introduced by
The parameter $senderEmail is not used and could be removed. ( Ignorable by Annotation )

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

8852
    /** @scrutinizer ignore-unused */ $senderEmail = '',

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

Loading history...
8853
    $extra_headers = [],
0 ignored issues
show
Unused Code introduced by
The parameter $extra_headers is not used and could be removed. ( Ignorable by Annotation )

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

8853
    /** @scrutinizer ignore-unused */ $extra_headers = [],

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

Loading history...
8854
    $data_file = [],
0 ignored issues
show
Unused Code introduced by
The parameter $data_file is not used and could be removed. ( Ignorable by Annotation )

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

8854
    /** @scrutinizer ignore-unused */ $data_file = [],

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

Loading history...
8855
    $embedded_image = false,
0 ignored issues
show
Unused Code introduced by
The parameter $embedded_image is not used and could be removed. ( Ignorable by Annotation )

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

8855
    /** @scrutinizer ignore-unused */ $embedded_image = false,

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

Loading history...
8856
    $additionalParameters = []
0 ignored issues
show
Unused Code introduced by
The parameter $additionalParameters is not used and could be removed. ( Ignorable by Annotation )

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

8856
    /** @scrutinizer ignore-unused */ $additionalParameters = []

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

Loading history...
8857
) {
8858
    global $platform_email;
8859
8860
    return;
8861
8862
    $mail = new PHPMailer();
0 ignored issues
show
Unused Code introduced by
$mail = new PHPMailer() is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
8863
    $mail->Mailer = $platform_email['SMTP_MAILER'];
8864
    $mail->Host = $platform_email['SMTP_HOST'];
8865
    $mail->Port = $platform_email['SMTP_PORT'];
8866
    $mail->CharSet = $platform_email['SMTP_CHARSET'];
8867
    // Stay far below SMTP protocol 980 chars limit.
8868
    $mail->WordWrap = 200;
8869
8870
    if ($platform_email['SMTP_AUTH']) {
8871
        $mail->SMTPAuth = 1;
8872
        $mail->Username = $platform_email['SMTP_USER'];
8873
        $mail->Password = $platform_email['SMTP_PASS'];
8874
        if (isset($platform_email['SMTP_SECURE'])) {
8875
            $mail->SMTPSecure = $platform_email['SMTP_SECURE'];
8876
        }
8877
    }
8878
    $mail->SMTPDebug = isset($platform_email['SMTP_DEBUG']) ? $platform_email['SMTP_DEBUG'] : 0;
8879
8880
    // 5 = low, 1 = high
8881
    $mail->Priority = 3;
8882
    $mail->SMTPKeepAlive = true;
8883
8884
    // Default values
8885
    $notification = new Notification();
8886
    $defaultEmail = $notification->getDefaultPlatformSenderEmail();
8887
    $defaultName = $notification->getDefaultPlatformSenderName();
8888
8889
    // If the parameter is set don't use the admin.
8890
    $senderName = !empty($senderName) ? $senderName : $defaultName;
8891
    $senderEmail = !empty($senderEmail) ? $senderEmail : $defaultEmail;
8892
8893
    // Reply to first
8894
    if (isset($extra_headers['reply_to']) && empty($platform_email['SMTP_UNIQUE_REPLY_TO'])) {
8895
        $mail->AddReplyTo(
8896
            $extra_headers['reply_to']['mail'],
8897
            $extra_headers['reply_to']['name']
8898
        );
8899
        // Errors to sender
8900
        $mail->AddCustomHeader('Errors-To: '.$extra_headers['reply_to']['mail']);
8901
        $mail->Sender = $extra_headers['reply_to']['mail'];
8902
        unset($extra_headers['reply_to']);
8903
    } else {
8904
        $mail->AddCustomHeader('Errors-To: '.$defaultEmail);
8905
    }
8906
8907
    //If the SMTP configuration only accept one sender
8908
    if (isset($platform_email['SMTP_UNIQUE_SENDER']) && $platform_email['SMTP_UNIQUE_SENDER']) {
8909
        $senderName = $platform_email['SMTP_FROM_NAME'];
8910
        $senderEmail = $platform_email['SMTP_FROM_EMAIL'];
8911
        $valid = PHPMailer::validateAddress($senderEmail);
8912
        if ($valid) {
8913
            //force-set Sender to $senderEmail, otherwise SetFrom only does it if it is currently empty
8914
            $mail->Sender = $senderEmail;
8915
        }
8916
    }
8917
8918
    $mail->SetFrom($senderEmail, $senderName);
8919
    $mail->Subject = $subject;
8920
    $mail->AltBody = strip_tags(
8921
        str_replace('<br />', "\n", api_html_entity_decode($message))
8922
    );
8923
8924
    $list = api_get_configuration_value('send_all_emails_to');
8925
    if (!empty($list) && isset($list['emails'])) {
8926
        foreach ($list['emails'] as $email) {
8927
            //$mail->AddBCC($email);
8928
            $mail->AddAddress($email);
8929
        }
8930
    }
8931
8932
    // Send embedded image.
8933
    if ($embedded_image) {
8934
        // Get all images html inside content.
8935
        preg_match_all("/<img\s+.*?src=[\"\']?([^\"\' >]*)[\"\']?[^>]*>/i", $message, $m);
8936
        // Prepare new tag images.
8937
        $new_images_html = [];
8938
        $i = 1;
8939
        if (!empty($m[1])) {
8940
            foreach ($m[1] as $image_path) {
8941
                $real_path = realpath($image_path);
8942
                $filename = basename($image_path);
8943
                $image_cid = $filename.'_'.$i;
8944
                $encoding = 'base64';
8945
                $image_type = mime_content_type($real_path);
8946
                $mail->AddEmbeddedImage(
8947
                    $real_path,
8948
                    $image_cid,
8949
                    $filename,
8950
                    $encoding,
8951
                    $image_type
8952
                );
8953
                $new_images_html[] = '<img src="cid:'.$image_cid.'" />';
8954
                $i++;
8955
            }
8956
        }
8957
8958
        // Replace origin image for new embedded image html.
8959
        $x = 0;
8960
        if (!empty($m[0])) {
8961
            foreach ($m[0] as $orig_img) {
8962
                $message = str_replace($orig_img, $new_images_html[$x], $message);
8963
                $x++;
8964
            }
8965
        }
8966
    }
8967
8968
    $mailView = new Template(null, false, false, false, false, false, false);
8969
8970
    $noReply = api_get_setting('noreply_email_address');
8971
    if (!empty($noReply)) {
8972
        $message .= "<br />".get_lang('ThisIsAutomaticEmailNoReply');
8973
    }
8974
    $mailView->assign('content', $message);
8975
8976
    if (isset($additionalParameters['link'])) {
8977
        $mailView->assign('link', $additionalParameters['link']);
8978
    }
8979
    $mailView->assign('mail_header_style', api_get_configuration_value('mail_header_style'));
8980
    $mailView->assign('mail_content_style', api_get_configuration_value('mail_content_style'));
8981
    $layout = $mailView->get_template('mail/mail.tpl');
8982
    $mail->Body = $mailView->fetch($layout);
8983
8984
    // Attachment ...
8985
    if (!empty($data_file)) {
8986
        foreach ($data_file as $file_attach) {
8987
            if (!empty($file_attach['path']) && !empty($file_attach['filename'])) {
8988
                $mail->AddAttachment($file_attach['path'], $file_attach['filename']);
8989
            }
8990
        }
8991
    }
8992
8993
    // Only valid addresses are accepted.
8994
    if (is_array($recipient_email)) {
8995
        foreach ($recipient_email as $dest) {
8996
            if (api_valid_email($dest)) {
8997
                $mail->AddAddress($dest, $recipient_name);
8998
            }
8999
        }
9000
    } else {
9001
        if (api_valid_email($recipient_email)) {
9002
            $mail->AddAddress($recipient_email, $recipient_name);
9003
        } else {
9004
            return 0;
9005
        }
9006
    }
9007
9008
    if (is_array($extra_headers) && count($extra_headers) > 0) {
9009
        foreach ($extra_headers as $key => $value) {
9010
            switch (strtolower($key)) {
9011
                case 'encoding':
9012
                case 'content-transfer-encoding':
9013
                    $mail->Encoding = $value;
9014
                    break;
9015
                case 'charset':
9016
                    $mail->Charset = $value;
9017
                    break;
9018
                case 'contenttype':
9019
                case 'content-type':
9020
                    $mail->ContentType = $value;
9021
                    break;
9022
                default:
9023
                    $mail->AddCustomHeader($key.':'.$value);
9024
                    break;
9025
            }
9026
        }
9027
    } else {
9028
        if (!empty($extra_headers)) {
9029
            $mail->AddCustomHeader($extra_headers);
9030
        }
9031
    }
9032
9033
    // WordWrap the html body (phpMailer only fixes AltBody) FS#2988
9034
    $mail->Body = $mail->WrapText($mail->Body, $mail->WordWrap);
9035
9036
    // Send the mail message.
9037
    if (!$mail->Send()) {
9038
        error_log('ERROR: mail not sent to '.$recipient_name.' ('.$recipient_email.') because of '.$mail->ErrorInfo.'<br />');
9039
        if ($mail->SMTPDebug) {
9040
            error_log(
9041
                "Connection details :: ".
9042
                "Protocol: ".$mail->Mailer.' :: '.
9043
                "Host/Port: ".$mail->Host.':'.$mail->Port.' :: '.
9044
                "Authent/Open: ".($mail->SMTPAuth ? 'Authent' : 'Open').' :: '.
9045
                ($mail->SMTPAuth ? "  User/Pass: ".$mail->Username.':'.$mail->Password : '').' :: '.
9046
                "Sender: ".$mail->Sender
9047
            );
9048
        }
9049
9050
        return 0;
9051
    }
9052
9053
    if (!empty($additionalParameters)) {
9054
        $plugin = new AppPlugin();
9055
        $smsPlugin = $plugin->getSMSPluginLibrary();
9056
        if ($smsPlugin) {
9057
            $smsPlugin->send($additionalParameters);
9058
        }
9059
    }
9060
9061
    // Clear all the addresses.
9062
    $mail->ClearAddresses();
9063
9064
    // Clear all attachments
9065
    $mail->ClearAttachments();
9066
9067
    return 1;
9068
}
9069
9070
/**
9071
 * @param string $tool       Possible values: GroupManager::GROUP_TOOL_*
9072
 * @param bool   $showHeader
9073
 */
9074
function api_protect_course_group($tool, $showHeader = true)
9075
{
9076
    $userId = api_get_user_id();
9077
    $groupId = api_get_group_id();
9078
    $groupInfo = GroupManager::get_group_properties($groupId);
9079
9080
    if (!empty($groupInfo)) {
9081
        $allow = GroupManager::user_has_access(
9082
            $userId,
9083
            $groupInfo['iid'],
9084
            $tool
9085
        );
9086
9087
        if (!$allow) {
9088
            api_not_allowed($showHeader);
9089
        }
9090
    }
9091
}
9092
9093
/**
9094
 * Check if a date is in a date range.
9095
 *
9096
 * @param datetime $startDate
9097
 * @param datetime $endDate
9098
 * @param datetime $currentDate
9099
 *
9100
 * @return bool true if date is in rage, false otherwise
9101
 */
9102
function api_is_date_in_date_range($startDate, $endDate, $currentDate = null)
9103
{
9104
    $startDate = strtotime(api_get_local_time($startDate));
9105
    $endDate = strtotime(api_get_local_time($endDate));
9106
    $currentDate = strtotime(api_get_local_time($currentDate));
9107
9108
    if ($currentDate >= $startDate && $currentDate <= $endDate) {
9109
        return true;
9110
    }
9111
9112
    return false;
9113
}
9114
9115
/**
9116
 * Eliminate the duplicates of a multidimensional array by sending the key.
9117
 *
9118
 * @param array $array multidimensional array
9119
 * @param int   $key   key to find to compare
9120
 *
9121
 * @return array
9122
 */
9123
function api_unique_multidim_array($array, $key)
9124
{
9125
    $temp_array = [];
9126
    $i = 0;
9127
    $key_array = [];
9128
9129
    foreach ($array as $val) {
9130
        if (!in_array($val[$key], $key_array)) {
9131
            $key_array[$i] = $val[$key];
9132
            $temp_array[$i] = $val;
9133
        }
9134
        $i++;
9135
    }
9136
9137
    return $temp_array;
9138
}
9139
9140
/**
9141
 * Limit the access to Session Admins when the limit_session_admin_role
9142
 * configuration variable is set to true.
9143
 */
9144
function api_protect_limit_for_session_admin()
9145
{
9146
    $limitAdmin = api_get_setting('limit_session_admin_role');
9147
    if (api_is_session_admin() && $limitAdmin === 'true') {
9148
        api_not_allowed(true);
9149
    }
9150
}
9151
9152
/**
9153
 * @return bool
9154
 */
9155
function api_is_student_view_active()
9156
{
9157
    $studentView = Session::read('studentview');
9158
9159
    return $studentView == 'studentview';
9160
}
9161
9162
/**
9163
 * Adds a file inside the upload/$type/id.
9164
 *
9165
 * @param string $type
9166
 * @param array  $file
9167
 * @param int    $itemId
9168
 * @param string $cropParameters
9169
 *
9170
 * @return array|bool
9171
 */
9172
function api_upload_file($type, $file, $itemId, $cropParameters = '')
9173
{
9174
    $upload = process_uploaded_file($file);
9175
    if ($upload) {
9176
        $name = api_replace_dangerous_char($file['name']);
9177
9178
        // No "dangerous" files
9179
        $name = disable_dangerous_file($name);
9180
9181
        $pathId = '/'.substr((string) $itemId, 0, 1).'/'.$itemId.'/';
9182
        $path = api_get_path(SYS_UPLOAD_PATH).$type.$pathId;
9183
9184
        if (!is_dir($path)) {
9185
            mkdir($path, api_get_permissions_for_new_directories(), true);
9186
        }
9187
9188
        $pathToSave = $path.$name;
9189
        $result = moveUploadedFile($file, $pathToSave);
9190
9191
        if ($result) {
9192
            if (!empty($cropParameters)) {
9193
                $image = new Image($pathToSave);
9194
                $image->crop($cropParameters);
9195
            }
9196
9197
            return ['path_to_save' => $pathId.$name];
9198
        }
9199
9200
        return false;
9201
    }
9202
}
9203
9204
/**
9205
 * @param string $type
9206
 * @param int    $itemId
9207
 * @param string $file
9208
 *
9209
 * @return bool
9210
 */
9211
function api_get_uploaded_web_url($type, $itemId, $file)
9212
{
9213
    return api_get_uploaded_file($type, $itemId, $file, true);
9214
}
9215
9216
/**
9217
 * @param string $type
9218
 * @param int    $itemId
9219
 * @param string $file
9220
 * @param bool   $getUrl
9221
 *
9222
 * @return bool
9223
 */
9224
function api_get_uploaded_file($type, $itemId, $file, $getUrl = false)
9225
{
9226
    $itemId = (int) $itemId;
9227
    $pathId = '/'.substr((string) $itemId, 0, 1).'/'.$itemId.'/';
9228
    $path = api_get_path(SYS_UPLOAD_PATH).$type.$pathId;
9229
    $file = basename($file);
9230
    $file = $path.'/'.$file;
9231
    if (Security::check_abs_path($file, $path) && is_file($file) && file_exists($file)) {
9232
        if ($getUrl) {
9233
            return str_replace(api_get_path(SYS_UPLOAD_PATH), api_get_path(WEB_UPLOAD_PATH), $file);
0 ignored issues
show
Bug Best Practice introduced by
The expression return str_replace(api_g...EB_UPLOAD_PATH), $file) returns the type string which is incompatible with the documented return type boolean.
Loading history...
9234
        }
9235
9236
        return $file;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $file returns the type string which is incompatible with the documented return type boolean.
Loading history...
9237
    }
9238
9239
    return false;
9240
}
9241
9242
/**
9243
 * @param string $type
9244
 * @param int    $itemId
9245
 * @param string $file
9246
 * @param string $title
9247
 */
9248
function api_download_uploaded_file($type, $itemId, $file, $title = '')
9249
{
9250
    $file = api_get_uploaded_file($type, $itemId, $file);
9251
    if ($file) {
9252
        if (Security::check_abs_path($file, api_get_path(SYS_UPLOAD_PATH).$type)) {
9253
            DocumentManager::file_send_for_download($file, true, $title);
9254
            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...
9255
        }
9256
    }
9257
    api_not_allowed(true);
9258
}
9259
9260
/**
9261
 * @param string $type
9262
 * @param string $file
9263
 */
9264
function api_remove_uploaded_file($type, $file)
9265
{
9266
    $typePath = api_get_path(SYS_UPLOAD_PATH).$type;
9267
    $path = $typePath.'/'.$file;
9268
    if (Security::check_abs_path($path, $typePath) && file_exists($path) && is_file($path)) {
9269
        unlink($path);
9270
    }
9271
}
9272
9273
/**
9274
 * @param string $type
9275
 * @param int    $itemId
9276
 * @param string $file
9277
 *
9278
 * @return bool
9279
 */
9280
function api_remove_uploaded_file_by_id($type, $itemId, $file)
9281
{
9282
    $file = api_get_uploaded_file($type, $itemId, $file, false);
9283
    $typePath = api_get_path(SYS_UPLOAD_PATH).$type;
9284
    if (Security::check_abs_path($file, $typePath) && file_exists($file) && is_file($file)) {
9285
        unlink($file);
9286
9287
        return true;
9288
    }
9289
9290
    return false;
9291
}
9292
9293
/**
9294
 * Converts string value to float value.
9295
 *
9296
 * 3.141516 => 3.141516
9297
 * 3,141516 => 3.141516
9298
 *
9299
 * @todo WIP
9300
 *
9301
 * @param string $number
9302
 *
9303
 * @return float
9304
 */
9305
function api_float_val($number)
9306
{
9307
    $number = (float) str_replace(',', '.', trim($number));
9308
9309
    return $number;
9310
}
9311
9312
/**
9313
 * Converts float values
9314
 * Example if $decimals = 2.
9315
 *
9316
 * 3.141516 => 3.14
9317
 * 3,141516 => 3,14
9318
 *
9319
 * @param string $number            number in iso code
9320
 * @param int    $decimals
9321
 * @param string $decimalSeparator
9322
 * @param string $thousandSeparator
9323
 *
9324
 * @return bool|string
9325
 */
9326
function api_number_format($number, $decimals = 0, $decimalSeparator = '.', $thousandSeparator = ',')
9327
{
9328
    $number = api_float_val($number);
9329
9330
    return number_format($number, $decimals, $decimalSeparator, $thousandSeparator);
9331
}
9332
9333
/**
9334
 * Set location url with a exit break by default.
9335
 *
9336
 * @param $url
9337
 * @param bool $exit
9338
 */
9339
function location($url, $exit = true)
9340
{
9341
    header('Location: '.$url);
9342
9343
    if ($exit) {
9344
        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...
9345
    }
9346
}
9347
9348
/**
9349
 * @return string
9350
 */
9351
function api_get_web_url()
9352
{
9353
    if (api_get_setting('server_type') === 'test') {
9354
        return api_get_path(WEB_PATH).'web/app_dev.php/';
9355
    } else {
9356
        return api_get_path(WEB_PATH).'web/';
9357
    }
9358
}
9359
9360
/**
9361
 * @param string $from
9362
 * @param string $to
9363
 *
9364
 * @return string
9365
 */
9366
function api_get_relative_path($from, $to)
9367
{
9368
    // some compatibility fixes for Windows paths
9369
    $from = is_dir($from) ? rtrim($from, '\/').'/' : $from;
9370
    $to = is_dir($to) ? rtrim($to, '\/').'/' : $to;
9371
    $from = str_replace('\\', '/', $from);
9372
    $to = str_replace('\\', '/', $to);
9373
9374
    $from = explode('/', $from);
9375
    $to = explode('/', $to);
9376
    $relPath = $to;
9377
9378
    foreach ($from as $depth => $dir) {
9379
        // find first non-matching dir
9380
        if ($dir === $to[$depth]) {
9381
            // ignore this directory
9382
            array_shift($relPath);
9383
        } else {
9384
            // get number of remaining dirs to $from
9385
            $remaining = count($from) - $depth;
9386
            if ($remaining > 1) {
9387
                // add traversals up to first matching dir
9388
                $padLength = (count($relPath) + $remaining - 1) * -1;
9389
                $relPath = array_pad($relPath, $padLength, '..');
9390
                break;
9391
            } else {
9392
                $relPath[0] = './'.$relPath[0];
9393
            }
9394
        }
9395
    }
9396
9397
    return implode('/', $relPath);
9398
}
9399