Completed
Push — master ( 16364b...ddb79a )
by Julito
14:09
created

api_not_allowed()   D

Complexity

Conditions 32
Paths 1

Size

Total Lines 189
Code Lines 118

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 32
eloc 118
nc 1
nop 3
dl 0
loc 189
rs 4.3721
c 1
b 1
f 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

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

1133
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...
1134
{
1135
    $is_allowed_in_course = api_is_allowed_in_course();
1136
1137
    $is_visible = false;
1138
    $course_info = api_get_course_info();
1139
1140
    if (empty($course_info)) {
1141
        api_not_allowed($print_headers);
1142
1143
        return false;
1144
    }
1145
1146
    if (api_is_drh()) {
1147
        return true;
1148
    }
1149
1150
    // Session admin has access to course
1151
    $sessionAccess = api_get_configuration_value('session_admins_access_all_content');
1152
    if ($sessionAccess) {
1153
        $allow_session_admins = true;
1154
    }
1155
1156
    if (api_is_platform_admin($allow_session_admins)) {
1157
        return true;
1158
    }
1159
1160
    if (isset($course_info) && isset($course_info['visibility'])) {
1161
        switch ($course_info['visibility']) {
1162
            default:
1163
            case COURSE_VISIBILITY_CLOSED:
1164
                // Completely closed: the course is only accessible to the teachers. - 0
1165
                if (api_get_user_id() && !api_is_anonymous() && $is_allowed_in_course) {
1166
                    $is_visible = true;
1167
                }
1168
                break;
1169
            case COURSE_VISIBILITY_REGISTERED:
1170
                // Private - access authorized to course members only - 1
1171
                if (api_get_user_id() && !api_is_anonymous() && $is_allowed_in_course) {
1172
                    $is_visible = true;
1173
                }
1174
                break;
1175
            case COURSE_VISIBILITY_OPEN_PLATFORM:
1176
                // Open - access allowed for users registered on the platform - 2
1177
                if (api_get_user_id() && !api_is_anonymous() && $is_allowed_in_course) {
1178
                    $is_visible = true;
1179
                }
1180
                break;
1181
            case COURSE_VISIBILITY_OPEN_WORLD:
1182
                //Open - access allowed for the whole world - 3
1183
                $is_visible = true;
1184
                break;
1185
            case COURSE_VISIBILITY_HIDDEN:
1186
                //Completely closed: the course is only accessible to the teachers. - 0
1187
                if (api_is_platform_admin()) {
1188
                    $is_visible = true;
1189
                }
1190
                break;
1191
        }
1192
1193
        //If password is set and user is not registered to the course then the course is not visible
1194
        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...
1195
            isset($course_info['registration_code']) &&
1196
            !empty($course_info['registration_code'])
1197
        ) {
1198
            $is_visible = false;
1199
        }
1200
    }
1201
1202
    // Check session visibility
1203
    $session_id = api_get_session_id();
1204
1205
    if (!empty($session_id)) {
1206
        //$is_allowed_in_course was set in local.inc.php
1207
        if (!$is_allowed_in_course) {
1208
            $is_visible = false;
1209
        }
1210
    }
1211
1212
    if (!$is_visible) {
1213
        api_not_allowed($print_headers);
1214
1215
        return false;
1216
    }
1217
1218
    return true;
1219
}
1220
1221
/**
1222
 * Function used to protect an admin script.
1223
 *
1224
 * The function blocks access when the user has no platform admin rights
1225
 * with an error message printed on default output
1226
 *
1227
 * @param bool Whether to allow session admins as well
1228
 * @param bool Whether to allow HR directors as well
1229
 * @param string An optional message (already passed through get_lang)
1230
 *
1231
 * @return bool True if user is allowed, false otherwise.
1232
 *              The function also outputs an error message in case not allowed
1233
 *
1234
 * @author Roan Embrechts (original author)
1235
 */
1236
function api_protect_admin_script($allow_sessions_admins = false, $allow_drh = false, $message = null)
1237
{
1238
    if (!api_is_platform_admin($allow_sessions_admins, $allow_drh)) {
1239
        api_not_allowed(true, $message);
1240
1241
        return false;
1242
    }
1243
1244
    return true;
1245
}
1246
1247
/**
1248
 * Function used to protect a teacher script.
1249
 * The function blocks access when the user has no teacher rights.
1250
 *
1251
 * @author Yoselyn Castillo
1252
 */
1253
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

1253
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...
1254
{
1255
    if (!api_is_allowed_to_edit()) {
1256
        api_not_allowed(true);
1257
1258
        return false;
1259
    }
1260
1261
    return true;
1262
}
1263
1264
/**
1265
 * Function used to prevent anonymous users from accessing a script.
1266
 *
1267
 * @param bool|true $printHeaders
1268
 *
1269
 * @author Roan Embrechts
1270
 *
1271
 * @return bool
1272
 */
1273
function api_block_anonymous_users($printHeaders = true)
1274
{
1275
    $user = api_get_user_info();
1276
    if (!(isset($user['user_id']) && $user['user_id']) || api_is_anonymous($user['user_id'], true)) {
1277
        api_not_allowed($printHeaders);
1278
1279
        return false;
1280
    }
1281
1282
    return true;
1283
}
1284
1285
/**
1286
 * @return array with the navigator name and version
1287
 */
1288
function api_get_navigator()
1289
{
1290
    $navigator = 'Unknown';
1291
    $version = 0;
1292
1293
    if (!isset($_SERVER['HTTP_USER_AGENT'])) {
1294
        return ['name' => 'Unknown', 'version' => '0.0.0'];
1295
    }
1296
1297
    if (strpos($_SERVER['HTTP_USER_AGENT'], 'Opera') !== false) {
1298
        $navigator = 'Opera';
1299
        list(, $version) = explode('Opera', $_SERVER['HTTP_USER_AGENT']);
1300
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== false) {
1301
        $navigator = 'Internet Explorer';
1302
        list(, $version) = explode('MSIE', $_SERVER['HTTP_USER_AGENT']);
1303
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Chrome') !== false) {
1304
        $navigator = 'Chrome';
1305
        list(, $version) = explode('Chrome', $_SERVER['HTTP_USER_AGENT']);
1306
    } elseif (stripos($_SERVER['HTTP_USER_AGENT'], 'safari') !== false) {
1307
        $navigator = 'Safari';
1308
        list(, $version) = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1309
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Gecko') !== false) {
1310
        $navigator = 'Mozilla';
1311
        list(, $version) = explode('; rv:', $_SERVER['HTTP_USER_AGENT']);
1312
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Netscape') !== false) {
1313
        $navigator = 'Netscape';
1314
        list(, $version) = explode('Netscape', $_SERVER['HTTP_USER_AGENT']);
1315
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Konqueror') !== false) {
1316
        $navigator = 'Konqueror';
1317
        list(, $version) = explode('Konqueror', $_SERVER['HTTP_USER_AGENT']);
1318
    } elseif (stripos($_SERVER['HTTP_USER_AGENT'], 'applewebkit') !== false) {
1319
        $navigator = 'AppleWebKit';
1320
        list(, $version) = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1321
    }
1322
    $version = str_replace('/', '', $version);
1323
    if (strpos($version, '.') === false) {
1324
        $version = number_format(doubleval($version), 1);
1325
    }
1326
    $return = ['name' => $navigator, 'version' => $version];
1327
1328
    return $return;
1329
}
1330
1331
/**
1332
 * @return true if user self registration is allowed, false otherwise
1333
 */
1334
function api_is_self_registration_allowed()
1335
{
1336
    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...
1337
}
1338
1339
/**
1340
 * This function returns the id of the user which is stored in the $_user array.
1341
 *
1342
 * example: The function can be used to check if a user is logged in
1343
 *          if (api_get_user_id())
1344
 *
1345
 * @return int the id of the current user, 0 if is empty
1346
 */
1347
function api_get_user_id()
1348
{
1349
    $userInfo = Session::read('_user');
1350
    if ($userInfo && isset($userInfo['user_id'])) {
1351
        return (int) $userInfo['user_id'];
1352
    }
1353
1354
    return 0;
1355
}
1356
1357
/**
1358
 * Gets the list of courses a specific user is subscribed to.
1359
 *
1360
 * @param int       User ID
1361
 * @param bool $fetch_session Whether to get session courses or not - NOT YET IMPLEMENTED
1362
 *
1363
 * @return array Array of courses in the form [0]=>('code'=>xxx,'db'=>xxx,'dir'=>xxx,'status'=>d)
1364
 *
1365
 * @deprecated use CourseManager::get_courses_list_by_user_id()
1366
 */
1367
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

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

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

3682
    /** @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...
3683
    $message = null,
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

3683
    /** @scrutinizer ignore-unused */ $message = 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...
3684
    $responseCode = 0
0 ignored issues
show
Unused Code introduced by
The parameter $responseCode 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

3684
    /** @scrutinizer ignore-unused */ $responseCode = 0

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

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

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

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

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

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

8334
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...
8335
{
8336
    //setcookie('GotoCourse', $in_firstpage);
8337
}
8338
8339
/**
8340
 * Delete the cookie to go directly to the course code $in_firstpage
8341
 * after login.
8342
 */
8343
function api_delete_firstpage_parameter()
8344
{
8345
    setcookie('GotoCourse', '', time() - 3600);
8346
}
8347
8348
/**
8349
 * @return bool if course_code for direct course access after login is set
8350
 */
8351
function exist_firstpage_parameter()
8352
{
8353
    return isset($_COOKIE['GotoCourse']) && $_COOKIE['GotoCourse'] != '';
8354
}
8355
8356
/**
8357
 * @return return the course_code of the course where user login
8358
 */
8359
function api_get_firstpage_parameter()
8360
{
8361
    return $_COOKIE['GotoCourse'];
8362
}
8363
8364
/**
8365
 * Return true on https install.
8366
 *
8367
 * @return bool
8368
 */
8369
function api_is_https()
8370
{
8371
    if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) &&
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: {currentAssign}, Probably Intended Meaning: {alternativeAssign}
Loading history...
8372
        $_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...
8373
    ) {
8374
        $isSecured = true;
8375
    } else {
8376
        if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') {
8377
            $isSecured = true;
8378
        } else {
8379
            $isSecured = false;
8380
            // last chance
8381
            if (!empty($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443) {
8382
                $isSecured = true;
8383
            }
8384
        }
8385
    }
8386
8387
    return $isSecured;
8388
}
8389
8390
/**
8391
 * Return protocol (http or https).
8392
 *
8393
 * @return string
8394
 */
8395
function api_get_protocol()
8396
{
8397
    return api_is_https() ? 'https' : 'http';
8398
}
8399
8400
/**
8401
 * Return a string where " are replaced with 2 '
8402
 * It is useful when you pass a PHP variable in a Javascript browser dialog
8403
 * e.g. : alert("<?php get_lang('Message') ?>");
8404
 * and message contains character ".
8405
 *
8406
 * @param string $in_text
8407
 *
8408
 * @return string
8409
 */
8410
function convert_double_quote_to_single($in_text)
8411
{
8412
    return api_preg_replace('/"/', "''", $in_text);
8413
}
8414
8415
/**
8416
 * Get origin.
8417
 *
8418
 * @param string
8419
 *
8420
 * @return string
8421
 */
8422
function api_get_origin()
8423
{
8424
    $origin = isset($_REQUEST['origin']) ? Security::remove_XSS($_REQUEST['origin']) : '';
8425
8426
    return $origin;
8427
}
8428
8429
/**
8430
 * Warns an user that the portal reach certain limit.
8431
 *
8432
 * @param string $limitName
8433
 */
8434
function api_warn_hosting_contact($limitName)
8435
{
8436
    $hostingParams = api_get_configuration_value(1);
8437
    $email = null;
8438
8439
    if (!empty($hostingParams)) {
8440
        if (isset($hostingParams['hosting_contact_mail'])) {
8441
            $email = $hostingParams['hosting_contact_mail'];
8442
        }
8443
    }
8444
8445
    if (!empty($email)) {
8446
        $subject = get_lang('HostingWarningReached');
8447
        $body = get_lang('PortalName').': '.api_get_path(WEB_PATH)." \n ";
8448
        $body .= get_lang('PortalLimitType').': '.$limitName." \n ";
8449
        if (isset($hostingParams[$limitName])) {
8450
            $body .= get_lang('Value').': '.$hostingParams[$limitName];
8451
        }
8452
        api_mail_html(null, $email, $subject, $body);
8453
    }
8454
}
8455
8456
/**
8457
 * Gets value of a variable from app/config/configuration.php
8458
 * Variables that are not set in the configuration.php file but set elsewhere:
8459
 * - virtual_css_theme_folder (vchamilo plugin)
8460
 * - access_url (global.inc.php)
8461
 * - apc/apc_prefix (global.inc.php).
8462
 *
8463
 * @param string $variable
8464
 *
8465
 * @return bool|mixed
8466
 */
8467
function api_get_configuration_value($variable)
8468
{
8469
    global $_configuration;
8470
    // Check the current url id, id = 1 by default
8471
    $urlId = isset($_configuration['access_url']) ? (int) $_configuration['access_url'] : 1;
8472
8473
    $variable = trim($variable);
8474
8475
    // Check if variable exists
8476
    if (isset($_configuration[$variable])) {
8477
        if (is_array($_configuration[$variable])) {
8478
            // Check if it exists for the sub portal
8479
            if (array_key_exists($urlId, $_configuration[$variable])) {
8480
                return $_configuration[$variable][$urlId];
8481
            } else {
8482
                // Try to found element with id = 1 (master portal)
8483
                if (array_key_exists(1, $_configuration[$variable])) {
8484
                    return $_configuration[$variable][1];
8485
                }
8486
            }
8487
        }
8488
8489
        return $_configuration[$variable];
8490
    }
8491
8492
    return false;
8493
}
8494
8495
/**
8496
 * Returns supported image extensions in the portal.
8497
 *
8498
 * @param bool $supportVectors Whether vector images should also be accepted or not
8499
 *
8500
 * @return array Supported image extensions in the portal
8501
 */
8502
function api_get_supported_image_extensions($supportVectors = true)
8503
{
8504
    // jpg can also be called jpeg, jpe, jfif and jif. See https://en.wikipedia.org/wiki/JPEG#JPEG_filename_extensions
8505
    $supportedImageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'jpe', 'jfif', 'jif'];
8506
    if ($supportVectors) {
8507
        array_push($supportedImageExtensions, 'svg');
8508
    }
8509
    if (version_compare(PHP_VERSION, '5.5.0', '>=')) {
8510
        array_push($supportedImageExtensions, 'webp');
8511
    }
8512
8513
    return $supportedImageExtensions;
8514
}
8515
8516
/**
8517
 * This setting changes the registration status for the campus.
8518
 *
8519
 * @author Patrick Cool <[email protected]>, Ghent University
8520
 *
8521
 * @version August 2006
8522
 *
8523
 * @param bool $listCampus Whether we authorize
8524
 *
8525
 * @todo the $_settings should be reloaded here. => write api function for this and use this in global.inc.php also.
8526
 */
8527
function api_register_campus($listCampus = true)
8528
{
8529
    $tbl_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
8530
8531
    $sql = "UPDATE $tbl_settings SET selected_value='true' WHERE variable='registered'";
8532
    Database::query($sql);
8533
8534
    if (!$listCampus) {
8535
        $sql = "UPDATE $tbl_settings SET selected_value='true' WHERE variable='donotlistcampus'";
8536
        Database::query($sql);
8537
    }
8538
}
8539
8540
/**
8541
 * Checks whether current user is a student boss.
8542
 *
8543
 * @global array $_user
8544
 *
8545
 * @return bool
8546
 */
8547
function api_is_student_boss()
8548
{
8549
    $_user = api_get_user_info();
8550
8551
    return isset($_user['status']) && $_user['status'] == STUDENT_BOSS;
8552
}
8553
8554
/**
8555
 * Check whether the user type should be exclude.
8556
 * Such as invited or anonymous users.
8557
 *
8558
 * @param bool $checkDB Optional. Whether check the user status
8559
 * @param int  $userId  Options. The user id
8560
 *
8561
 * @return bool
8562
 */
8563
function api_is_excluded_user_type($checkDB = false, $userId = 0)
8564
{
8565
    if ($checkDB) {
8566
        $userId = empty($userId) ? api_get_user_id() : intval($userId);
8567
8568
        if ($userId == 0) {
8569
            return true;
8570
        }
8571
8572
        $userInfo = api_get_user_info($userId);
8573
8574
        switch ($userInfo['status']) {
8575
            case INVITEE:
8576
            case ANONYMOUS:
8577
                return true;
8578
            default:
8579
                return false;
8580
        }
8581
    }
8582
8583
    $isInvited = api_is_invitee();
8584
    $isAnonymous = api_is_anonymous();
8585
8586
    if ($isInvited || $isAnonymous) {
8587
        return true;
8588
    }
8589
8590
    return false;
8591
}
8592
8593
/**
8594
 * Get the user status to ignore in reports.
8595
 *
8596
 * @param string $format Optional. The result type (array or string)
8597
 *
8598
 * @return array|string
8599
 */
8600
function api_get_users_status_ignored_in_reports($format = 'array')
8601
{
8602
    $excludedTypes = [
8603
        INVITEE,
8604
        ANONYMOUS,
8605
    ];
8606
8607
    if ($format == 'string') {
8608
        return implode(', ', $excludedTypes);
8609
    }
8610
8611
    return $excludedTypes;
8612
}
8613
8614
/**
8615
 * Set the Site Use Cookie Warning for 1 year.
8616
 */
8617
function api_set_site_use_cookie_warning_cookie()
8618
{
8619
    setcookie('ChamiloUsesCookies', 'ok', time() + 31556926);
8620
}
8621
8622
/**
8623
 * Return true if the Site Use Cookie Warning Cookie warning exists.
8624
 *
8625
 * @return bool
8626
 */
8627
function api_site_use_cookie_warning_cookie_exist()
8628
{
8629
    return isset($_COOKIE['ChamiloUsesCookies']);
8630
}
8631
8632
/**
8633
 * Given a number of seconds, format the time to show hours, minutes and seconds.
8634
 *
8635
 * @param int    $time         The time in seconds
8636
 * @param string $originFormat Optional. PHP o JS
8637
 *
8638
 * @return string (00h00'00")
8639
 */
8640
function api_format_time($time, $originFormat = 'php')
8641
{
8642
    $h = get_lang('h');
8643
    $hours = $time / 3600;
8644
    $mins = ($time % 3600) / 60;
8645
    $secs = ($time % 60);
8646
8647
    if ($time < 0) {
8648
        $hours = 0;
8649
        $mins = 0;
8650
        $secs = 0;
8651
    }
8652
8653
    if ($originFormat == 'js') {
8654
        $formattedTime = trim(sprintf("%02d : %02d : %02d", $hours, $mins, $secs));
8655
    } else {
8656
        $formattedTime = trim(sprintf("%02d$h%02d'%02d\"", $hours, $mins, $secs));
8657
    }
8658
8659
    return $formattedTime;
8660
}
8661
8662
/**
8663
 * Create a new empty directory with index.html file.
8664
 *
8665
 * @param string $name            The new directory name
8666
 * @param string $parentDirectory Directory parent directory name
8667
 *
8668
 * @return bool Return true if the directory was create. Otherwise return false
8669
 */
8670
function api_create_protected_dir($name, $parentDirectory)
8671
{
8672
    $isCreated = false;
8673
8674
    if (!is_writable($parentDirectory)) {
8675
        return false;
8676
    }
8677
8678
    $fullPath = $parentDirectory.api_replace_dangerous_char($name);
8679
8680
    if (mkdir($fullPath, api_get_permissions_for_new_directories(), true)) {
8681
        $fp = fopen($fullPath.'/index.html', 'w');
8682
8683
        if ($fp) {
0 ignored issues
show
introduced by
$fp is of type resource|false, thus it always evaluated to false.
Loading history...
8684
            if (fwrite($fp, '<html><head></head><body></body></html>')) {
8685
                $isCreated = true;
8686
            }
8687
        }
8688
8689
        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

8689
        fclose(/** @scrutinizer ignore-type */ $fp);
Loading history...
8690
    }
8691
8692
    return $isCreated;
8693
}
8694
8695
/**
8696
 * Sends an HTML email using the phpmailer class (and multipart/alternative to downgrade gracefully)
8697
 * Sender name and email can be specified, if not specified
8698
 * name and email of the platform admin are used.
8699
 *
8700
 * @author Bert Vanderkimpen ICT&O UGent
8701
 * @author Yannick Warnier <[email protected]>
8702
 *
8703
 * @param string    name of recipient
8704
 * @param string    email of recipient
8705
 * @param string    email subject
8706
 * @param string    email body
8707
 * @param string    sender name
8708
 * @param string    sender e-mail
8709
 * @param array     extra headers in form $headers = array($name => $value) to allow parsing
8710
 * @param array     data file (path and filename)
8711
 * @param bool      True for attaching a embedded file inside content html (optional)
8712
 * @param array     Additional parameters
8713
 *
8714
 * @return int true if mail was sent
8715
 *
8716
 * @see             class.phpmailer.php
8717
 */
8718
function api_mail_html(
8719
    $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

8719
    /** @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...
8720
    $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

8720
    /** @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...
8721
    $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

8721
    /** @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...
8722
    $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

8722
    /** @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...
8723
    $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

8723
    /** @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...
8724
    $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

8724
    /** @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...
8725
    $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

8725
    /** @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...
8726
    $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

8726
    /** @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...
8727
    $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

8727
    /** @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...
8728
    $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

8728
    /** @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...
8729
) {
8730
    global $platform_email;
8731
8732
    return;
8733
8734
    $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...
8735
    $mail->Mailer = $platform_email['SMTP_MAILER'];
8736
    $mail->Host = $platform_email['SMTP_HOST'];
8737
    $mail->Port = $platform_email['SMTP_PORT'];
8738
    $mail->CharSet = $platform_email['SMTP_CHARSET'];
8739
    // Stay far below SMTP protocol 980 chars limit.
8740
    $mail->WordWrap = 200;
8741
8742
    if ($platform_email['SMTP_AUTH']) {
8743
        $mail->SMTPAuth = 1;
8744
        $mail->Username = $platform_email['SMTP_USER'];
8745
        $mail->Password = $platform_email['SMTP_PASS'];
8746
        if (isset($platform_email['SMTP_SECURE'])) {
8747
            $mail->SMTPSecure = $platform_email['SMTP_SECURE'];
8748
        }
8749
    }
8750
    $mail->SMTPDebug = isset($platform_email['SMTP_DEBUG']) ? $platform_email['SMTP_DEBUG'] : 0;
8751
8752
    // 5 = low, 1 = high
8753
    $mail->Priority = 3;
8754
    $mail->SMTPKeepAlive = true;
8755
8756
    // Default values
8757
    $notification = new Notification();
8758
    $defaultEmail = $notification->getDefaultPlatformSenderEmail();
8759
    $defaultName = $notification->getDefaultPlatformSenderName();
8760
8761
    // If the parameter is set don't use the admin.
8762
    $senderName = !empty($senderName) ? $senderName : $defaultName;
8763
    $senderEmail = !empty($senderEmail) ? $senderEmail : $defaultEmail;
8764
8765
    // Reply to first
8766
    if (isset($extra_headers['reply_to']) && empty($platform_email['SMTP_UNIQUE_REPLY_TO'])) {
8767
        $mail->AddReplyTo(
8768
            $extra_headers['reply_to']['mail'],
8769
            $extra_headers['reply_to']['name']
8770
        );
8771
        // Errors to sender
8772
        $mail->AddCustomHeader('Errors-To: '.$extra_headers['reply_to']['mail']);
8773
        $mail->Sender = $extra_headers['reply_to']['mail'];
8774
        unset($extra_headers['reply_to']);
8775
    } else {
8776
        $mail->AddCustomHeader('Errors-To: '.$defaultEmail);
8777
    }
8778
8779
    //If the SMTP configuration only accept one sender
8780
    if (isset($platform_email['SMTP_UNIQUE_SENDER']) && $platform_email['SMTP_UNIQUE_SENDER']) {
8781
        $senderName = $platform_email['SMTP_FROM_NAME'];
8782
        $senderEmail = $platform_email['SMTP_FROM_EMAIL'];
8783
        $valid = PHPMailer::validateAddress($senderEmail);
8784
        if ($valid) {
8785
            //force-set Sender to $senderEmail, otherwise SetFrom only does it if it is currently empty
8786
            $mail->Sender = $senderEmail;
8787
        }
8788
    }
8789
8790
    $mail->SetFrom($senderEmail, $senderName);
8791
    $mail->Subject = $subject;
8792
    $mail->AltBody = strip_tags(
8793
        str_replace('<br />', "\n", api_html_entity_decode($message))
8794
    );
8795
8796
    $list = api_get_configuration_value('send_all_emails_to');
8797
    if (!empty($list) && isset($list['emails'])) {
8798
        foreach ($list['emails'] as $email) {
8799
            //$mail->AddBCC($email);
8800
            $mail->AddAddress($email);
8801
        }
8802
    }
8803
8804
    // Send embedded image.
8805
    if ($embedded_image) {
8806
        // Get all images html inside content.
8807
        preg_match_all("/<img\s+.*?src=[\"\']?([^\"\' >]*)[\"\']?[^>]*>/i", $message, $m);
8808
        // Prepare new tag images.
8809
        $new_images_html = [];
8810
        $i = 1;
8811
        if (!empty($m[1])) {
8812
            foreach ($m[1] as $image_path) {
8813
                $real_path = realpath($image_path);
8814
                $filename = basename($image_path);
8815
                $image_cid = $filename.'_'.$i;
8816
                $encoding = 'base64';
8817
                $image_type = mime_content_type($real_path);
8818
                $mail->AddEmbeddedImage(
8819
                    $real_path,
8820
                    $image_cid,
8821
                    $filename,
8822
                    $encoding,
8823
                    $image_type
8824
                );
8825
                $new_images_html[] = '<img src="cid:'.$image_cid.'" />';
8826
                $i++;
8827
            }
8828
        }
8829
8830
        // Replace origin image for new embedded image html.
8831
        $x = 0;
8832
        if (!empty($m[0])) {
8833
            foreach ($m[0] as $orig_img) {
8834
                $message = str_replace($orig_img, $new_images_html[$x], $message);
8835
                $x++;
8836
            }
8837
        }
8838
    }
8839
8840
    $mailView = new Template(null, false, false, false, false, false, false);
8841
8842
    $noReply = api_get_setting('noreply_email_address');
8843
    if (!empty($noReply)) {
8844
        $message .= "<br />".get_lang('ThisIsAutomaticEmailNoReply');
8845
    }
8846
    $mailView->assign('content', $message);
8847
8848
    if (isset($additionalParameters['link'])) {
8849
        $mailView->assign('link', $additionalParameters['link']);
8850
    }
8851
    $mailView->assign('mail_header_style', api_get_configuration_value('mail_header_style'));
8852
    $mailView->assign('mail_content_style', api_get_configuration_value('mail_content_style'));
8853
    $layout = $mailView->get_template('mail/mail.tpl');
8854
    $mail->Body = $mailView->fetch($layout);
8855
8856
    // Attachment ...
8857
    if (!empty($data_file)) {
8858
        $o = 0;
8859
        foreach ($data_file as $file_attach) {
8860
            if (!empty($file_attach['path']) && !empty($file_attach['filename'])) {
8861
                $mail->AddAttachment($file_attach['path'], $file_attach['filename']);
8862
            }
8863
            $o++;
8864
        }
8865
    }
8866
8867
    // Only valid addresses are accepted.
8868
    if (is_array($recipient_email)) {
8869
        foreach ($recipient_email as $dest) {
8870
            if (api_valid_email($dest)) {
8871
                $mail->AddAddress($dest, $recipient_name);
8872
            }
8873
        }
8874
    } else {
8875
        if (api_valid_email($recipient_email)) {
8876
            $mail->AddAddress($recipient_email, $recipient_name);
8877
        } else {
8878
            return 0;
8879
        }
8880
    }
8881
8882
    if (is_array($extra_headers) && count($extra_headers) > 0) {
8883
        foreach ($extra_headers as $key => $value) {
8884
            switch (strtolower($key)) {
8885
                case 'encoding':
8886
                case 'content-transfer-encoding':
8887
                    $mail->Encoding = $value;
8888
                    break;
8889
                case 'charset':
8890
                    $mail->Charset = $value;
8891
                    break;
8892
                case 'contenttype':
8893
                case 'content-type':
8894
                    $mail->ContentType = $value;
8895
                    break;
8896
                default:
8897
                    $mail->AddCustomHeader($key.':'.$value);
8898
                    break;
8899
            }
8900
        }
8901
    } else {
8902
        if (!empty($extra_headers)) {
8903
            $mail->AddCustomHeader($extra_headers);
8904
        }
8905
    }
8906
8907
    // WordWrap the html body (phpMailer only fixes AltBody) FS#2988
8908
    $mail->Body = $mail->WrapText($mail->Body, $mail->WordWrap);
8909
8910
    // Send the mail message.
8911
    if (!$mail->Send()) {
8912
        error_log('ERROR: mail not sent to '.$recipient_name.' ('.$recipient_email.') because of '.$mail->ErrorInfo.'<br />');
8913
        if ($mail->SMTPDebug) {
8914
            error_log(
8915
                "Connection details :: ".
8916
                "Protocol: ".$mail->Mailer.' :: '.
8917
                "Host/Port: ".$mail->Host.':'.$mail->Port.' :: '.
8918
                "Authent/Open: ".($mail->SMTPAuth ? 'Authent' : 'Open').' :: '.
8919
                ($mail->SMTPAuth ? "  User/Pass: ".$mail->Username.':'.$mail->Password : '').' :: '.
8920
                "Sender: ".$mail->Sender
8921
            );
8922
        }
8923
8924
        return 0;
8925
    }
8926
8927
    if (!empty($additionalParameters)) {
8928
        $plugin = new AppPlugin();
8929
        $smsPlugin = $plugin->getSMSPluginLibrary();
8930
        if ($smsPlugin) {
8931
            $smsPlugin->send($additionalParameters);
8932
        }
8933
    }
8934
8935
    // Clear all the addresses.
8936
    $mail->ClearAddresses();
8937
8938
    // Clear all attachments
8939
    $mail->ClearAttachments();
8940
8941
    return 1;
8942
}
8943
8944
/**
8945
 * @param string $tool       Possible values: GroupManager::GROUP_TOOL_*
8946
 * @param bool   $showHeader
8947
 */
8948
function api_protect_course_group($tool, $showHeader = true)
8949
{
8950
    $userId = api_get_user_id();
8951
    $groupId = api_get_group_id();
8952
    $groupInfo = GroupManager::get_group_properties($groupId);
8953
8954
    if (!empty($groupInfo)) {
8955
        $allow = GroupManager::user_has_access(
8956
            $userId,
8957
            $groupInfo['iid'],
8958
            $tool
8959
        );
8960
8961
        if (!$allow) {
8962
            api_not_allowed($showHeader);
8963
        }
8964
    }
8965
}
8966
8967
/**
8968
 * Check if a date is in a date range.
8969
 *
8970
 * @param datetime $startDate
8971
 * @param datetime $endDate
8972
 * @param datetime $currentDate
8973
 *
8974
 * @return bool true if date is in rage, false otherwise
8975
 */
8976
function api_is_date_in_date_range($startDate, $endDate, $currentDate = null)
8977
{
8978
    $startDate = strtotime(api_get_local_time($startDate));
8979
    $endDate = strtotime(api_get_local_time($endDate));
8980
    $currentDate = strtotime(api_get_local_time($currentDate));
8981
8982
    if ($currentDate >= $startDate && $currentDate <= $endDate) {
8983
        return true;
8984
    }
8985
8986
    return false;
8987
}
8988
8989
/**
8990
 * Eliminate the duplicates of a multidimensional array by sending the key.
8991
 *
8992
 * @param array $array multidimensional array
8993
 * @param int   $key   key to find to compare
8994
 *
8995
 * @return array
8996
 */
8997
function api_unique_multidim_array($array, $key)
8998
{
8999
    $temp_array = [];
9000
    $i = 0;
9001
    $key_array = [];
9002
9003
    foreach ($array as $val) {
9004
        if (!in_array($val[$key], $key_array)) {
9005
            $key_array[$i] = $val[$key];
9006
            $temp_array[$i] = $val;
9007
        }
9008
        $i++;
9009
    }
9010
9011
    return $temp_array;
9012
}
9013
9014
/**
9015
 * Limit the access to Session Admins wheen the limit_session_admin_role
9016
 * configuration variable is set to true.
9017
 */
9018
function api_protect_limit_for_session_admin()
9019
{
9020
    $limitAdmin = api_get_setting('limit_session_admin_role');
9021
    if (api_is_session_admin() && $limitAdmin === 'true') {
9022
        api_not_allowed(true);
9023
    }
9024
}
9025
9026
/**
9027
 * @return bool
9028
 */
9029
function api_is_student_view_active()
9030
{
9031
    $studentView = Session::read('studentview');
9032
9033
    return $studentView == 'studentview';
9034
}
9035
9036
/**
9037
 * Adds a file inside the upload/$type/id.
9038
 *
9039
 * @param string $type
9040
 * @param array  $file
9041
 * @param int    $itemId
9042
 * @param string $cropParameters
9043
 *
9044
 * @return array|bool
9045
 */
9046
function api_upload_file($type, $file, $itemId, $cropParameters = '')
9047
{
9048
    $upload = process_uploaded_file($file);
9049
    if ($upload) {
9050
        $name = api_replace_dangerous_char($file['name']);
9051
9052
        // No "dangerous" files
9053
        $name = disable_dangerous_file($name);
9054
9055
        $pathId = '/'.substr((string) $itemId, 0, 1).'/'.$itemId.'/';
9056
        $path = api_get_path(SYS_UPLOAD_PATH).$type.$pathId;
9057
9058
        if (!is_dir($path)) {
9059
            mkdir($path, api_get_permissions_for_new_directories(), true);
9060
        }
9061
9062
        $pathToSave = $path.$name;
9063
9064
        $result = move_uploaded_file($file['tmp_name'], $pathToSave);
9065
        if ($result) {
9066
            if (!empty($cropParameters)) {
9067
                $image = new Image($pathToSave);
9068
                $image->crop($cropParameters);
9069
            }
9070
9071
            return ['path_to_save' => $pathId.$name];
9072
        }
9073
9074
        return false;
9075
    }
9076
}
9077
9078
/**
9079
 * @param string $type
9080
 * @param int    $itemId
9081
 * @param string $file
9082
 *
9083
 * @return bool
9084
 */
9085
function api_get_uploaded_web_url($type, $itemId, $file)
9086
{
9087
    return api_get_uploaded_file($type, $itemId, $file, true);
9088
}
9089
9090
/**
9091
 * @param string $type
9092
 * @param int    $itemId
9093
 * @param string $file
9094
 * @param bool   $getUrl
9095
 *
9096
 * @return bool
9097
 */
9098
function api_get_uploaded_file($type, $itemId, $file, $getUrl = false)
9099
{
9100
    $itemId = (int) $itemId;
9101
    $pathId = '/'.substr((string) $itemId, 0, 1).'/'.$itemId.'/';
9102
    $path = api_get_path(SYS_UPLOAD_PATH).$type.$pathId;
9103
    $file = basename($file);
9104
    $file = $path.'/'.$file;
9105
    if (Security::check_abs_path($file, $path) && is_file($file) && file_exists($file)) {
9106
        if ($getUrl) {
9107
            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...
9108
        }
9109
9110
        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...
9111
    }
9112
9113
    return false;
9114
}
9115
9116
/**
9117
 * @param string $type
9118
 * @param int    $itemId
9119
 * @param string $file
9120
 * @param string $title
9121
 */
9122
function api_download_uploaded_file($type, $itemId, $file, $title = '')
9123
{
9124
    $file = api_get_uploaded_file($type, $itemId, $file);
9125
    if ($file) {
9126
        if (Security::check_abs_path($file, api_get_path(SYS_UPLOAD_PATH).$type)) {
9127
            DocumentManager::file_send_for_download($file, true, $title);
9128
            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...
9129
        }
9130
    }
9131
    api_not_allowed(true);
9132
}
9133
9134
/**
9135
 * @param string $type
9136
 * @param string $file
9137
 */
9138
function api_remove_uploaded_file($type, $file)
9139
{
9140
    $typePath = api_get_path(SYS_UPLOAD_PATH).$type;
9141
    $path = $typePath.'/'.$file;
9142
    if (Security::check_abs_path($path, $typePath) && file_exists($path) && is_file($path)) {
9143
        unlink($path);
9144
    }
9145
}
9146
9147
/**
9148
 * Converts string value to float value.
9149
 *
9150
 * 3.141516 => 3.141516
9151
 * 3,141516 => 3.141516
9152
 *
9153
 * @todo WIP
9154
 *
9155
 * @param string $number
9156
 *
9157
 * @return float
9158
 */
9159
function api_float_val($number)
9160
{
9161
    $number = (float) str_replace(',', '.', trim($number));
9162
9163
    return $number;
9164
}
9165
9166
/**
9167
 * Converts float values
9168
 * Example if $decimals = 2.
9169
 *
9170
 * 3.141516 => 3.14
9171
 * 3,141516 => 3,14
9172
 *
9173
 * @param string $number            number in iso code
9174
 * @param int    $decimals
9175
 * @param string $decimalSeparator
9176
 * @param string $thousandSeparator
9177
 *
9178
 * @return bool|string
9179
 */
9180
function api_number_format($number, $decimals = 0, $decimalSeparator = '.', $thousandSeparator = ',')
9181
{
9182
    $number = api_float_val($number);
9183
9184
    return number_format($number, $decimals, $decimalSeparator, $thousandSeparator);
9185
}
9186
9187
/**
9188
 * Set location url with a exit break by default.
9189
 *
9190
 * @param $url
9191
 * @param bool $exit
9192
 */
9193
function location($url, $exit = true)
9194
{
9195
    header('Location: '.$url);
9196
9197
    if ($exit) {
9198
        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...
9199
    }
9200
}
9201
9202
/**
9203
 * @return string
9204
 */
9205
function api_get_web_url()
9206
{
9207
    if (api_get_setting('server_type') == 'test') {
9208
        return api_get_path(WEB_PATH).'web/app_dev.php/';
9209
    } else {
9210
        return api_get_path(WEB_PATH).'web/';
9211
    }
9212
}
9213