Completed
Push — master ( a0b9ee...f2d979 )
by Julito
25:28 queued 04:47
created

api_get_course_entity()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

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

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

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

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

// Bar.php
namespace OtherDir;

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

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

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

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

// Bar.php
namespace OtherDir;

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

1082
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...
1083
{
1084
    $is_allowed_in_course = api_is_allowed_in_course();
1085
1086
    $is_visible = false;
1087
    $course_info = api_get_course_info();
1088
1089
    if (empty($course_info)) {
1090
        api_not_allowed($print_headers);
1091
        return false;
1092
    }
1093
1094
    if (api_is_drh()) {
1095
        return true;
1096
    }
1097
1098
    // Session admin has access to course
1099
    $sessionAccess = api_get_configuration_value('session_admins_access_all_content');
1100
    if ($sessionAccess) {
1101
        $allow_session_admins = true;
1102
    }
1103
1104
    if (api_is_platform_admin($allow_session_admins)) {
1105
        return true;
1106
    }
1107
1108
    if (isset($course_info) && isset($course_info['visibility'])) {
1109
        switch ($course_info['visibility']) {
1110
            default:
1111
            case COURSE_VISIBILITY_CLOSED:
1112
                // Completely closed: the course is only accessible to the teachers. - 0
1113
                if (api_get_user_id() && !api_is_anonymous() && $is_allowed_in_course) {
1114
                    $is_visible = true;
1115
                }
1116
                break;
1117
            case COURSE_VISIBILITY_REGISTERED:
1118
                // Private - access authorized to course members only - 1
1119
                if (api_get_user_id() && !api_is_anonymous() && $is_allowed_in_course) {
1120
                    $is_visible = true;
1121
                }
1122
                break;
1123
            case COURSE_VISIBILITY_OPEN_PLATFORM:
1124
                // Open - access allowed for users registered on the platform - 2
1125
                if (api_get_user_id() && !api_is_anonymous() && $is_allowed_in_course) {
1126
                    $is_visible = true;
1127
                }
1128
                break;
1129
            case COURSE_VISIBILITY_OPEN_WORLD:
1130
                //Open - access allowed for the whole world - 3
1131
                $is_visible = true;
1132
                break;
1133
            case COURSE_VISIBILITY_HIDDEN:
1134
                //Completely closed: the course is only accessible to the teachers. - 0
1135
                if (api_is_platform_admin()) {
1136
                    $is_visible = true;
1137
                }
1138
                break;
1139
        }
1140
1141
        //If password is set and user is not registered to the course then the course is not visible
1142
        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...
1143
            isset($course_info['registration_code']) &&
1144
            !empty($course_info['registration_code'])
1145
        ) {
1146
            $is_visible = false;
1147
        }
1148
    }
1149
1150
    // Check session visibility
1151
    $session_id = api_get_session_id();
1152
1153
    if (!empty($session_id)) {
1154
        //$is_allowed_in_course was set in local.inc.php
1155
        if (!$is_allowed_in_course) {
1156
            $is_visible = false;
1157
        }
1158
    }
1159
1160
    if (!$is_visible) {
1161
        api_not_allowed($print_headers);
1162
        return false;
1163
    }
1164
    return true;
1165
}
1166
1167
/**
1168
 * Function used to protect an admin script.
1169
 *
1170
 * The function blocks access when the user has no platform admin rights
1171
 * with an error message printed on default output
1172
 * @param bool Whether to allow session admins as well
1173
 * @param bool Whether to allow HR directors as well
1174
 * @param string An optional message (already passed through get_lang)
1175
 * @return bool True if user is allowed, false otherwise.
1176
 * The function also outputs an error message in case not allowed
1177
 * @author Roan Embrechts (original author)
1178
 */
1179
function api_protect_admin_script($allow_sessions_admins = false, $allow_drh = false, $message = null)
1180
{
1181
    if (!api_is_platform_admin($allow_sessions_admins, $allow_drh)) {
1182
        api_not_allowed(true, $message);
1183
        return false;
1184
    }
1185
    return true;
1186
}
1187
1188
/**
1189
 * Function used to protect a teacher script.
1190
 * The function blocks access when the user has no teacher rights.
1191
 *
1192
 * @author Yoselyn Castillo
1193
 */
1194
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

1194
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...
1195
{
1196
    if (!api_is_allowed_to_edit()) {
1197
        api_not_allowed(true);
1198
        return false;
1199
    }
1200
    return true;
1201
}
1202
1203
/**
1204
 * Function used to prevent anonymous users from accessing a script.
1205
 * @param bool|true $printHeaders
1206
 * @author Roan Embrechts
1207
 *
1208
 * @return bool
1209
 */
1210
function api_block_anonymous_users($printHeaders = true)
1211
{
1212
    $user = api_get_user_info();
1213
    if (!(isset($user['user_id']) && $user['user_id']) || api_is_anonymous($user['user_id'], true)) {
1214
        api_not_allowed($printHeaders);
1215
        return false;
1216
    }
1217
1218
    return true;
1219
}
1220
1221
/**
1222
 * @return array with the navigator name and version
1223
 */
1224
function api_get_navigator()
1225
{
1226
    $navigator = 'Unknown';
1227
    $version = 0;
1228
1229
    if (!isset($_SERVER['HTTP_USER_AGENT'])) {
1230
        return ['name' => 'Unknown', 'version' => '0.0.0'];
1231
    }
1232
1233
    if (strpos($_SERVER['HTTP_USER_AGENT'], 'Opera') !== false) {
1234
        $navigator = 'Opera';
1235
        list(, $version) = explode('Opera', $_SERVER['HTTP_USER_AGENT']);
1236
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== false) {
1237
        $navigator = 'Internet Explorer';
1238
        list(, $version) = explode('MSIE', $_SERVER['HTTP_USER_AGENT']);
1239
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Chrome') !== false) {
1240
        $navigator = 'Chrome';
1241
        list(, $version) = explode('Chrome', $_SERVER['HTTP_USER_AGENT']);
1242
    } elseif (stripos($_SERVER['HTTP_USER_AGENT'], 'safari') !== false) {
1243
        $navigator = 'Safari';
1244
        list(, $version) = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1245
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Gecko') !== false) {
1246
        $navigator = 'Mozilla';
1247
        list(, $version) = explode('; rv:', $_SERVER['HTTP_USER_AGENT']);
1248
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Netscape') !== false) {
1249
        $navigator = 'Netscape';
1250
        list(, $version) = explode('Netscape', $_SERVER['HTTP_USER_AGENT']);
1251
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Konqueror') !== false) {
1252
        $navigator = 'Konqueror';
1253
        list(, $version) = explode('Konqueror', $_SERVER['HTTP_USER_AGENT']);
1254
    } elseif (stripos($_SERVER['HTTP_USER_AGENT'], 'applewebkit') !== false) {
1255
        $navigator = 'AppleWebKit';
1256
        list(, $version) = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1257
    }
1258
    $version = str_replace('/', '', $version);
1259
    if (strpos($version, '.') === false) {
1260
        $version = number_format(doubleval($version), 1);
1261
    }
1262
    $return = ['name' => $navigator, 'version' => $version];
1263
    return $return;
1264
}
1265
1266
/**
1267
 * @return True if user self registration is allowed, false otherwise.
1268
 */
1269
function api_is_self_registration_allowed()
1270
{
1271
    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...
1272
}
1273
1274
/**
1275
 * This function returns the id of the user which is stored in the $_user array.
1276
 *
1277
 * example: The function can be used to check if a user is logged in
1278
 *          if (api_get_user_id())
1279
 * @return int the id of the current user, 0 if is empty
1280
 */
1281
function api_get_user_id()
1282
{
1283
    $userInfo = Session::read('_user');
1284
    if ($userInfo && isset($userInfo['user_id'])) {
1285
        return (int) $userInfo['user_id'];
1286
    }
1287
    return 0;
1288
}
1289
1290
/**
1291
 * Gets the list of courses a specific user is subscribed to
1292
 * @param int       User ID
1293
 * @param boolean   $fetch_session Whether to get session courses or not - NOT YET IMPLEMENTED
1294
 * @return array    Array of courses in the form [0]=>('code'=>xxx,'db'=>xxx,'dir'=>xxx,'status'=>d)
1295
 * @deprecated use CourseManager::get_courses_list_by_user_id()
1296
 */
1297
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

1297
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...
1298
{
1299
    // Get out if not integer
1300
    if ($userid != strval(intval($userid))) {
1301
        return [];
1302
    }
1303
1304
    $t_course = Database::get_main_table(TABLE_MAIN_COURSE);
1305
    $t_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
1306
1307
    $sql = "SELECT cc.id as real_id, cc.code code, cc.directory dir, cu.status status
1308
            FROM    $t_course       cc,
1309
                    $t_course_user   cu
1310
            WHERE
1311
                cc.id = cu.c_id AND
1312
                cu.user_id = '".$userid."' AND
1313
                cu.relation_type<>".COURSE_RELATION_TYPE_RRHH." ";
1314
    $result = Database::query($sql);
1315
    if ($result === false) {
1316
        return [];
1317
    }
1318
1319
    $courses = [];
1320
    while ($row = Database::fetch_array($result)) {
1321
        // we only need the database name of the course
1322
        $courses[] = $row;
1323
    }
1324
1325
    return $courses;
1326
}
1327
1328
/**
1329
 * Formats user information into a standard array
1330
 * This function should be only used inside api_get_user_info()
1331
 *
1332
 * @param array Non-standard user array
1333
 * @param bool $add_password
1334
 * @param bool $loadAvatars turn off to improve performance
1335
 *
1336
 * @return array Standard user array
1337
 */
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...
1338
function _api_format_user($user, $add_password = false, $loadAvatars = true)
1339
{
1340
    $result = [];
1341
1342
    $result['firstname'] = null;
1343
    $result['lastname'] = null;
1344
1345
    if (isset($user['firstname']) && isset($user['lastname'])) { // with only lowercase
1346
        $result['firstname'] = $user['firstname'];
1347
        $result['lastname'] = $user['lastname'];
1348
    } elseif (isset($user['firstName']) && isset($user['lastName'])) { // with uppercase letters
1349
        $result['firstname'] = isset($user['firstName']) ? $user['firstName'] : null;
1350
        $result['lastname'] = isset($user['lastName']) ? $user['lastName'] : null;
1351
    }
1352
1353
    if (isset($user['email'])) {
1354
        $result['mail'] = isset($user['email']) ? $user['email'] : null;
1355
        $result['email'] = isset($user['email']) ? $user['email'] : null;
1356
    } else {
1357
        $result['mail'] = isset($user['mail']) ? $user['mail'] : null;
1358
        $result['email'] = isset($user['mail']) ? $user['mail'] : null;
1359
    }
1360
1361
    $result['complete_name'] = api_get_person_name($result['firstname'], $result['lastname']);
1362
    $result['complete_name_with_username'] = $result['complete_name'];
1363
1364
    if (!empty($user['username'])) {
1365
        $result['complete_name_with_username'] = $result['complete_name'].' ('.$user['username'].')';
1366
    }
1367
1368
    $showEmail = api_get_setting('show_email_addresses') === 'true';
1369
    if (!empty($user['email'])) {
1370
        $result['complete_name_with_email_forced'] = $result['complete_name'].' ('.$user['email'].')';
1371
        if ($showEmail) {
1372
            $result['complete_name_with_email'] = $result['complete_name'].' ('.$user['email'].')';
1373
        }
1374
    } else {
1375
        $result['complete_name_with_email'] = $result['complete_name'];
1376
        $result['complete_name_with_email_forced'] = $result['complete_name'];
1377
    }
1378
1379
    // Kept for historical reasons
1380
    $result['firstName'] = $result['firstname'];
1381
    $result['lastName'] = $result['lastname'];
1382
1383
    $attributes = [
1384
        'phone',
1385
        'address',
1386
        'picture_uri',
1387
        'official_code',
1388
        'status',
1389
        'active',
1390
        'auth_source',
1391
        'username',
1392
        'theme',
1393
        'language',
1394
        'creator_id',
1395
        'registration_date',
1396
        'hr_dept_id',
1397
        'expiration_date',
1398
        'last_login',
1399
        'user_is_online'
1400
    ];
1401
1402
    if (api_get_setting('extended_profile') === 'true') {
1403
        $attributes[] = 'competences';
1404
        $attributes[] = 'diplomas';
1405
        $attributes[] = 'teach';
1406
        $attributes[] = 'openarea';
1407
    }
1408
1409
    foreach ($attributes as $attribute) {
1410
        $result[$attribute] = isset($user[$attribute]) ? $user[$attribute] : null;
1411
    }
1412
1413
    $user_id = intval($user['user_id']);
1414
    // Maintain the user_id index for backwards compatibility
1415
    $result['user_id'] = $result['id'] = $user_id;
1416
1417
    // Getting user avatar.
1418
    if ($loadAvatars) {
1419
        $result['avatar'] = '';
1420
        $result['avatar_no_query'] = '';
1421
        $result['avatar_small'] = '';
1422
        $result['avatar_medium'] = '';
1423
1424
        if (!isset($user['avatar'])) {
1425
            $originalFile = UserManager::getUserPicture(
1426
                $user_id,
1427
                USER_IMAGE_SIZE_ORIGINAL,
1428
                null,
1429
                $result
1430
            );
1431
            $result['avatar'] = $originalFile;
1432
            $avatarString = explode('?', $result['avatar']);
1433
            $result['avatar_no_query'] = reset($avatarString);
1434
        } else {
1435
            $result['avatar'] = $user['avatar'];
1436
            $avatarString = explode('?', $user['avatar']);
1437
            $result['avatar_no_query'] = reset($avatarString);
1438
        }
1439
1440
        if (!isset($user['avatar_small'])) {
1441
            $smallFile = UserManager::getUserPicture(
1442
                $user_id,
1443
                USER_IMAGE_SIZE_SMALL,
1444
                null,
1445
                $result
1446
            );
1447
            $result['avatar_small'] = $smallFile;
1448
        } else {
1449
            $result['avatar_small'] = $user['avatar_small'];
1450
        }
1451
1452
        if (!isset($user['avatar_medium'])) {
1453
            $mediumFile = UserManager::getUserPicture(
1454
                $user_id,
1455
                USER_IMAGE_SIZE_MEDIUM,
1456
                null,
1457
                $result
1458
            );
1459
            $result['avatar_medium'] = $mediumFile;
1460
        } else {
1461
            $result['avatar_medium'] = $user['avatar_medium'];
1462
        }
1463
    }
1464
1465
    if (isset($user['user_is_online'])) {
1466
        $result['user_is_online'] = $user['user_is_online'] == true ? 1 : 0;
1467
    }
1468
    if (isset($user['user_is_online_in_chat'])) {
1469
        $result['user_is_online_in_chat'] = intval($user['user_is_online_in_chat']);
1470
    }
1471
1472
    if ($add_password) {
1473
        $result['password'] = $user['password'];
1474
    }
1475
1476
    if (isset($result['profile_completed'])) {
1477
        $result['profile_completed'] = $user['profile_completed'];
1478
    }
1479
1480
    $result['profile_url'] = api_get_path(WEB_CODE_PATH).'social/profile.php?u='.$user_id;
1481
1482
    // Send message link
1483
    $sendMessage = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&user_id='.$user_id;
1484
    $result['complete_name_with_message_link'] = Display::url(
1485
        $result['complete_name_with_username'],
1486
        $sendMessage,
1487
        ['class' => 'ajax']
1488
    );
1489
1490
    if (isset($user['extra'])) {
1491
        $result['extra'] = $user['extra'];
1492
    }
1493
1494
    return $result;
1495
}
1496
1497
/**
1498
 * Finds all the information about a user.
1499
 * If no parameter is passed you find all the information about the current user.
1500
 * @param int  $user_id
1501
 * @param bool $checkIfUserOnline
1502
 * @param bool $showPassword
1503
 * @param bool $loadExtraData
1504
 * @param bool $loadOnlyVisibleExtraData Get the user extra fields that are visible
1505
 * @param bool $loadAvatars turn off to improve performance and if avatars are not needed.
1506
 * @param bool $updateCache update apc cache if exists
1507
 *
1508
 * @return array $user_info user_id, lastname, firstname, username, email, etc
1509
 * @author Patrick Cool <[email protected]>
1510
 * @author Julio Montoya
1511
 * @version 21 September 2004
1512
 */
1513
function api_get_user_info(
1514
    $user_id = 0,
1515
    $checkIfUserOnline = false,
1516
    $showPassword = false,
1517
    $loadExtraData = false,
1518
    $loadOnlyVisibleExtraData = false,
1519
    $loadAvatars = true,
1520
    $updateCache = false
1521
) {
1522
    $apcVar = null;
1523
    $user = false;
1524
    $cacheAvailable = api_get_configuration_value('apc');
1525
1526
    if (empty($user_id)) {
1527
        $userFromSession = Session::read('_user');
1528
1529
        if (isset($userFromSession)) {
1530
            if ($cacheAvailable === true) {
1531
                $apcVar = api_get_configuration_value('apc_prefix').'userinfo_'.$userFromSession['user_id'];
0 ignored issues
show
Bug introduced by
Are you sure api_get_configuration_value('apc_prefix') of type mixed|false can be used in concatenation? ( Ignorable by Annotation )

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

1531
                $apcVar = /** @scrutinizer ignore-type */ api_get_configuration_value('apc_prefix').'userinfo_'.$userFromSession['user_id'];
Loading history...
1532
                if (apcu_exists($apcVar)) {
1533
                    if ($updateCache) {
1534
                        apcu_store($apcVar, $userFromSession, 60);
1535
                    }
1536
                    $user = apcu_fetch($apcVar);
1537
                } else {
1538
                    $user = _api_format_user(
1539
                        $userFromSession,
1540
                        $showPassword,
1541
                        $loadAvatars
1542
                    );
1543
                    apcu_store($apcVar, $user, 60);
1544
                }
1545
            } else {
1546
                $user = _api_format_user(
1547
                    $userFromSession,
1548
                    $showPassword,
1549
                    $loadAvatars
1550
                );
1551
            }
1552
1553
            return $user;
1554
        }
1555
1556
        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...
1557
    }
1558
1559
    // Make sure user_id is safe
1560
    $user_id = intval($user_id);
1561
1562
    // Re-use user information if not stale and already stored in APCu
1563
    if ($cacheAvailable === true) {
1564
        $apcVar = api_get_configuration_value('apc_prefix').'userinfo_'.$user_id;
1565
        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...
1566
            $user = apcu_fetch($apcVar);
1567
1568
            return $user;
1569
        }
1570
    }
1571
1572
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1573
            WHERE id = $user_id";
1574
    $result = Database::query($sql);
1575
    if (Database::num_rows($result) > 0) {
1576
        $result_array = Database::fetch_array($result);
1577
        if ($checkIfUserOnline) {
1578
            $use_status_in_platform = user_is_online($user_id);
1579
            $result_array['user_is_online'] = $use_status_in_platform;
1580
            $user_online_in_chat = 0;
1581
1582
            if ($use_status_in_platform) {
1583
                $user_status = UserManager::get_extra_user_data_by_field(
1584
                    $user_id,
1585
                    'user_chat_status',
1586
                    false,
1587
                    true
1588
                );
1589
                if (@intval($user_status['user_chat_status']) == 1) {
1590
                    $user_online_in_chat = 1;
1591
                }
1592
            }
1593
            $result_array['user_is_online_in_chat'] = $user_online_in_chat;
1594
        }
1595
1596
        if ($loadExtraData) {
1597
            $fieldValue = new ExtraFieldValue('user');
1598
            $result_array['extra'] = $fieldValue->getAllValuesForAnItem(
1599
                $user_id,
1600
                $loadOnlyVisibleExtraData
1601
            );
1602
        }
1603
        $user = _api_format_user($result_array, $showPassword, $loadAvatars);
1604
    }
1605
1606
    if ($cacheAvailable === true) {
1607
        apcu_store($apcVar, $user, 60);
1608
    }
1609
1610
    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...
1611
}
1612
1613
/**
1614
 * @param int $userId
1615
 * @return User
1616
 */
1617
function api_get_user_entity($userId)
1618
{
1619
    $userId = (int) $userId;
1620
    /** @var \Chamilo\UserBundle\Repository\UserRepository $repo */
1621
    $repo = Database::getManager()->getRepository('ChamiloUserBundle:User');
1622
1623
    return $repo->find($userId);
1624
}
1625
1626
/**
1627
 * Finds all the information about a user from username instead of user id
1628
 * @param string $username
1629
 * @return array $user_info array user_id, lastname, firstname, username, email
1630
 * @author Yannick Warnier <[email protected]>
1631
 */
1632
function api_get_user_info_from_username($username = '')
1633
{
1634
    if (empty($username)) {
1635
        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...
1636
    }
1637
    $username = trim($username);
1638
1639
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1640
            WHERE username='".Database::escape_string($username)."'";
1641
    $result = Database::query($sql);
1642
    if (Database::num_rows($result) > 0) {
1643
        $result_array = Database::fetch_array($result);
1644
        return _api_format_user($result_array);
1645
    }
1646
    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...
1647
}
1648
1649
/**
1650
 * Get first user with an email
1651
 * @param string $email
1652
 * @return array|bool
1653
 */
1654
function api_get_user_info_from_email($email = '')
1655
{
1656
    if (empty($email)) {
1657
        return false;
1658
    }
1659
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1660
            WHERE email ='".Database::escape_string($email)."' LIMIT 1";
1661
    $result = Database::query($sql);
1662
    if (Database::num_rows($result) > 0) {
1663
        $result_array = Database::fetch_array($result);
1664
        return _api_format_user($result_array);
1665
    }
1666
1667
    return false;
1668
}
1669
1670
/**
1671
 * @return string
1672
 */
1673
function api_get_course_id()
1674
{
1675
    return Session::read('_cid', null);
1676
}
1677
1678
/**
1679
 * Returns the current course id (integer)
1680
 * @param   string  $code   Optional course code
1681
 * @return int
1682
 */
1683
function api_get_course_int_id($code = null)
1684
{
1685
    if (!empty($code)) {
1686
        $code = Database::escape_string($code);
1687
        $row = Database::select(
1688
            'id',
1689
            Database::get_main_table(TABLE_MAIN_COURSE),
1690
            ['where'=> ['code = ?' => [$code]]],
1691
            'first'
1692
        );
1693
1694
        if (is_array($row) && isset($row['id'])) {
1695
            return $row['id'];
1696
        } else {
1697
            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...
1698
        }
1699
    }
1700
    return Session::read('_real_cid', 0);
1701
}
1702
1703
/**
1704
 * Returns the current course directory
1705
 *
1706
 * This function relies on api_get_course_info()
1707
 * @param string    The course code - optional (takes it from session if not given)
1708
 * @return string   The directory where the course is located inside the Chamilo "courses" directory
1709
 * @author Yannick Warnier <[email protected]>
1710
 */
1711
function api_get_course_path($course_code = null)
1712
{
1713
    $info = !empty($course_code) ? api_get_course_info($course_code) : api_get_course_info();
1714
    return $info['path'];
1715
}
1716
1717
/**
1718
 * Gets a course setting from the current course_setting table. Try always using integer values.
1719
 * @param string    The name of the setting we want from the table
1720
 * @param string    Optional: course code
1721
 * @param string $setting_name
1722
 * @return mixed    The value of that setting in that table. Return -1 if not found.
1723
 */
1724
function api_get_course_setting($setting_name, $course_code = null)
1725
{
1726
    $course_info = api_get_course_info($course_code);
1727
    $table = Database::get_course_table(TABLE_COURSE_SETTING);
1728
    $setting_name = Database::escape_string($setting_name);
1729
    if (!empty($course_info['real_id']) && !empty($setting_name)) {
1730
        $sql = "SELECT value FROM $table
1731
                WHERE c_id = {$course_info['real_id']} AND variable = '$setting_name'";
1732
        $res = Database::query($sql);
1733
        if (Database::num_rows($res) > 0) {
1734
            $row = Database::fetch_array($res);
1735
            if ($setting_name === 'email_alert_manager_on_new_quiz') {
1736
                if (!is_null($row['value'])) {
1737
                    $result = explode(',', $row['value']);
1738
                    $row['value'] = $result;
1739
                }
1740
            }
1741
            return $row['value'];
1742
        }
1743
    }
1744
    return -1;
1745
}
1746
1747
/**
1748
 * Gets an anonymous user ID
1749
 *
1750
 * For some tools that need tracking, like the learnpath tool, it is necessary
1751
 * to have a usable user-id to enable some kind of tracking, even if not
1752
 * perfect. An anonymous ID is taken from the users table by looking for a
1753
 * status of "6" (anonymous).
1754
 * @return int  User ID of the anonymous user, or O if no anonymous user found
1755
 */
1756
function api_get_anonymous_id()
1757
{
1758
    // Find if another anon is connected now
1759
    $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
1760
    $tableU = Database::get_main_table(TABLE_MAIN_USER);
1761
    $ip = api_get_real_ip();
1762
    $max = api_get_configuration_value('max_anonymous_users');
1763
    if ($max >= 2) {
1764
        $sql = "SELECT * FROM $table as TEL 
1765
                JOIN $tableU as U
1766
                ON U.user_id = TEL.login_user_id
1767
                WHERE TEL.user_ip = '$ip'
1768
                    AND U.status = ".ANONYMOUS."
1769
                    AND U.user_id != 2 ";
1770
1771
        $result = Database::query($sql);
1772
        if (empty(Database::num_rows($result))) {
1773
            $login = uniqid('anon_');
1774
            $anonList = UserManager::get_user_list(['status' => ANONYMOUS], ['registration_date ASC']);
1775
            if (count($anonList) == $max) {
1776
                foreach ($anonList as $userToDelete) {
1777
                    UserManager::delete_user($userToDelete['user_id']);
1778
                    break;
1779
                }
1780
            }
1781
            $userId = UserManager::create_user(
1782
                $login,
1783
                'anon',
1784
                ANONYMOUS,
1785
                ' anonymous@localhost',
1786
                $login,
1787
                $login
1788
            );
1789
            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...
1790
        } else {
1791
            $row = Database::fetch_array($result, 'ASSOC');
1792
            return $row['user_id'];
1793
        }
1794
    }
1795
1796
    $table = Database::get_main_table(TABLE_MAIN_USER);
1797
    $sql = "SELECT user_id 
1798
            FROM $table 
1799
            WHERE status = ".ANONYMOUS." ";
1800
    $res = Database::query($sql);
1801
    if (Database::num_rows($res) > 0) {
1802
        $row = Database::fetch_array($res, 'ASSOC');
1803
        return $row['user_id'];
1804
    }
1805
1806
    // No anonymous user was found.
1807
    return 0;
1808
}
1809
1810
/**
1811
 * @param string $courseCode
1812
 * @param int $sessionId
1813
 * @param int $groupId
1814
 * @return string
1815
 */
1816
function api_get_cidreq_params($courseCode, $sessionId = 0, $groupId = 0)
1817
{
1818
    $courseCode = !empty($courseCode) ? htmlspecialchars($courseCode) : '';
1819
    $sessionId = !empty($sessionId) ? (int) $sessionId : 0;
1820
    $groupId = !empty($groupId) ? (int) $groupId : 0;
1821
1822
    $url = 'cidReq='.$courseCode;
1823
    $url .= '&id_session='.$sessionId;
1824
    $url .= '&gidReq='.$groupId;
1825
1826
    return $url;
1827
}
1828
1829
/**
1830
 * Returns the current course url part including session, group, and gradebook params
1831
 *
1832
 * @param bool $addSessionId
1833
 * @param bool $addGroupId
1834
 * @param string $origin
1835
 *
1836
 * @return  string  Course & session references to add to a URL
1837
 *
1838
 */
1839
function api_get_cidreq($addSessionId = true, $addGroupId = true, $origin = '')
1840
{
1841
    $courseCode = api_get_course_id();
1842
    $url = empty($courseCode) ? '' : 'cidReq='.htmlspecialchars($courseCode);
1843
    $origin = empty($origin) ? api_get_origin() : Security::remove_XSS($origin);
1844
1845
    if ($addSessionId) {
1846
        if (!empty($url)) {
1847
            $url .= api_get_session_id() == 0 ? '&id_session=0' : '&id_session='.api_get_session_id();
1848
        }
1849
    }
1850
1851
    if ($addGroupId) {
1852
        if (!empty($url)) {
1853
            $url .= api_get_group_id() == 0 ? '&gidReq=0' : '&gidReq='.api_get_group_id();
1854
        }
1855
    }
1856
1857
    if (!empty($url)) {
1858
        $url .= '&gradebook='.intval(api_is_in_gradebook());
1859
        $url .= '&origin='.$origin;
1860
    }
1861
1862
    return $url;
1863
}
1864
1865
/**
1866
 * Get if we visited a gradebook page
1867
 * @return bool
1868
 */
1869
function api_is_in_gradebook()
1870
{
1871
    return Session::read('in_gradebook', false);
1872
}
1873
1874
/**
1875
 * Set that we are in a page inside a gradebook
1876
 * @return bool
1877
 */
1878
function api_set_in_gradebook()
1879
{
1880
    Session::write('in_gradebook', true);
1881
}
1882
1883
/**
1884
 * Remove gradebook session
1885
 */
1886
function api_remove_in_gradebook()
1887
{
1888
    Session::erase('in_gradebook');
1889
}
1890
1891
/**
1892
 * Returns the current course info array see api_format_course_array()
1893
 * If the course_code is given, the returned array gives info about that
1894
 * particular course, if none given it gets the course info from the session.
1895
 *
1896
 * @param string $course_code
1897
 * @param bool $strict
1898
 *
1899
 * @return array
1900
 */
1901
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

1901
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...
1902
{
1903
    if (!empty($course_code)) {
1904
        $course_code = Database::escape_string($course_code);
1905
        $courseId = api_get_course_int_id($course_code);
1906
1907
        if (empty($courseId)) {
1908
            return [];
1909
        }
1910
1911
        $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
1912
        $course_cat_table = Database::get_main_table(TABLE_MAIN_CATEGORY);
1913
        $sql = "SELECT
1914
                    course.*,
1915
                    course_category.code faCode,
1916
                    course_category.name faName
1917
                FROM $course_table
1918
                LEFT JOIN $course_cat_table
1919
                ON course.category_code = course_category.code
1920
                WHERE course.id = $courseId";
1921
        $result = Database::query($sql);
1922
        $courseInfo = [];
1923
        if (Database::num_rows($result) > 0) {
1924
            $data = Database::fetch_array($result);
1925
            $courseInfo = api_format_course_array($data);
1926
        }
1927
1928
        return $courseInfo;
1929
    }
1930
1931
    global $_course;
1932
    if ($_course == '-1') {
1933
        $_course = [];
1934
    }
1935
1936
    return $_course;
1937
}
1938
1939
/**
1940
 * @param int $courseId
1941
 * @return \Chamilo\CoreBundle\Entity\Course
1942
 */
1943
function api_get_course_entity($courseId)
1944
{
1945
    if (empty($courseId)) {
1946
        $courseId = api_get_course_int_id();
1947
    }
1948
    return CourseManager::getManager()->find($courseId);
1949
}
1950
1951
/**
1952
 * Returns the current course info array.
1953
1954
 * Now if the course_code is given, the returned array gives info about that
1955
 * particular course, not specially the current one.
1956
 * @param int $id Numeric ID of the course
1957
 * @return array The course info as an array formatted by api_format_course_array, including category.name
1958
 */
1959
function api_get_course_info_by_id($id = null)
1960
{
1961
    if (!empty($id)) {
1962
        $id = intval($id);
1963
        $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
1964
        $course_cat_table = Database::get_main_table(TABLE_MAIN_CATEGORY);
1965
        $sql = "SELECT
1966
                    course.*,
1967
                    course_category.code faCode,
1968
                    course_category.name faName
1969
                FROM $course_table
1970
                LEFT JOIN $course_cat_table
1971
                ON course.category_code = course_category.code
1972
                WHERE course.id = $id";
1973
        $result = Database::query($sql);
1974
        $_course = [];
1975
        if (Database::num_rows($result) > 0) {
1976
            $row = Database::fetch_array($result);
1977
            $_course = api_format_course_array($row);
1978
        }
1979
        return $_course;
1980
    }
1981
1982
    global $_course;
1983
    if ($_course == '-1') {
1984
        $_course = [];
1985
    }
1986
    return $_course;
1987
}
1988
1989
/**
1990
 * Reformat the course array (output by api_get_course_info()) in order, mostly,
1991
 * to switch from 'code' to 'id' in the array. This is a legacy feature and is
1992
 * now possibly causing massive confusion as a new "id" field has been added to
1993
 * the course table in 1.9.0.
1994
 * @param $course_data
1995
 * @return array
1996
 * @todo eradicate the false "id"=code field of the $_course array and use the int id
1997
 */
1998
function api_format_course_array($course_data)
1999
{
2000
    if (empty($course_data)) {
2001
        return [];
2002
    }
2003
2004
    $_course = [];
2005
    $_course['id'] = $course_data['code'];
2006
    $_course['real_id'] = $course_data['id'];
2007
2008
    // Added
2009
    $_course['code'] = $course_data['code'];
2010
    $_course['name'] = $course_data['title'];
2011
    $_course['title'] = $course_data['title'];
2012
    $_course['official_code'] = $course_data['visual_code'];
2013
    $_course['visual_code'] = $course_data['visual_code'];
2014
    $_course['sysCode'] = $course_data['code'];
2015
    $_course['path'] = $course_data['directory']; // Use as key in path.
2016
    $_course['directory'] = $course_data['directory'];
2017
    $_course['creation_date'] = $course_data['creation_date'];
2018
    $_course['titular'] = $course_data['tutor_name'];
2019
    $_course['language'] = $course_data['course_language'];
2020
    $_course['extLink']['url'] = $course_data['department_url'];
2021
    $_course['extLink']['name'] = $course_data['department_name'];
2022
    $_course['categoryCode'] = $course_data['faCode'];
2023
    $_course['categoryName'] = $course_data['faName'];
2024
    $_course['visibility'] = $course_data['visibility'];
2025
    $_course['subscribe_allowed'] = $course_data['subscribe'];
2026
    $_course['subscribe'] = $course_data['subscribe'];
2027
    $_course['unsubscribe'] = $course_data['unsubscribe'];
2028
    $_course['course_language'] = $course_data['course_language'];
2029
    $_course['activate_legal'] = isset($course_data['activate_legal']) ? $course_data['activate_legal'] : false;
2030
    $_course['legal'] = $course_data['legal'];
2031
    $_course['show_score'] = $course_data['show_score']; //used in the work tool
2032
    $_course['department_name'] = $course_data['department_name'];
2033
    $_course['department_url'] = $course_data['department_url'];
2034
2035
    $courseSys = api_get_path(SYS_COURSE_PATH).$course_data['directory'];
2036
    $webCourseHome = api_get_path(WEB_COURSE_PATH).$course_data['directory'];
2037
2038
    // Course password
2039
    $_course['registration_code'] = !empty($course_data['registration_code']) ? sha1($course_data['registration_code']) : null;
2040
    $_course['disk_quota'] = $course_data['disk_quota'];
2041
    $_course['course_public_url'] = $webCourseHome.'/index.php';
2042
2043
    if (array_key_exists('add_teachers_to_sessions_courses', $course_data)) {
2044
        $_course['add_teachers_to_sessions_courses'] = $course_data['add_teachers_to_sessions_courses'];
2045
    }
2046
2047
    // Course image
2048
    $_course['course_image_source'] = '';
2049
    if (file_exists($courseSys.'/course-pic85x85.png')) {
2050
        $url_image = $webCourseHome.'/course-pic85x85.png';
2051
        $_course['course_image_source'] = $courseSys.'/course-pic85x85.png';
2052
    } else {
2053
        $url_image = Display::return_icon(
2054
            'course.png',
2055
            null,
2056
            null,
2057
            ICON_SIZE_BIG,
2058
            null,
2059
            true,
2060
            false
2061
        );
2062
    }
2063
    $_course['course_image'] = $url_image;
2064
2065
    // Course large image
2066
    $_course['course_image_large_source'] = '';
2067
    if (file_exists($courseSys.'/course-pic.png')) {
2068
        $url_image = $webCourseHome.'/course-pic.png';
2069
        $_course['course_image_large_source'] = $courseSys.'/course-pic.png';
2070
    } else {
2071
        $url_image = Display::return_icon(
2072
            'session_default.png',
2073
            null,
2074
            null,
2075
            null,
2076
            null,
2077
            true
2078
        );
2079
    }
2080
    $_course['course_image_large'] = $url_image;
2081
2082
    return $_course;
2083
}
2084
2085
/**
2086
 * Returns a difficult to guess password.
2087
 * @param int $length the length of the password
2088
 * @return string the generated password
2089
 */
2090
function api_generate_password($length = 8)
2091
{
2092
    if ($length < 2) {
2093
        $length = 2;
2094
    }
2095
2096
    $charactersLowerCase = 'abcdefghijkmnopqrstuvwxyz';
2097
    $charactersUpperCase = 'ABCDEFGHJKLMNPQRSTUVWXYZ';
2098
    $minNumbers = 2;
2099
    $length = $length - $minNumbers;
2100
    $minLowerCase = round($length / 2);
2101
    $minUpperCase = $length - $minLowerCase;
2102
2103
    $password = '';
2104
    $passwordRequirements = api_get_configuration_value('password_requirements');
2105
2106
    $factory = new RandomLib\Factory();
2107
    $generator = $factory->getGenerator(new SecurityLib\Strength(SecurityLib\Strength::MEDIUM));
2108
2109
    if (!empty($passwordRequirements)) {
2110
        $length = $passwordRequirements['min']['length'];
2111
        $minNumbers = $passwordRequirements['min']['numeric'];
2112
        $minLowerCase = $passwordRequirements['min']['lowercase'];
2113
        $minUpperCase = $passwordRequirements['min']['uppercase'];
2114
2115
        $rest = $length - $minNumbers - $minLowerCase - $minUpperCase;
2116
        // Add the rest to fill the length requirement
2117
        if ($rest > 0) {
2118
            $password .= $generator->generateString($rest, $charactersLowerCase.$charactersUpperCase);
2119
        }
2120
    }
2121
2122
    // Min digits default 2
2123
    for ($i = 0; $i < $minNumbers; $i++) {
2124
        $password .= $generator->generateInt(2, 9);
2125
    }
2126
2127
    // Min lowercase
2128
    $password .= $generator->generateString($minLowerCase, $charactersLowerCase);
2129
2130
    // Min uppercase
2131
    $password .= $generator->generateString($minUpperCase, $charactersUpperCase);
2132
    $password = str_shuffle($password);
2133
2134
    return $password;
2135
}
2136
2137
/**
2138
 * Checks a password to see wether it is OK to use.
2139
 * @param string $password
2140
 * @return boolean if the password is acceptable, false otherwise
2141
 * Notes about what a password "OK to use" is:
2142
 * 1. The password should be at least 5 characters long.
2143
 * 2. Only English letters (uppercase or lowercase, it doesn't matter) and digits are allowed.
2144
 * 3. The password should contain at least 3 letters.
2145
 * 4. It should contain at least 2 digits.
2146
 * Settings will change if the configuration value is set: password_requirements
2147
 */
2148
function api_check_password($password)
2149
{
2150
    $passwordRequirements = Security::getPasswordRequirements();
2151
2152
    $minLength = $passwordRequirements['min']['length'];
2153
    $minNumbers = $passwordRequirements['min']['numeric'];
2154
    // Optional
2155
    $minLowerCase = $passwordRequirements['min']['lowercase'];
2156
    $minUpperCase = $passwordRequirements['min']['uppercase'];
2157
2158
    $minLetters = $minLowerCase + $minUpperCase;
2159
    $passwordLength = api_strlen($password);
2160
2161
    $conditions = [
2162
        'min_length' => $passwordLength >= $minLength
2163
    ];
2164
2165
    $digits = 0;
2166
    $lowerCase = 0;
2167
    $upperCase = 0;
2168
2169
    for ($i = 0; $i < $passwordLength; $i++) {
2170
        $currentCharacterCode = api_ord(api_substr($password, $i, 1));
2171
        if ($currentCharacterCode >= 65 && $currentCharacterCode <= 90) {
2172
            $upperCase++;
2173
        }
2174
2175
        if ($currentCharacterCode >= 97 && $currentCharacterCode <= 122) {
2176
            $lowerCase++;
2177
        }
2178
        if ($currentCharacterCode >= 48 && $currentCharacterCode <= 57) {
2179
            $digits++;
2180
        }
2181
    }
2182
2183
    // Min number of digits
2184
    $conditions['min_numeric'] = $digits >= $minNumbers;
2185
2186
    if (!empty($minUpperCase)) {
2187
        // Uppercase
2188
        $conditions['min_uppercase'] = $upperCase >= $minUpperCase;
2189
    }
2190
2191
    if (!empty($minLowerCase)) {
2192
        // Lowercase
2193
        $conditions['min_lowercase'] = $upperCase >= $minLowerCase;
2194
    }
2195
2196
    // Min letters
2197
    $letters = $upperCase + $lowerCase;
2198
    $conditions['min_letters'] = $letters >= $minLetters;
2199
2200
    $isPasswordOk = true;
2201
    foreach ($conditions as $condition) {
2202
        if ($condition === false) {
2203
            $isPasswordOk = false;
2204
            break;
2205
        }
2206
    }
2207
2208
    if ($isPasswordOk === false) {
2209
        $output = get_lang('NewPasswordRequirementsNotMatched').'<br />';
2210
        $output .= Security::getPasswordRequirementsToString($conditions);
2211
2212
        Display::addFlash(Display::return_message($output, 'warning', false));
2213
    }
2214
2215
    return $isPasswordOk;
2216
}
2217
2218
/**
2219
 * Clears the user ID from the session if it was the anonymous user. Generally
2220
 * used on out-of-tools pages to remove a user ID that could otherwise be used
2221
 * in the wrong context.
2222
 * This function is to be used in conjunction with the api_set_anonymous()
2223
 * function to simulate the user existence in case of an anonymous visit.
2224
 * @param bool      database check switch - passed to api_is_anonymous()
2225
 * @return bool     true if succesfully unregistered, false if not anonymous.
2226
 */
2227
function api_clear_anonymous($db_check = false)
2228
{
2229
    global $_user;
2230
    if (api_is_anonymous($_user['user_id'], $db_check)) {
2231
        unset($_user['user_id']);
2232
        Session::erase('_uid');
2233
        return true;
2234
    }
2235
    return false;
2236
}
2237
2238
/**
2239
 * Returns the status string corresponding to the status code
2240
 * @author Noel Dieschburg
2241
 * @param the int status code
2242
 * @return string
2243
 */
2244
function get_status_from_code($status_code)
2245
{
2246
    switch ($status_code) {
2247
        case STUDENT:
2248
            return get_lang('Student', '');
2249
        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...
2250
            return get_lang('Teacher', '');
2251
        case COURSEMANAGER:
2252
            return get_lang('Manager', '');
2253
        case SESSIONADMIN:
2254
            return get_lang('SessionsAdmin', '');
2255
        case DRH:
2256
            return get_lang('Drh', '');
2257
    }
2258
}
2259
2260
/**
2261
 * Sets the current user as anonymous if it hasn't been identified yet. This
2262
 * function should be used inside a tool only. The function api_clear_anonymous()
2263
 * acts in the opposite direction by clearing the anonymous user's data every
2264
 * time we get on a course homepage or on a neutral page (index, admin, my space)
2265
 * @return bool     true if set user as anonymous, false if user was already logged in or anonymous id could not be found
2266
 */
2267
function api_set_anonymous()
2268
{
2269
    global $_user;
2270
2271
    if (!empty($_user['user_id'])) {
2272
        return false;
2273
    }
2274
2275
    $user_id = api_get_anonymous_id();
2276
    if ($user_id == 0) {
2277
        return false;
2278
    }
2279
2280
    if (isset($_user['is_anonymous'])) {
2281
        return false;
2282
    }
2283
2284
    Session::erase('_user');
2285
    $_user['user_id'] = $user_id;
2286
    $_user['is_anonymous'] = true;
2287
    $GLOBALS['_user'] = $_user;
2288
    Session::write('_user', $_user);
2289
    return true;
2290
}
2291
2292
/**
2293
 * Gets the current Chamilo (not PHP/cookie) session ID
2294
 * @return  int     O if no active session, the session ID otherwise
2295
 */
2296
function api_get_session_id()
2297
{
2298
    return (int) Session::read('id_session', 0);
2299
}
2300
2301
/**
2302
 * Gets the current Chamilo (not social network) group ID
2303
 * @return  int     O if no active session, the session ID otherwise
2304
 */
2305
function api_get_group_id()
2306
{
2307
    return Session::read('_gid', 0);
2308
}
2309
2310
/**
2311
 * Gets the current or given session name
2312
 * @param   int     Session ID (optional)
2313
 * @return  string  The session name, or null if not found
2314
 */
2315
function api_get_session_name($session_id = 0)
2316
{
2317
    if (empty($session_id)) {
2318
        $session_id = api_get_session_id();
2319
        if (empty($session_id)) {
2320
            return null;
2321
        }
2322
    }
2323
    $t = Database::get_main_table(TABLE_MAIN_SESSION);
2324
    $s = "SELECT name FROM $t WHERE id = ".(int) $session_id;
2325
    $r = Database::query($s);
2326
    $c = Database::num_rows($r);
2327
    if ($c > 0) {
2328
        //technically, there can be only one, but anyway we take the first
2329
        $rec = Database::fetch_array($r);
2330
        return $rec['name'];
2331
    }
2332
    return null;
2333
}
2334
2335
/**
2336
 * Gets the session info by id
2337
 * @param int $id       Session ID
2338
 * @return array    information of the session
2339
 */
2340
function api_get_session_info($id)
2341
{
2342
    return SessionManager::fetch($id);
2343
}
2344
2345
/**
2346
 * Gets the session visibility by session id
2347
 * @param int $session_id
2348
 * @param int $courseId
2349
 * @param bool $ignore_visibility_for_admins
2350
 * @return int
2351
 *  0 = session still available,
2352
 *  SESSION_VISIBLE_READ_ONLY = 1,
2353
 *  SESSION_VISIBLE = 2,
2354
 *  SESSION_INVISIBLE = 3
2355
 */
2356
function api_get_session_visibility(
2357
    $session_id,
2358
    $courseId = null,
2359
    $ignore_visibility_for_admins = true
2360
) {
2361
    if (api_is_platform_admin()) {
2362
        if ($ignore_visibility_for_admins) {
2363
            return SESSION_AVAILABLE;
2364
        }
2365
    }
2366
2367
    $now = time();
2368
2369
    if (empty($session_id)) {
2370
        return 0; // Means that the session is still available.
2371
    }
2372
2373
    $session_id = intval($session_id);
2374
    $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
2375
2376
    $result = Database::query("SELECT * FROM $tbl_session WHERE id = $session_id");
2377
2378
    if (Database::num_rows($result) <= 0) {
2379
        return SESSION_INVISIBLE;
2380
    }
2381
2382
    $row = Database::fetch_array($result, 'ASSOC');
2383
    $visibility = $original_visibility = $row['visibility'];
2384
2385
    // I don't care the session visibility.
2386
    if (empty($row['access_start_date']) && empty($row['access_end_date'])) {
2387
        // Session duration per student.
2388
        if (isset($row['duration']) && !empty($row['duration'])) {
2389
            $duration = $row['duration'] * 24 * 60 * 60;
2390
            $courseAccess = CourseManager::getFirstCourseAccessPerSessionAndUser($session_id, api_get_user_id());
2391
2392
            // If there is a session duration but there is no previous
2393
            // access by the user, then the session is still available
2394
            if (count($courseAccess) == 0) {
2395
                return SESSION_AVAILABLE;
2396
            }
2397
2398
            $currentTime = time();
2399
            $firstAccess = isset($courseAccess['login_course_date'])
2400
                ? api_strtotime($courseAccess['login_course_date'], 'UTC')
2401
                : 0;
2402
            $userDurationData = SessionManager::getUserSession(
2403
                api_get_user_id(),
2404
                $session_id
2405
            );
2406
            $userDuration = isset($userDurationData['duration'])
2407
                ? (intval($userDurationData['duration']) * 24 * 60 * 60)
2408
                : 0;
2409
2410
            $totalDuration = $firstAccess + $duration + $userDuration;
2411
2412
            return $totalDuration > $currentTime ? SESSION_AVAILABLE : SESSION_VISIBLE_READ_ONLY;
2413
        }
2414
2415
        return SESSION_AVAILABLE;
2416
    }
2417
    // If start date was set.
2418
    if (!empty($row['access_start_date'])) {
2419
        $visibility = $now > api_strtotime($row['access_start_date'], 'UTC') ? SESSION_AVAILABLE : SESSION_INVISIBLE;
2420
    }
2421
2422
    // If the end date was set.
2423
    if (!empty($row['access_end_date'])) {
2424
        // Only if date_start said that it was ok
2425
        if ($visibility === SESSION_AVAILABLE) {
2426
            $visibility = $now < api_strtotime($row['access_end_date'], 'UTC')
2427
                ? SESSION_AVAILABLE // Date still available
2428
                : $row['visibility']; // Session ends
2429
        }
2430
    }
2431
2432
    /* If I'm a coach the visibility can change in my favor depending in
2433
     the coach dates */
2434
    $isCoach = api_is_coach($session_id, $courseId);
2435
2436
    if ($isCoach) {
2437
        // Test start date.
2438
        if (!empty($row['coach_access_start_date'])) {
2439
            $start = api_strtotime($row['coach_access_start_date'], 'UTC');
2440
            $visibility = $start < $now ? SESSION_AVAILABLE : SESSION_INVISIBLE;
2441
        }
2442
2443
        // Test end date.
2444
        if (!empty($row['coach_access_end_date'])) {
2445
            if ($visibility === SESSION_AVAILABLE) {
2446
                $endDateCoach = api_strtotime($row['coach_access_end_date'], 'UTC');
2447
                $visibility = $endDateCoach >= $now ? SESSION_AVAILABLE : $row['visibility'];
2448
            }
2449
        }
2450
    }
2451
2452
    return $visibility;
2453
}
2454
2455
/**
2456
 * This function returns a (star) session icon if the session is not null and
2457
 * the user is not a student
2458
 * @param int   $session_id
2459
 * @param int   $status_id User status id - if 5 (student), will return empty
2460
 * @return string   Session icon
2461
 */
2462
function api_get_session_image($session_id, $status_id)
2463
{
2464
    $session_id = (int) $session_id;
2465
    $session_img = '';
2466
    if ((int) $status_id != 5) { //check whether is not a student
2467
        if ($session_id > 0) {
2468
            $session_img = "&nbsp;&nbsp;".Display::return_icon(
2469
                    'star.png',
2470
                    get_lang('SessionSpecificResource'),
2471
                    ['align' => 'absmiddle'],
2472
                    ICON_SIZE_SMALL
2473
                );
2474
        }
2475
    }
2476
    return $session_img;
2477
}
2478
2479
/**
2480
 * This function add an additional condition according to the session of the course
2481
 * @param int       $session_id session id
2482
 * @param bool      $and optional, true if more than one condition false if the only condition in the query
2483
 * @param bool      $with_base_content optional, true to accept content with session=0 as well,
2484
 * false for strict session condition
2485
 * @param string $session_field
2486
 * @return string   condition of the session
2487
 */
2488
function api_get_session_condition(
2489
    $session_id,
2490
    $and = true,
2491
    $with_base_content = false,
2492
    $session_field = 'session_id'
2493
) {
2494
    $session_id = intval($session_id);
2495
2496
    if (empty($session_field)) {
2497
        $session_field = "session_id";
2498
    }
2499
    // Condition to show resources by session
2500
    $condition_add = $and ? " AND " : " WHERE ";
2501
2502
    if ($with_base_content) {
2503
        $condition_session = $condition_add." ( $session_field = $session_id OR $session_field = 0 OR $session_field IS NULL) ";
2504
    } else {
2505
        if (empty($session_id)) {
2506
            $condition_session = $condition_add." ($session_field = $session_id OR $session_field IS NULL)";
2507
        } else {
2508
            $condition_session = $condition_add." $session_field = $session_id ";
2509
        }
2510
    }
2511
    return $condition_session;
2512
}
2513
2514
/**
2515
 * Returns the value of a setting from the web-adjustable admin config settings.
2516
 *
2517
 * WARNING true/false are stored as string, so when comparing you need to check e.g.
2518
 * if (api_get_setting('show_navigation_menu') == 'true') //CORRECT
2519
 * instead of
2520
 * if (api_get_setting('show_navigation_menu') == true) //INCORRECT
2521
 * @param string    $variable The variable name
2522
 * @param string    $key The subkey (sub-variable) if any. Defaults to NULL
2523
 * @return string
2524
 * @author René Haentjens
2525
 * @author Bart Mollet
2526
 */
2527
function api_get_setting($variable, $key = null)
2528
{
2529
    global $_setting;
2530
    if ($variable == 'header_extra_content') {
2531
        $filename = api_get_home_path().'header_extra_content.txt';
2532
        if (file_exists($filename)) {
2533
            $value = file_get_contents($filename);
2534
            return $value;
2535
        } else {
2536
            return '';
2537
        }
2538
    }
2539
    if ($variable == 'footer_extra_content') {
2540
        $filename = api_get_home_path().'footer_extra_content.txt';
2541
        if (file_exists($filename)) {
2542
            $value = file_get_contents($filename);
2543
            return $value;
2544
        } else {
2545
            return '';
2546
        }
2547
    }
2548
    $value = null;
2549
    if (is_null($key)) {
2550
        $value = ((isset($_setting[$variable]) && $_setting[$variable] != '') ? $_setting[$variable] : null);
2551
    } else {
2552
        if (isset($_setting[$variable][$key])) {
2553
            $value = $_setting[$variable][$key];
2554
        }
2555
    }
2556
2557
    return $value;
2558
}
2559
2560
/**
2561
 * @param string $plugin
2562
 * @param string $variable
2563
 * @return string
2564
 */
2565
function api_get_plugin_setting($plugin, $variable)
2566
{
2567
    $variableName = $plugin.'_'.$variable;
2568
    $result = api_get_setting($variableName);
2569
2570
    if (isset($result[$plugin])) {
2571
        $value = $result[$plugin];
2572
        if (@unserialize($value) !== false) {
2573
            $value = unserialize($value);
2574
        }
2575
        return $value;
2576
    }
2577
2578
    return null;
2579
}
2580
2581
/**
2582
 * Returns the value of a setting from the web-adjustable admin config settings.
2583
 **/
2584
function api_get_settings_params($params)
2585
{
2586
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2587
    $result = Database::select('*', $table, ['where' => $params]);
2588
    return $result;
2589
}
2590
2591
function api_get_settings_params_simple($params)
2592
{
2593
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2594
    $result = Database::select('*', $table, ['where' => $params], 'one');
2595
    return $result;
2596
}
2597
2598
/**
2599
 * Returns the value of a setting from the web-adjustable admin config settings.
2600
 **/
2601
function api_delete_settings_params($params)
2602
{
2603
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2604
    $result = Database::delete($table, $params);
2605
    return $result;
2606
}
2607
2608
/**
2609
 * Returns an escaped version of $_SERVER['PHP_SELF'] to avoid XSS injection
2610
 * @return string   Escaped version of $_SERVER['PHP_SELF']
2611
 */
2612
function api_get_self()
2613
{
2614
    return htmlentities($_SERVER['PHP_SELF']);
2615
}
2616
2617
/* USER PERMISSIONS */
2618
2619
/**
2620
 * Checks whether current user is a platform administrator
2621
 * @param boolean $allowSessionAdmins Whether session admins should be considered admins or not
2622
 * @param boolean $allowDrh Whether HR directors should be considered admins or not
2623
 * @return boolean True if the user has platform admin rights,
2624
 * false otherwise.
2625
 * @see usermanager::is_admin(user_id) for a user-id specific function
2626
 */
2627
function api_is_platform_admin($allowSessionAdmins = false, $allowDrh = false)
2628
{
2629
    $isAdmin = Session::read('is_platformAdmin');
2630
    if ($isAdmin) {
2631
        return true;
2632
    }
2633
    $user = api_get_user_info();
2634
    return
2635
        isset($user['status']) &&
2636
        (
2637
            ($allowSessionAdmins && $user['status'] == SESSIONADMIN) ||
2638
            ($allowDrh && $user['status'] == DRH)
2639
        );
2640
}
2641
2642
/**
2643
 * Checks whether the user given as user id is in the admin table.
2644
 * @param int $user_id If none provided, will use current user
2645
 * @param int $url URL ID. If provided, also check if the user is active on given URL
2646
 * @return bool True if the user is admin, false otherwise
2647
 */
2648
function api_is_platform_admin_by_id($user_id = null, $url = null)
2649
{
2650
    $user_id = intval($user_id);
2651
    if (empty($user_id)) {
2652
        $user_id = api_get_user_id();
2653
    }
2654
    $admin_table = Database::get_main_table(TABLE_MAIN_ADMIN);
2655
    $sql = "SELECT * FROM $admin_table WHERE user_id = $user_id";
2656
    $res = Database::query($sql);
2657
    $is_admin = Database::num_rows($res) === 1;
2658
    if (!$is_admin || !isset($url)) {
2659
        return $is_admin;
2660
    }
2661
    // We get here only if $url is set
2662
    $url = intval($url);
2663
    $url_user_table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
2664
    $sql = "SELECT * FROM $url_user_table
2665
            WHERE access_url_id = $url AND user_id = $user_id";
2666
    $res = Database::query($sql);
2667
    $result = Database::num_rows($res) === 1;
2668
2669
    return $result;
2670
}
2671
2672
/**
2673
 * Returns the user's numeric status ID from the users table
2674
 * @param int $user_id If none provided, will use current user
2675
 * @return int User's status (1 for teacher, 5 for student, etc)
2676
 */
2677
function api_get_user_status($user_id = null)
2678
{
2679
    $user_id = intval($user_id);
2680
    if (empty($user_id)) {
2681
        $user_id = api_get_user_id();
2682
    }
2683
    $table = Database::get_main_table(TABLE_MAIN_USER);
2684
    $sql = "SELECT status FROM $table WHERE user_id = $user_id ";
2685
    $result = Database::query($sql);
2686
    $status = null;
2687
    if (Database::num_rows($result)) {
2688
        $row = Database::fetch_array($result);
2689
        $status = $row['status'];
2690
    }
2691
    return $status;
2692
}
2693
2694
/**
2695
 * Checks whether current user is allowed to create courses
2696
 * @return boolean True if the user has course creation rights,
2697
 * false otherwise.
2698
 */
2699
function api_is_allowed_to_create_course()
2700
{
2701
    if (api_is_platform_admin()) {
2702
        return true;
2703
    }
2704
2705
    // Teachers can only create courses
2706
    if (api_is_teacher()) {
2707
        if (api_get_setting('allow_users_to_create_courses') === 'true') {
2708
            return true;
2709
        } else {
2710
            return false;
2711
        }
2712
    }
2713
2714
    return Session::read('is_allowedCreateCourse');
2715
}
2716
2717
/**
2718
 * Checks whether the current user is a course administrator
2719
 * @return boolean True if current user is a course administrator
2720
 */
2721
function api_is_course_admin()
2722
{
2723
    if (api_is_platform_admin()) {
2724
        return true;
2725
    }
2726
    return Session::read('is_courseAdmin');
2727
}
2728
2729
/**
2730
 * Checks whether the current user is a course coach
2731
 * Based on the presence of user in session.id_coach (session general coach)
2732
 * @return bool True if current user is a course coach
2733
 */
2734
function api_is_session_general_coach()
2735
{
2736
    return Session::read('is_session_general_coach');
2737
}
2738
2739
/**
2740
 * Checks whether the current user is a course tutor
2741
 * Based on the presence of user in session_rel_course_rel_user.user_id with status = 2
2742
 * @return bool     True if current user is a course tutor
2743
 */
2744
function api_is_course_tutor()
2745
{
2746
    return Session::read('is_courseTutor');
2747
}
2748
2749
/**
2750
 * @param int $user_id
2751
 * @param int $courseId
2752
 * @param int $session_id
2753
 * @return bool
2754
 */
2755
function api_is_course_session_coach($user_id, $courseId, $session_id)
2756
{
2757
    $session_table = Database::get_main_table(TABLE_MAIN_SESSION);
2758
    $session_rel_course_rel_user_table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2759
2760
    $user_id = intval($user_id);
2761
    $session_id = intval($session_id);
2762
    $courseId = intval($courseId);
2763
2764
    $sql = "SELECT DISTINCT session.id
2765
            FROM $session_table
2766
            INNER JOIN $session_rel_course_rel_user_table session_rc_ru
2767
            ON session.id = session_rc_ru.session_id
2768
            WHERE
2769
                session_rc_ru.user_id = '".$user_id."'  AND
2770
                session_rc_ru.c_id = '$courseId' AND
2771
                session_rc_ru.status = 2 AND
2772
                session_rc_ru.session_id = '$session_id'";
2773
    $result = Database::query($sql);
2774
2775
    return Database::num_rows($result) > 0;
2776
}
2777
2778
/**
2779
 * Checks whether the current user is a course or session coach
2780
 * @param int $session_id
2781
 * @param int $courseId
2782
 * @param bool  Check whether we are in student view and, if we are, return false
2783
 * @return boolean True if current user is a course or session coach
2784
 */
2785
function api_is_coach($session_id = 0, $courseId = null, $check_student_view = true)
2786
{
2787
    $userId = api_get_user_id();
2788
2789
    if (!empty($session_id)) {
2790
        $session_id = intval($session_id);
2791
    } else {
2792
        $session_id = api_get_session_id();
2793
    }
2794
2795
    // The student preview was on
2796
    if ($check_student_view && api_is_student_view_active()) {
2797
        return false;
2798
    }
2799
2800
    if (!empty($courseId)) {
2801
        $courseId = intval($courseId);
2802
    } else {
2803
        $courseId = api_get_course_int_id();
2804
    }
2805
2806
    $session_table = Database::get_main_table(TABLE_MAIN_SESSION);
2807
    $session_rel_course_rel_user_table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2808
    $sessionIsCoach = null;
2809
2810
    if (!empty($courseId)) {
2811
        $sql = "SELECT DISTINCT s.id, name, access_start_date, access_end_date
2812
                FROM $session_table s
2813
                INNER JOIN $session_rel_course_rel_user_table session_rc_ru
2814
                ON session_rc_ru.session_id = s.id AND session_rc_ru.user_id = '".$userId."'
2815
                WHERE
2816
                    session_rc_ru.c_id = '$courseId' AND
2817
                    session_rc_ru.status = 2 AND
2818
                    session_rc_ru.session_id = '$session_id'";
2819
        $result = Database::query($sql);
2820
        $sessionIsCoach = Database::store_result($result);
2821
    }
2822
2823
    if (!empty($session_id)) {
2824
        $sql = "SELECT DISTINCT id, name, access_start_date, access_end_date
2825
                FROM $session_table
2826
                WHERE session.id_coach = $userId AND id = $session_id
2827
                ORDER BY access_start_date, access_end_date, name";
2828
        $result = Database::query($sql);
2829
        if (!empty($sessionIsCoach)) {
2830
            $sessionIsCoach = array_merge(
2831
                $sessionIsCoach,
2832
                Database::store_result($result)
2833
            );
2834
        } else {
2835
            $sessionIsCoach = Database::store_result($result);
2836
        }
2837
    }
2838
2839
    return count($sessionIsCoach) > 0;
2840
}
2841
2842
/**
2843
 * Checks whether the current user is a session administrator
2844
 * @return boolean True if current user is a course administrator
2845
 */
2846
function api_is_session_admin()
2847
{
2848
    $user = api_get_user_info();
2849
    return isset($user['status']) && $user['status'] == SESSIONADMIN;
2850
}
2851
2852
/**
2853
 * Checks whether the current user is a human resources manager
2854
 * @return boolean True if current user is a human resources manager
2855
 */
2856
function api_is_drh()
2857
{
2858
    $user = api_get_user_info();
2859
    return isset($user['status']) && $user['status'] == DRH;
2860
}
2861
2862
/**
2863
 * Checks whether the current user is a student
2864
 * @return boolean True if current user is a human resources manager
2865
 */
2866
function api_is_student()
2867
{
2868
    $user = api_get_user_info();
2869
    return isset($user['status']) && $user['status'] == STUDENT;
2870
}
2871
2872
/**
2873
 * Checks whether the current user has the status 'teacher'
2874
 * @return boolean True if current user is a human resources manager
2875
 */
2876
function api_is_teacher()
2877
{
2878
    $user = api_get_user_info();
2879
    return isset($user['status']) && $user['status'] == COURSEMANAGER;
2880
}
2881
2882
/**
2883
 * Checks whether the current user is a invited user
2884
 * @return boolean
2885
 */
2886
function api_is_invitee()
2887
{
2888
    $user = api_get_user_info();
2889
2890
    return isset($user['status']) && $user['status'] == INVITEE;
2891
}
2892
2893
/**
2894
 * This function checks whether a session is assigned into a category
2895
 * @param int       - session id
2896
 * @param string    - category name
2897
 * @return bool     - true if is found, otherwise false
2898
 */
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...
2899
function api_is_session_in_category($session_id, $category_name)
2900
{
2901
    $session_id = intval($session_id);
2902
    $category_name = Database::escape_string($category_name);
2903
    $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
2904
    $tbl_session_category = Database::get_main_table(TABLE_MAIN_SESSION_CATEGORY);
2905
2906
    $sql = "SELECT 1
2907
            FROM $tbl_session
2908
            WHERE $session_id IN (
2909
                SELECT s.id FROM $tbl_session s, $tbl_session_category sc
2910
                WHERE
2911
                  s.session_category_id = sc.id AND
2912
                  sc.name LIKE '%$category_name'
2913
            )";
2914
    $rs = Database::query($sql);
2915
2916
    if (Database::num_rows($rs) > 0) {
2917
        return true;
2918
    } else {
2919
        return false;
2920
    }
2921
}
2922
2923
/**
2924
 * Displays the title of a tool.
2925
 * Normal use: parameter is a string:
2926
 * api_display_tool_title("My Tool")
2927
 *
2928
 * Optionally, there can be a subtitle below
2929
 * the normal title, and / or a supra title above the normal title.
2930
 *
2931
 * e.g. supra title:
2932
 * group
2933
 * GROUP PROPERTIES
2934
 *
2935
 * e.g. subtitle:
2936
 * AGENDA
2937
 * calender & events tool
2938
 *
2939
 * @author Hugues Peeters <[email protected]>
2940
 * @param  mixed $title_element - it could either be a string or an array
2941
 *                               containing 'supraTitle', 'mainTitle',
2942
 *                               'subTitle'
2943
 * @return void
2944
 */
2945
function api_display_tool_title($title_element)
2946
{
2947
    if (is_string($title_element)) {
2948
        $tit = $title_element;
2949
        unset($title_element);
2950
        $title_element['mainTitle'] = $tit;
2951
    }
2952
    echo '<h3>';
2953
    if (!empty($title_element['supraTitle'])) {
2954
        echo '<small>'.$title_element['supraTitle'].'</small><br />';
2955
    }
2956
    if (!empty($title_element['mainTitle'])) {
2957
        echo $title_element['mainTitle'];
2958
    }
2959
    if (!empty($title_element['subTitle'])) {
2960
        echo '<br /><small>'.$title_element['subTitle'].'</small>';
2961
    }
2962
    echo '</h3>';
2963
}
2964
2965
/**
2966
 * Displays options for switching between student view and course manager view
2967
 *
2968
 * Changes in version 1.2 (Patrick Cool)
2969
 * Student view switch now behaves as a real switch. It maintains its current state until the state
2970
 * is changed explicitly
2971
 *
2972
 * Changes in version 1.1 (Patrick Cool)
2973
 * student view now works correctly in subfolders of the document tool
2974
 * student view works correctly in the new links tool
2975
 *
2976
 * Example code for using this in your tools:
2977
 * //if ($is_courseAdmin && api_get_setting('student_view_enabled') == 'true') {
2978
 * //   display_tool_view_option($isStudentView);
2979
 * //}
2980
 * //and in later sections, use api_is_allowed_to_edit()
2981
 *
2982
 * @author Roan Embrechts
2983
 * @author Patrick Cool
2984
 * @author Julio Montoya, changes added in Chamilo
2985
 * @version 1.2
2986
 * @todo rewrite code so it is easier to understand
2987
 */
2988
function api_display_tool_view_option()
2989
{
2990
    if (api_get_setting('student_view_enabled') != 'true') {
2991
        return '';
2992
    }
2993
2994
    $sourceurl = '';
2995
    $is_framed = false;
2996
    // Exceptions apply for all multi-frames pages
2997
    if (strpos($_SERVER['REQUEST_URI'], 'chat/chat_banner.php') !== false) {
2998
        // The chat is a multiframe bit that doesn't work too well with the student_view, so do not show the link
2999
        return '';
3000
    }
3001
3002
    // Uncomment to remove student view link from document view page
3003
    if (strpos($_SERVER['REQUEST_URI'], 'lp/lp_header.php') !== false) {
3004
        if (empty($_GET['lp_id'])) {
3005
            return '';
3006
        }
3007
        $sourceurl = substr($_SERVER['REQUEST_URI'], 0, strpos($_SERVER['REQUEST_URI'], '?'));
3008
        $sourceurl = str_replace(
3009
            'lp/lp_header.php',
3010
            'lp/lp_controller.php?'.api_get_cidreq().'&action=view&lp_id='.intval($_GET['lp_id']).'&isStudentView='.($_SESSION['studentview'] == 'studentview' ? 'false' : 'true'),
3011
            $sourceurl
3012
        );
3013
        //showinframes doesn't handle student view anyway...
3014
        //return '';
3015
        $is_framed = true;
3016
    }
3017
3018
    // Check whether the $_SERVER['REQUEST_URI'] contains already url parameters (thus a questionmark)
3019
    if (!$is_framed) {
3020
        if (strpos($_SERVER['REQUEST_URI'], '?') === false) {
3021
            $sourceurl = api_get_self().'?'.api_get_cidreq();
3022
        } else {
3023
            $sourceurl = $_SERVER['REQUEST_URI'];
3024
        }
3025
    }
3026
3027
    $output_string = '';
3028
    if (!empty($_SESSION['studentview'])) {
3029
        if ($_SESSION['studentview'] == 'studentview') {
3030
            // We have to remove the isStudentView=true from the $sourceurl
3031
            $sourceurl = str_replace('&isStudentView=true', '', $sourceurl);
3032
            $sourceurl = str_replace('&isStudentView=false', '', $sourceurl);
3033
            $output_string .= '<a class="btn btn-primary btn-sm" href="'.$sourceurl.'&isStudentView=false" target="_self">'.
3034
                Display::returnFontAwesomeIcon('eye').' '.get_lang('SwitchToTeacherView').'</a>';
3035
        } elseif ($_SESSION['studentview'] == 'teacherview') {
3036
            // Switching to teacherview
3037
            $sourceurl = str_replace('&isStudentView=true', '', $sourceurl);
3038
            $sourceurl = str_replace('&isStudentView=false', '', $sourceurl);
3039
            $output_string .= '<a class="btn btn-default btn-sm" href="'.$sourceurl.'&isStudentView=true" target="_self">'.
3040
                Display::returnFontAwesomeIcon('eye').' '.get_lang('SwitchToStudentView').'</a>';
3041
        }
3042
    } else {
3043
        $output_string .= '<a class="btn btn-default btn-sm" href="'.$sourceurl.'&isStudentView=true" target="_self">'.
3044
            Display::returnFontAwesomeIcon('eye').' '.get_lang('SwitchToStudentView').'</a>';
3045
    }
3046
    $html = Display::tag('div', $output_string, ['class'=>'view-options']);
3047
    return $html;
3048
}
3049
3050
// TODO: This is for the permission section.
3051
/**
3052
 * Function that removes the need to directly use is_courseAdmin global in
3053
 * tool scripts. It returns true or false depending on the user's rights in
3054
 * this particular course.
3055
 * Optionally checking for tutor and coach roles here allows us to use the
3056
 * student_view feature altogether with these roles as well.
3057
 * @param bool  Whether to check if the user has the tutor role
3058
 * @param bool  Whether to check if the user has the coach role
3059
 * @param bool  Whether to check if the user has the session coach role
3060
 * @param bool  check the student view or not
3061
 *
3062
 * @author Roan Embrechts
3063
 * @author Patrick Cool
3064
 * @author Julio Montoya
3065
 * @version 1.1, February 2004
3066
 * @return boolean true: the user has the rights to edit, false: he does not
3067
 */
3068
3069
function api_is_allowed_to_edit(
3070
    $tutor = false,
3071
    $coach = false,
3072
    $session_coach = false,
3073
    $check_student_view = true
3074
) {
3075
    $sessionId = api_get_session_id();
3076
    $is_allowed_coach_to_edit = api_is_coach(null, null, $check_student_view);
3077
    $session_visibility = api_get_session_visibility($sessionId);
3078
3079
    // Admins can edit anything.
3080
    if (api_is_platform_admin(false)) {
3081
        //The student preview was on
3082
        if ($check_student_view && api_is_student_view_active()) {
3083
            return false;
3084
        } else {
3085
            return true;
3086
        }
3087
    }
3088
3089
    $is_courseAdmin = api_is_course_admin();
3090
3091
    if (!$is_courseAdmin && $tutor) {
3092
        // If we also want to check if the user is a tutor...
3093
        $is_courseAdmin = $is_courseAdmin || api_is_course_tutor();
3094
    }
3095
3096
    if (!$is_courseAdmin && $coach) {
3097
        // If we also want to check if the user is a coach...';
3098
        // Check if session visibility is read only for coaches.
3099
        if ($session_visibility == SESSION_VISIBLE_READ_ONLY) {
3100
            $is_allowed_coach_to_edit = false;
3101
        }
3102
3103
        if (api_get_setting('allow_coach_to_edit_course_session') == 'true') {
3104
            // Check if coach is allowed to edit a course.
3105
            $is_courseAdmin = $is_courseAdmin || $is_allowed_coach_to_edit;
3106
        }
3107
    }
3108
3109
    if (!$is_courseAdmin && $session_coach) {
3110
        $is_courseAdmin = $is_courseAdmin || $is_allowed_coach_to_edit;
3111
    }
3112
3113
    // Check if the student_view is enabled, and if so, if it is activated.
3114
    if (api_get_setting('student_view_enabled') == 'true') {
3115
        if (!empty($sessionId)) {
3116
            // Check if session visibility is read only for coaches.
3117
            if ($session_visibility == SESSION_VISIBLE_READ_ONLY) {
3118
                $is_allowed_coach_to_edit = false;
3119
            }
3120
3121
            if (api_get_setting('allow_coach_to_edit_course_session') == 'true') {
3122
                // Check if coach is allowed to edit a course.
3123
                $is_allowed = $is_allowed_coach_to_edit;
3124
            } else {
3125
                $is_allowed = false;
3126
            }
3127
            if ($check_student_view) {
3128
                $is_allowed = $is_allowed && $_SESSION['studentview'] != 'studentview';
3129
            }
3130
        } else {
3131
            if ($check_student_view) {
3132
                $is_allowed = $is_courseAdmin && $_SESSION['studentview'] != 'studentview';
3133
            } else {
3134
                $is_allowed = $is_courseAdmin;
3135
            }
3136
        }
3137
3138
        return $is_allowed;
3139
    } else {
3140
        return $is_courseAdmin;
3141
    }
3142
}
3143
3144
/**
3145
 * Returns true if user is a course coach of at least one course in session
3146
 * @param int $sessionId
3147
 * @return bool
3148
 */
3149
function api_is_coach_of_course_in_session($sessionId)
3150
{
3151
    if (api_is_platform_admin()) {
3152
        return true;
3153
    }
3154
3155
    $userId = api_get_user_id();
3156
    $courseList = UserManager::get_courses_list_by_session(
3157
        $userId,
3158
        $sessionId
3159
    );
3160
3161
    // Session visibility.
3162
    $visibility = api_get_session_visibility(
3163
        $sessionId,
3164
        null,
3165
        false
3166
    );
3167
3168
    if ($visibility != SESSION_VISIBLE && !empty($courseList)) {
3169
        // Course Coach session visibility.
3170
        $blockedCourseCount = 0;
3171
        $closedVisibilityList = [
3172
            COURSE_VISIBILITY_CLOSED,
3173
            COURSE_VISIBILITY_HIDDEN
3174
        ];
3175
3176
        foreach ($courseList as $course) {
3177
            // Checking session visibility
3178
            $sessionCourseVisibility = api_get_session_visibility(
3179
                $sessionId,
3180
                $course['real_id']
3181
            );
3182
3183
            $courseIsVisible = !in_array(
3184
                $course['visibility'],
3185
                $closedVisibilityList
3186
            );
3187
            if ($courseIsVisible === false || $sessionCourseVisibility == SESSION_INVISIBLE) {
3188
                $blockedCourseCount++;
3189
            }
3190
        }
3191
3192
        // If all courses are blocked then no show in the list.
3193
        if ($blockedCourseCount === count($courseList)) {
3194
            $visibility = SESSION_INVISIBLE;
3195
        } else {
3196
            $visibility = SESSION_VISIBLE;
3197
        }
3198
    }
3199
3200
    switch ($visibility) {
3201
        case SESSION_VISIBLE_READ_ONLY:
3202
        case SESSION_VISIBLE:
3203
        case SESSION_AVAILABLE:
3204
            return true;
3205
            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...
3206
        case SESSION_INVISIBLE:
3207
            return false;
3208
    }
3209
3210
    return false;
3211
}
3212
3213
/**
3214
 * Checks if a student can edit contents in a session depending
3215
 * on the session visibility
3216
 * @param bool $tutor  Whether to check if the user has the tutor role
3217
 * @param bool  $coach Whether to check if the user has the coach role
3218
 * @return boolean true: the user has the rights to edit, false: he does not
3219
 */
3220
function api_is_allowed_to_session_edit($tutor = false, $coach = false)
3221
{
3222
    if (api_is_allowed_to_edit($tutor, $coach)) {
3223
        // If I'm a teacher, I will return true in order to not affect the normal behaviour of Chamilo tools.
3224
        return true;
3225
    } else {
3226
        $sessionId = api_get_session_id();
3227
3228
        if ($sessionId == 0) {
3229
            // I'm not in a session so i will return true to not affect the normal behaviour of Chamilo tools.
3230
            return true;
3231
        } else {
3232
            // I'm in a session and I'm a student
3233
            // Get the session visibility
3234
            $session_visibility = api_get_session_visibility($sessionId);
3235
            // if 5 the session is still available
3236
            //@todo We could load the session_rel_course_rel_user permission to increase the level of detail.
3237
            //echo api_get_user_id();
3238
            //echo api_get_course_id();
3239
3240
            switch ($session_visibility) {
3241
                case SESSION_VISIBLE_READ_ONLY: // 1
3242
                    return false;
3243
                case SESSION_VISIBLE:           // 2
3244
                    return true;
3245
                case SESSION_INVISIBLE:         // 3
3246
                    return false;
3247
                case SESSION_AVAILABLE:         //5
3248
                    return true;
3249
            }
3250
        }
3251
    }
3252
}
3253
3254
/**
3255
 * Checks whether the user is allowed in a specific tool for a specific action
3256
 * @param string $tool the tool we are checking if the user has a certain permission
3257
 * @param string $action the action we are checking (add, edit, delete, move, visibility)
3258
 * @return bool
3259
 * @author Patrick Cool <[email protected]>, Ghent University
3260
 * @author Julio Montoya
3261
 * @version 1.0
3262
 */
3263
function api_is_allowed($tool, $action, $task_id = 0)
3264
{
3265
    $_user = api_get_user_info();
3266
    $_course = api_get_course_info();
3267
3268
    if (api_is_course_admin()) {
3269
        return true;
3270
    }
3271
3272
    if (is_array($_course) and count($_course) > 0) {
3273
        require_once api_get_path(SYS_CODE_PATH).'permissions/permissions_functions.inc.php';
3274
3275
        // Getting the permissions of this user.
3276
        if ($task_id == 0) {
3277
            $user_permissions = get_permissions('user', $_user['user_id']);
3278
            $_SESSION['total_permissions'][$_course['code']] = $user_permissions;
3279
        }
3280
3281
        // Getting the permissions of the task.
3282
        if ($task_id != 0) {
3283
            $task_permissions = get_permissions('task', $task_id);
3284
            /* !!! */$_SESSION['total_permissions'][$_course['code']] = $task_permissions;
3285
        }
3286
        //print_r($_SESSION['total_permissions']);
3287
3288
        // Getting the permissions of the groups of the user
3289
        //$groups_of_user = GroupManager::get_group_ids($_course['db_name'], $_user['user_id']);
3290
3291
        //foreach($groups_of_user as $group)
3292
        //   $this_group_permissions = get_permissions('group', $group);
3293
3294
        // Getting the permissions of the courseroles of the user
3295
        $user_courserole_permissions = get_roles_permissions('user', $_user['user_id']);
3296
3297
        // Getting the permissions of the platformroles of the user
3298
        //$user_platformrole_permissions = get_roles_permissions('user', $_user['user_id'], ', platform');
3299
3300
        // Getting the permissions of the roles of the groups of the user
3301
        //foreach($groups_of_user as $group)
3302
        //    $this_group_courserole_permissions = get_roles_permissions('group', $group);
3303
3304
        // Getting the permissions of the platformroles of the groups of the user
3305
        //foreach($groups_of_user as $group)
3306
        //    $this_group_platformrole_permissions = get_roles_permissions('group', $group, 'platform');
3307
    }
3308
3309
    // If the permissions are limited, we have to map the extended ones to the limited ones.
3310
    if (api_get_setting('permissions') == 'limited') {
3311
        if ($action == 'Visibility') {
3312
            $action = 'Edit';
3313
        }
3314
        if ($action == 'Move') {
3315
            $action = 'Edit';
3316
        }
3317
    }
3318
3319
    // The session that contains all the permissions already exists for this course
3320
    // so there is no need to requery everything.
3321
    //my_print_r($_SESSION['total_permissions'][$_course['code']][$tool]);
3322
    if (is_array($_SESSION['total_permissions'][$_course['code']][$tool])) {
3323
        if (in_array($action, $_SESSION['total_permissions'][$_course['code']][$tool])) {
3324
            return true;
3325
        } else {
3326
            return false;
3327
        }
3328
    }
3329
}
3330
3331
/**
3332
 * Tells whether this user is an anonymous user
3333
 * @param int  $user_id      User ID (optional, will take session ID if not provided)
3334
 * @param bool $db_check     Whether to check in the database (true) or simply in
3335
 * the session (false) to see if the current user is the anonymous user
3336
 * @return bool     true if this user is anonymous, false otherwise
3337
 */
3338
function api_is_anonymous($user_id = null, $db_check = false)
3339
{
3340
    if (!isset($user_id)) {
3341
        $user_id = api_get_user_id();
3342
    }
3343
3344
    if ($db_check) {
3345
        $info = api_get_user_info($user_id);
3346
        if ($info['status'] == ANONYMOUS) {
3347
            return true;
3348
        }
3349
    }
3350
3351
    $_user = api_get_user_info();
3352
3353
    if (isset($_user['status']) && $_user['status'] == ANONYMOUS) {
3354
        //if ($_user['user_id'] == 0) {
3355
        // In some cases, api_set_anonymous doesn't seem to be triggered in local.inc.php. Make sure it is.
3356
        // Occurs in agenda for admin links - YW
3357
        global $use_anonymous;
3358
        if (isset($use_anonymous) && $use_anonymous) {
3359
            api_set_anonymous();
3360
        }
3361
3362
        return true;
3363
    }
3364
3365
    return (isset($_user['is_anonymous']) && $_user['is_anonymous'] === true) || $_user === false;
3366
}
3367
3368
/**
3369
 * Displays message "You are not allowed here..." and exits the entire script.
3370
 * @param bool   $print_headers    Whether or not to print headers (default = false -> does not print them)
3371
 * @param string $message
3372
 */
3373
function api_not_allowed(
3374
    $print_headers = false,
3375
    $message = null
3376
) {
3377
    if (api_get_setting('sso_authentication') === 'true') {
3378
        global $osso;
3379
        if ($osso) {
3380
            $osso->logout();
3381
        }
3382
    }
3383
    $home_url = api_get_path(WEB_PATH);
3384
    $user_id = api_get_user_id();
3385
    $course = api_get_course_id();
3386
3387
    global $this_section;
3388
3389
    if (CustomPages::enabled() && !isset($user_id)) {
3390
        if (empty($user_id)) {
3391
            // Why the CustomPages::enabled() need to be to set the request_uri
3392
            $_SESSION['request_uri'] = $_SERVER['REQUEST_URI'];
3393
        }
3394
        CustomPages::display(CustomPages::INDEX_UNLOGGED);
3395
    }
3396
3397
    $origin = api_get_origin();
3398
3399
    $msg = null;
3400
    if (isset($message)) {
3401
        $msg = $message;
3402
    } else {
3403
        $msg = Display::return_message(
3404
            get_lang('NotAllowedClickBack').'
3405
            <script>function goBack(){window.history.back();}</script>',
3406
            'error',
3407
            false
3408
        );
3409
        $msg .= '<p class="text-center">
3410
             <a onclick="goBack();" class="btn btn-default" href="'.$home_url.'">'.get_lang('GoBack').'</a>
3411
             </p>';
3412
    }
3413
3414
    $msg = Display::div($msg, ['align'=>'center']);
3415
3416
    $show_headers = 0;
3417
    if ($print_headers && $origin != 'learnpath') {
3418
        $show_headers = 1;
3419
    }
3420
3421
    $tpl = new Template(null, $show_headers, $show_headers, false, true, false);
3422
    $tpl->assign('hide_login_link', 1);
3423
    $tpl->assign('content', $msg);
3424
3425
    if (($user_id != 0 && !api_is_anonymous()) &&
3426
        (!isset($course) || $course == -1) &&
3427
        empty($_GET['cidReq'])
3428
    ) {
3429
        // if the access is not authorized and there is some login information
3430
        // but the cidReq is not found, assume we are missing course data and send the user
3431
        // to the user_portal
3432
        $tpl->display_one_col_template();
3433
        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...
3434
    }
3435
3436
    if (!empty($_SERVER['REQUEST_URI']) &&
3437
        (
3438
            !empty($_GET['cidReq']) ||
3439
            $this_section == SECTION_MYPROFILE ||
3440
            $this_section == SECTION_PLATFORM_ADMIN
3441
        )
3442
    ) {
3443
        $courseCode = api_get_course_id();
3444
        // Only display form and return to the previous URL if there was a course ID included
3445
        if ($user_id != 0 && !api_is_anonymous()) {
3446
            //if there is a user ID, then the user is not allowed but the session is still there. Say so and exit
3447
            $tpl->assign('content', $msg);
3448
            $tpl->display_one_col_template();
3449
            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...
3450
        }
3451
3452
        if (!is_null($courseCode)) {
3453
            api_set_firstpage_parameter($courseCode);
3454
        }
3455
3456
        // If the user has no user ID, then his session has expired
3457
        $form = api_get_not_allowed_login_form();
3458
3459
        // see same text in auth/gotocourse.php and main_api.lib.php function api_not_allowed (above)
3460
        $content = Display::return_message(get_lang('NotAllowed'), 'error', false);
3461
3462
        if (!empty($courseCode)) {
3463
            $content .= '<h4>'.get_lang('LoginToGoToThisCourse').'</h4>';
3464
        }
3465
3466
        if (api_is_cas_activated()) {
3467
            $content .= Display::return_message(sprintf(get_lang('YouHaveAnInstitutionalAccount'), api_get_setting("Institution")), '', false);
3468
            $content .= Display::div(
3469
                "<br/><a href='".get_cas_direct_URL(api_get_course_id())."'>".sprintf(get_lang('LoginWithYourAccount'), api_get_setting("Institution"))."</a><br/><br/>",
3470
                ['align' => 'center']
3471
            );
3472
            $content .= Display::return_message(get_lang('YouDontHaveAnInstitutionAccount'));
3473
            $content .= "<p style='text-align:center'><a href='#' onclick='$(this).parent().next().toggle()'>".get_lang('LoginWithExternalAccount')."</a></p>";
3474
            $content .= "<div style='display:none;'>";
3475
        }
3476
        $content .= '<div class="well">';
3477
        $content .= $form->returnForm();
3478
        $content .= '</div>';
3479
        if (api_is_cas_activated()) {
3480
            $content .= "</div>";
3481
        }
3482
3483
        if (!empty($courseCode)) {
3484
            $content .= '<hr/><p style="text-align:center"><a href="'.$home_url.'">'.
3485
                get_lang('ReturnToCourseHomepage').'</a></p>';
3486
        } else {
3487
            $content .= '<hr/><p style="text-align:center"><a href="'.$home_url.'">'.
3488
                get_lang('BackHome').'</a></p>';
3489
        }
3490
3491
        $tpl->setLoginBodyClass();
3492
        $tpl->assign('content', $content);
3493
        $tpl->display_one_col_template();
3494
        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...
3495
    }
3496
3497
    if ($user_id != 0 && !api_is_anonymous()) {
3498
        $tpl->display_one_col_template();
3499
        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...
3500
    }
3501
3502
    $msg = null;
3503
    // The session is over and we were not in a course,
3504
    // or we try to get directly to a private course without being logged
3505
    $courseId = api_get_course_int_id();
3506
    if (!empty($courseId)) {
3507
        api_set_firstpage_parameter(api_get_course_id());
3508
        $tpl->setLoginBodyClass();
3509
3510
        // see same text in auth/gotocourse.php and main_api.lib.php function api_not_allowed (bellow)
3511
        $msg = Display::return_message(get_lang('NotAllowed'), 'error', false);
3512
        $msg .= '<h4>'.get_lang('LoginToGoToThisCourse').'</h4>';
3513
        $casEnabled = api_is_cas_activated();
3514
        if ($casEnabled) {
3515
            $msg .= Display::return_message(
3516
                sprintf(get_lang('YouHaveAnInstitutionalAccount'), api_get_setting("Institution")),
3517
                '',
3518
                false
3519
            );
3520
            $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']);
3521
            $msg .= Display::return_message(get_lang('YouDontHaveAnInstitutionAccount'));
3522
            $msg .= "<p style='text-align:center'><a href='#' onclick='$(this).parent().next().toggle()'>".get_lang('LoginWithExternalAccount')."</a></p>";
3523
            $msg .= "<div style='display:none;'>";
3524
        }
3525
        $form = api_get_not_allowed_login_form();
3526
        $msg .= '<div class="well">';
3527
        $msg .= $form->returnForm();
3528
        $msg .= '</div>';
3529
        if ($casEnabled) {
3530
            $msg .= "</div>";
3531
        }
3532
    } else {
3533
        // we were not in a course, return to home page
3534
        $msg = Display::return_message(
3535
            get_lang('NotAllowed'),
3536
            'error',
3537
            false
3538
        );
3539
3540
        $msg .= '<p class="text-center">
3541
                 <a class="btn btn-default" href="'.$home_url.'">'.get_lang('BackHome').'</a>
3542
                 </p>';
3543
3544
        if (!empty($message)) {
3545
            $msg = $message;
3546
        }
3547
3548
        if (api_is_anonymous()) {
3549
            $form = api_get_not_allowed_login_form();
3550
            $msg .= '<div class="well">';
3551
            $msg .= $form->returnForm();
3552
            $msg .= '</div>';
3553
        }
3554
    }
3555
3556
    $tpl->assign('content', $msg);
3557
    $tpl->display_one_col_template();
3558
    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...
3559
}
3560
3561
/**
3562
 * @return FormValidator
3563
 */
3564
function api_get_not_allowed_login_form()
3565
{
3566
    $action = api_get_self().'?'.Security::remove_XSS($_SERVER['QUERY_STRING']);
3567
    $action = str_replace('&amp;', '&', $action);
3568
    Session::write('redirect_after_not_allow_page', $action);
3569
    $action .= '&redirect_after_not_allow_page=1';
3570
3571
    $form = new FormValidator(
3572
        'formLogin',
3573
        'post',
3574
        $action,
3575
        null,
3576
        ['class' => 'form-stacked']
3577
    );
3578
    $params = [
3579
        'placeholder' => get_lang('UserName'),
3580
        'class' => 'col-md-3'
3581
    ];
3582
    if (api_browser_support('autocapitalize')) {
3583
        $params['autocapitalize'] = 'none';
3584
    }
3585
3586
    $form->addElement(
3587
        'text',
3588
        'login',
3589
        null,
3590
        $params
3591
    );
3592
    $form->addElement(
3593
        'password',
3594
        'password',
3595
        null,
3596
        ['placeholder' => get_lang('Password'), 'class' => 'col-md-3']
3597
    ); //new
3598
    $form->addButtonNext(get_lang('LoginEnter'), 'submitAuth');
3599
3600
    return $form;
3601
}
3602
3603
/**
3604
 * Gets a UNIX timestamp from a database (MySQL) datetime format string
3605
 * @param $last_post_datetime standard output date in a sql query
3606
 * @return integer timestamp
3607
 * @author Toon Van Hoecke <[email protected]>
3608
 * @version October 2003
3609
 * @desc convert sql date to unix timestamp
3610
 */
3611
function convert_sql_date($last_post_datetime)
3612
{
3613
    list($last_post_date, $last_post_time) = explode(' ', $last_post_datetime);
3614
    list($year, $month, $day) = explode('-', $last_post_date);
3615
    list($hour, $min, $sec) = explode(':', $last_post_time);
3616
    return mktime((int) $hour, (int) $min, (int) $sec, (int) $month, (int) $day, (int) $year);
3617
}
3618
3619
/**
3620
 * Gets item visibility from the item_property table
3621
 *
3622
 * Getting the visibility is done by getting the last updated visibility entry,
3623
 * using the largest session ID found if session 0 and another was found (meaning
3624
 * the only one that is actually from the session, in case there are results from
3625
 * session 0 *AND* session n).
3626
 * @param array     Course properties array (result of api_get_course_info())
3627
 * @param string    Tool (learnpath, document, etc)
3628
 * @param int       The item ID in the given tool
3629
 * @param int       The session ID (optional)
3630
 * @param string $tool
3631
 * @param integer $user_id
3632
 * @param string $type
3633
 * @return int      -1 on error, 0 if invisible, 1 if visible
3634
 */
3635
function api_get_item_visibility(
3636
    $_course,
3637
    $tool,
3638
    $id,
3639
    $session = 0,
3640
    $user_id = null,
3641
    $type = null,
3642
    $group_id = null
3643
) {
3644
    if (!is_array($_course) || count($_course) == 0 || empty($tool) || empty($id)) {
3645
        return -1;
3646
    }
3647
3648
    $tool = Database::escape_string($tool);
3649
    $id = intval($id);
3650
    $session = (int) $session;
3651
    $TABLE_ITEMPROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY);
3652
    $course_id = intval($_course['real_id']);
3653
3654
    $userCondition = '';
3655
    if (!empty($user_id)) {
3656
        $user_id = intval($user_id);
3657
        $userCondition = " AND to_user_id = $user_id ";
3658
    }
3659
3660
    $typeCondition = '';
3661
    if (!empty($type)) {
3662
        $type = Database::escape_string($type);
3663
        $typeCondition = " AND lastedit_type = '$type' ";
3664
    }
3665
3666
    $groupCondition = '';
3667
    if (!empty($group_id)) {
3668
        $group_id = intval($group_id);
3669
        $groupCondition = " AND to_group_id = '$group_id' ";
3670
    }
3671
3672
    $sql = "SELECT visibility
3673
            FROM $TABLE_ITEMPROPERTY
3674
            WHERE
3675
                c_id = $course_id AND
3676
                tool = '$tool' AND
3677
                ref = $id AND
3678
                (session_id = $session OR session_id = 0 OR session_id IS NULL)
3679
                $userCondition $typeCondition $groupCondition
3680
            ORDER BY session_id DESC, lastedit_date DESC
3681
            LIMIT 1";
3682
3683
    $res = Database::query($sql);
3684
    if ($res === false || Database::num_rows($res) == 0) {
3685
        return -1;
3686
    }
3687
    $row = Database::fetch_array($res);
3688
3689
    return $row['visibility'];
3690
}
3691
3692
/**
3693
 * Delete a row in the c_item_property table
3694
 *
3695
 * @param array $courseInfo
3696
 * @param string $tool
3697
 * @param int $itemId
3698
 * @param int $userId
3699
 * @param int $groupId group.iid
3700
 * @param int $sessionId
3701
 * @return false|null
3702
 */
3703
function api_item_property_delete(
3704
    $courseInfo,
3705
    $tool,
3706
    $itemId,
3707
    $userId,
3708
    $groupId = 0,
3709
    $sessionId = 0
3710
) {
3711
    if (empty($courseInfo)) {
3712
        return false;
3713
    }
3714
3715
    $courseId = intval($courseInfo['real_id']);
3716
3717
    if (empty($courseId) || empty($tool) || empty($itemId)) {
3718
        return false;
3719
    }
3720
3721
    $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
3722
    $tool = Database::escape_string($tool);
3723
    $itemId = intval($itemId);
3724
    $userId = intval($userId);
3725
    $groupId = intval($groupId);
3726
    $sessionId = intval($sessionId);
3727
3728
    $groupCondition = " AND to_group_id = $groupId ";
3729
    if (empty($groupId)) {
3730
        $groupCondition = " AND (to_group_id is NULL OR to_group_id = 0) ";
3731
    }
3732
3733
    $userCondition = " AND to_user_id = $userId ";
3734
    if (empty($userId)) {
3735
        $userCondition = " AND (to_user_id is NULL OR to_user_id = 0) ";
3736
    }
3737
    $sessionCondition = api_get_session_condition($sessionId, true, false, 'session_id');
3738
    $sql = "DELETE FROM $table
3739
            WHERE
3740
                c_id = $courseId AND
3741
                tool  = '$tool' AND
3742
                ref = $itemId
3743
                $sessionCondition
3744
                $userCondition
3745
                $groupCondition
3746
            ";
3747
3748
    Database::query($sql);
3749
}
3750
3751
/**
3752
 * Updates or adds item properties to the Item_propetry table
3753
 * Tool and lastedit_type are language independant strings (langvars->get_lang!)
3754
 *
3755
 * @param array $_course array with course properties
3756
 * @param string $tool tool id, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
3757
 * @param int $item_id id of the item itself, linked to key of every tool ('id', ...)
3758
 * @param string $last_edit_type add or update action
3759
 * (1) message to be translated (in trad4all) : e.g. DocumentAdded, DocumentUpdated;
3760
 * (2) "delete"
3761
 * (3) "visible"
3762
 * (4) "invisible"
3763
 * @param int $user_id id of the editing/adding user
3764
 * @param array $groupInfo must include group.iid/group.od
3765
 * @param int $to_user_id id of the intended user (always has priority over $to_group_id !), only relevant for $type (1)
3766
 * @param string $start_visible 0000-00-00 00:00:00 format
3767
 * @param string $end_visible 0000-00-00 00:00:00 format
3768
 * @param int $session_id The session ID, if any, otherwise will default to 0
3769
 * @return boolean False if update fails.
3770
 * @author Toon Van Hoecke <[email protected]>, Ghent University
3771
 * @version January 2005
3772
 * @desc update the item_properties table (if entry not exists, insert) of the course
3773
 */
3774
function api_item_property_update(
3775
    $_course,
3776
    $tool,
3777
    $item_id,
3778
    $last_edit_type,
3779
    $user_id,
3780
    $groupInfo = [],
3781
    $to_user_id = null,
3782
    $start_visible = '',
3783
    $end_visible = '',
3784
    $session_id = 0
3785
) {
3786
    if (empty($_course)) {
3787
        return false;
3788
    }
3789
3790
    $course_id = $_course['real_id'];
3791
3792
    if (empty($course_id)) {
3793
        return false;
3794
    }
3795
3796
    $to_group_id = 0;
3797
    if (!empty($groupInfo) && isset($groupInfo['iid'])) {
3798
        $to_group_id = $groupInfo['iid'];
3799
    }
3800
3801
    $em = Database::getManager();
3802
3803
    // Definition of variables.
3804
    $tool = Database::escape_string($tool);
3805
    $item_id = intval($item_id);
3806
    $lastEditTypeNoFilter = $last_edit_type;
3807
    $last_edit_type = Database::escape_string($last_edit_type);
3808
    $user_id = intval($user_id);
3809
3810
    $startVisible = "NULL";
3811
    if (!empty($start_visible)) {
3812
        $start_visible = Database::escape_string($start_visible);
3813
        $startVisible = "'$start_visible'";
3814
    }
3815
3816
    $endVisible = "NULL";
3817
    if (!empty($end_visible)) {
3818
        $end_visible = Database::escape_string($end_visible);
3819
        $endVisible = "'$end_visible'";
3820
    }
3821
3822
    $to_filter = '';
3823
    $time = api_get_utc_datetime();
3824
3825
    if (!empty($session_id)) {
3826
        $session_id = intval($session_id);
3827
    } else {
3828
        $session_id = api_get_session_id();
3829
    }
3830
3831
    // Definition of tables.
3832
    $tableItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
3833
3834
    if ($to_user_id <= 0) {
3835
        $to_user_id = null; // No to_user_id set
3836
    }
3837
3838
    if (!is_null($to_user_id)) {
3839
        // $to_user_id has more priority than $to_group_id
3840
        $to_user_id = intval($to_user_id);
3841
        $to_field = 'to_user_id';
3842
        $to_value = $to_user_id;
3843
    } else {
3844
        // $to_user_id is not set.
3845
        $to_field = 'to_group_id';
3846
        $to_value = $to_group_id;
3847
    }
3848
3849
    $toValueCondition = empty($to_value) ? "NULL" : "'$to_value'";
3850
    // Set filters for $to_user_id and $to_group_id, with priority for $to_user_id
3851
    $condition_session = " AND session_id = $session_id ";
3852
    if (empty($session_id)) {
3853
        $condition_session = " AND (session_id = 0 OR session_id IS NULL) ";
3854
    }
3855
3856
    $filter = " c_id = $course_id AND tool = '$tool' AND ref = $item_id $condition_session ";
3857
3858
    // Check whether $to_user_id and $to_group_id are passed in the function call.
3859
    // If both are not passed (both are null) then it is a message for everybody and $to_group_id should be 0 !
3860
    if (is_null($to_user_id) && is_null($to_group_id)) {
3861
        $to_group_id = 0;
3862
    }
3863
3864
    if (!is_null($to_user_id)) {
3865
        // Set filter to intended user.
3866
        $to_filter = " AND to_user_id = $to_user_id $condition_session";
3867
    } else {
3868
        // Set filter to intended group.
3869
        if (($to_group_id != 0) && $to_group_id == strval(intval($to_group_id))) {
3870
            $to_filter = " AND to_group_id = $to_group_id $condition_session";
3871
        }
3872
    }
3873
3874
    // Adding filter if set.
3875
    $filter .= $to_filter;
3876
3877
    // Update if possible
3878
    $set_type = '';
3879
3880
    switch ($lastEditTypeNoFilter) {
3881
        case 'delete':
3882
            // delete = make item only visible for the platform admin.
3883
            $visibility = '2';
3884
            if (!empty($session_id)) {
3885
                // Check whether session id already exist into item_properties for updating visibility or add it.
3886
                $sql = "SELECT session_id FROM $tableItemProperty
3887
                        WHERE
3888
                            c_id = $course_id AND
3889
                            tool = '$tool' AND
3890
                            ref = $item_id AND
3891
                            session_id = $session_id";
3892
                $rs = Database::query($sql);
3893
                if (Database::num_rows($rs) > 0) {
3894
                    $sql = "UPDATE $tableItemProperty
3895
                            SET lastedit_type       = '".str_replace('_', '', ucwords($tool))."Deleted',
3896
                                lastedit_date       = '$time',
3897
                                lastedit_user_id    = $user_id,
3898
                                visibility          = $visibility,
3899
                                session_id          = $session_id $set_type
3900
                            WHERE $filter";
3901
                    $result = Database::query($sql);
3902
                } else {
3903
                    $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)
3904
                            VALUES ($course_id, '$tool',$item_id, '$time', $user_id, '$time', '$last_edit_type',$user_id, $toValueCondition, $visibility, $startVisible, $endVisible, $session_id)";
3905
                    $result = Database::query($sql);
3906
                    $id = Database::insert_id();
3907
                    if ($id) {
3908
                        $sql = "UPDATE $tableItemProperty SET id = iid WHERE iid = $id";
3909
                        Database::query($sql);
3910
                    }
3911
                }
3912
            } else {
3913
                $sql = "UPDATE $tableItemProperty
3914
                        SET
3915
                            lastedit_type='".str_replace('_', '', ucwords($tool))."Deleted',
3916
                            lastedit_date='$time',
3917
                            lastedit_user_id = $user_id,
3918
                            visibility = $visibility $set_type
3919
                        WHERE $filter";
3920
                $result = Database::query($sql);
3921
            }
3922
            break;
3923
        case 'visible': // Change item to visible.
3924
            $visibility = '1';
3925
            if (!empty($session_id)) {
3926
                // Check whether session id already exist into item_properties for updating visibility or add it.
3927
                $sql = "SELECT session_id FROM $tableItemProperty
3928
                        WHERE
3929
                            c_id = $course_id AND
3930
                            tool = '$tool' AND
3931
                            ref = $item_id AND
3932
                            session_id = $session_id";
3933
                $rs = Database::query($sql);
3934
                if (Database::num_rows($rs) > 0) {
3935
                    $sql = "UPDATE $tableItemProperty
3936
                            SET
3937
                                lastedit_type='".str_replace('_', '', ucwords($tool))."Visible',
3938
                                lastedit_date='$time',
3939
                                lastedit_user_id = $user_id,
3940
                                visibility = $visibility,
3941
                                session_id = $session_id $set_type
3942
                            WHERE $filter";
3943
                    $result = Database::query($sql);
3944
                } else {
3945
                    $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)
3946
                            VALUES ($course_id, '$tool', $item_id, '$time', $user_id, '$time', '$last_edit_type', $user_id, $toValueCondition, $visibility, $startVisible, $endVisible, $session_id)";
3947
                    $result = Database::query($sql);
3948
                    $id = Database::insert_id();
3949
                    if ($id) {
3950
                        $sql = "UPDATE $tableItemProperty SET id = iid WHERE iid = $id";
3951
                        Database::query($sql);
3952
                    }
3953
                }
3954
            } else {
3955
                $sql = "UPDATE $tableItemProperty
3956
                        SET
3957
                            lastedit_type='".str_replace('_', '', ucwords($tool))."Visible',
3958
                            lastedit_date='$time',
3959
                            lastedit_user_id = $user_id,
3960
                            visibility = $visibility $set_type
3961
                        WHERE $filter";
3962
                $result = Database::query($sql);
3963
            }
3964
            break;
3965
        case 'invisible': // Change item to invisible.
3966
            $visibility = '0';
3967
            if (!empty($session_id)) {
3968
                // Check whether session id already exist into item_properties for updating visibility or add it
3969
                $sql = "SELECT session_id FROM $tableItemProperty
3970
                        WHERE
3971
                            c_id = $course_id AND
3972
                            tool = '$tool' AND
3973
                            ref = $item_id AND
3974
                            session_id = $session_id";
3975
                $rs = Database::query($sql);
3976
                if (Database::num_rows($rs) > 0) {
3977
                    $sql = "UPDATE $tableItemProperty
3978
                            SET
3979
                                lastedit_type = '".str_replace('_', '', ucwords($tool))."Invisible',
3980
                                lastedit_date = '$time',
3981
                                lastedit_user_id = $user_id,
3982
                                visibility = $visibility,
3983
                                session_id = $session_id $set_type
3984
                            WHERE $filter";
3985
                    $result = Database::query($sql);
3986
                } else {
3987
                    $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)
3988
                            VALUES ($course_id, '$tool', $item_id, '$time', $user_id, '$time', '$last_edit_type', $user_id, $toValueCondition, $visibility, $startVisible, $endVisible, $session_id)";
3989
                    $result = Database::query($sql);
3990
                    $id = Database::insert_id();
3991
                    if ($id) {
3992
                        $sql = "UPDATE $tableItemProperty SET id = iid WHERE iid = $id";
3993
                        Database::query($sql);
3994
                    }
3995
                }
3996
            } else {
3997
                $sql = "UPDATE $tableItemProperty
3998
                        SET
3999
                            lastedit_type = '".str_replace('_', '', ucwords($tool))."Invisible',
4000
                            lastedit_date = '$time',
4001
                            lastedit_user_id = $user_id,
4002
                            visibility = $visibility $set_type
4003
                        WHERE $filter";
4004
                $result = Database::query($sql);
4005
            }
4006
            break;
4007
        default: // The item will be added or updated.
4008
            $set_type = ", lastedit_type = '$last_edit_type' ";
4009
            $visibility = '1';
4010
            //$filter .= $to_filter; already added
4011
            $sql = "UPDATE $tableItemProperty
4012
                    SET
4013
                      lastedit_date = '$time',
4014
                      lastedit_user_id = $user_id $set_type
4015
                    WHERE $filter";
4016
            $result = Database::query($sql);
4017
    }
4018
4019
    // Insert if no entries are found (can only happen in case of $last_edit_type switch is 'default').
4020
    if ($result == false || Database::affected_rows($result) == 0) {
4021
        $objCourse = $em->find('ChamiloCoreBundle:Course', intval($course_id));
4022
        $objTime = new DateTime('now', new DateTimeZone('UTC'));
4023
        $objUser = api_get_user_entity($user_id);
4024
        if (empty($objUser)) {
4025
            // Use anonymous
4026
            $user_id = api_get_anonymous_id();
4027
            $objUser = api_get_user_entity($user_id);
4028
        }
4029
        $objGroup = $em->find('ChamiloCourseBundle:CGroupInfo', intval($to_group_id));
4030
        $objToUser = api_get_user_entity($to_user_id);
4031
        $objSession = $em->find('ChamiloCoreBundle:Session', intval($session_id));
4032
4033
        $startVisibleDate = !empty($start_visible) ? new DateTime($start_visible, new DateTimeZone('UTC')) : null;
4034
        $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...
4035
4036
        $cItemProperty = new CItemProperty($objCourse);
4037
        $cItemProperty
4038
            ->setTool($tool)
4039
            ->setRef($item_id)
4040
            ->setInsertDate($objTime)
4041
            ->setInsertUser($objUser)
4042
            ->setLasteditDate($objTime)
4043
            ->setLasteditType($last_edit_type)
4044
            ->setGroup($objGroup)
4045
            ->setToUser($objToUser)
4046
            ->setVisibility($visibility)
4047
            ->setStartVisible($startVisibleDate)
4048
            ->setEndVisible($endVisibleDate)
4049
            ->setSession($objSession);
4050
4051
        $em->persist($cItemProperty);
4052
        $em->flush();
4053
4054
        $id = $cItemProperty->getIid();
4055
4056
        if ($id) {
4057
            $cItemProperty->setId($id);
4058
            $em->merge($cItemProperty);
4059
            $em->flush();
4060
4061
            return false;
4062
        }
4063
    }
4064
4065
    return true;
4066
}
4067
4068
/**
4069
 * Gets item property by tool
4070
 * @param string    course code
4071
 * @param string    tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4072
 * @param int       id of the item itself, linked to key of every tool ('id', ...), "*" = all items of the tool
4073
 * @param int $session_id
4074
 * @param string $tool
4075
 * @param string $course_code
4076
 * @return array All fields from c_item_property (all rows found) or empty array
4077
 */
4078
function api_get_item_property_by_tool($tool, $course_code, $session_id = null)
4079
{
4080
    $course_info = api_get_course_info($course_code);
4081
    $tool = Database::escape_string($tool);
4082
4083
    // Definition of tables.
4084
    $item_property_table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4085
    $session_id = intval($session_id);
4086
    $session_condition = ' AND session_id = '.$session_id;
4087
    if (empty($session_id)) {
4088
        $session_condition = " AND (session_id = 0 OR session_id IS NULL) ";
4089
    }
4090
    $course_id = $course_info['real_id'];
4091
4092
    $sql = "SELECT * FROM $item_property_table
4093
            WHERE
4094
                c_id = $course_id AND
4095
                tool = '$tool'
4096
                $session_condition ";
4097
    $rs = Database::query($sql);
4098
    $list = [];
4099
    if (Database::num_rows($rs) > 0) {
4100
        while ($row = Database::fetch_array($rs, 'ASSOC')) {
4101
            $list[] = $row;
4102
        }
4103
    }
4104
    return $list;
4105
}
4106
4107
/**
4108
 * Gets item property by tool and user
4109
 * @param int $userId
4110
 * @param int $tool
4111
 * @param int $courseId
4112
 * @param int $session_id
4113
 * @return array
4114
 */
4115
function api_get_item_property_list_by_tool_by_user(
4116
    $userId,
4117
    $tool,
4118
    $courseId,
4119
    $session_id = 0
4120
) {
4121
    $userId = intval($userId);
4122
    $tool = Database::escape_string($tool);
4123
    $session_id = intval($session_id);
4124
    $courseId = intval($courseId);
4125
4126
    // Definition of tables.
4127
    $item_property_table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4128
    $session_condition = ' AND session_id = '.$session_id;
4129
    if (empty($session_id)) {
4130
        $session_condition = " AND (session_id = 0 OR session_id IS NULL) ";
4131
    }
4132
    $sql = "SELECT * FROM $item_property_table
4133
            WHERE
4134
                insert_user_id = $userId AND
4135
                c_id = $courseId AND
4136
                tool = '$tool'
4137
                $session_condition ";
4138
4139
    $rs = Database::query($sql);
4140
    $list = [];
4141
    if (Database::num_rows($rs) > 0) {
4142
        while ($row = Database::fetch_array($rs, 'ASSOC')) {
4143
            $list[] = $row;
4144
        }
4145
    }
4146
4147
    return $list;
4148
}
4149
4150
/**
4151
 * Gets item property id from tool of a course
4152
 * @param string $course_code course code
4153
 * @param string $tool tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4154
 * @param int $ref id of the item itself, linked to key of every tool ('id', ...), "*" = all items of the tool
4155
 * @param int $sessionId Session ID (optional)
4156
 * @return int
4157
 */
4158
function api_get_item_property_id($course_code, $tool, $ref, $sessionId = 0)
4159
{
4160
    $course_info = api_get_course_info($course_code);
4161
    $tool = Database::escape_string($tool);
4162
    $ref = intval($ref);
4163
4164
    // Definition of tables.
4165
    $tableItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
4166
    $course_id = $course_info['real_id'];
4167
    $sessionId = (int) $sessionId;
4168
    $sessionCondition = " AND session_id = $sessionId ";
4169
    if (empty($sessionId)) {
4170
        $sessionCondition = " AND (session_id = 0 OR session_id IS NULL) ";
4171
    }
4172
    $sql = "SELECT id FROM $tableItemProperty
4173
            WHERE
4174
                c_id = $course_id AND
4175
                tool = '$tool' AND
4176
                ref = $ref
4177
                $sessionCondition";
4178
    $rs = Database::query($sql);
4179
    $item_property_id = '';
4180
    if (Database::num_rows($rs) > 0) {
4181
        $row = Database::fetch_array($rs);
4182
        $item_property_id = $row['id'];
4183
    }
4184
    return $item_property_id;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $item_property_id also could return the type string which is incompatible with the documented return type integer.
Loading history...
4185
}
4186
4187
/**
4188
 * Inserts a record in the track_e_item_property table (No update)
4189
 * @param string $tool
4190
 * @param int $ref
4191
 * @param string $title
4192
 * @param string $content
4193
 * @param int $progress
4194
 * @return bool|int
4195
 */
4196
function api_track_item_property_update($tool, $ref, $title, $content, $progress)
4197
{
4198
    $tbl_stats_item_property = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ITEM_PROPERTY);
4199
    $course_id = api_get_course_int_id(); //numeric
4200
    $course_code = api_get_course_id(); //alphanumeric
4201
    $item_property_id = api_get_item_property_id($course_code, $tool, $ref);
4202
    if (!empty($item_property_id)) {
4203
        $sql = "INSERT IGNORE INTO $tbl_stats_item_property SET
4204
                course_id           = '$course_id',
4205
                item_property_id    = '$item_property_id',
4206
                title               = '".Database::escape_string($title)."',
4207
                content             = '".Database::escape_string($content)."',
4208
                progress            = '".intval($progress)."',
4209
                lastedit_date       = '".api_get_utc_datetime()."',
4210
                lastedit_user_id    = '".api_get_user_id()."',
4211
                session_id          = '".api_get_session_id()."'";
4212
        $result = Database::query($sql);
4213
        $affected_rows = Database::affected_rows($result);
4214
4215
        return $affected_rows;
4216
    }
4217
4218
    return false;
4219
}
4220
4221
/**
4222
 * @param string $tool
4223
 * @param int $ref
4224
 * @return array|resource
4225
 */
4226
function api_get_track_item_property_history($tool, $ref)
4227
{
4228
    $tbl_stats_item_property = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ITEM_PROPERTY);
4229
    $course_id = api_get_course_int_id(); //numeric
4230
    $course_code = api_get_course_id(); //alphanumeric
4231
    $item_property_id = api_get_item_property_id($course_code, $tool, $ref);
4232
    $sql = "SELECT * FROM $tbl_stats_item_property
4233
            WHERE item_property_id = $item_property_id AND course_id = $course_id
4234
            ORDER BY lastedit_date DESC";
4235
    $result = Database::query($sql);
4236
    if ($result === false or $result === null) {
4237
        $result = [];
4238
    } else {
4239
        $result = Database::store_result($result, 'ASSOC');
4240
    }
4241
4242
    return $result;
4243
}
4244
4245
/**
4246
 * Gets item property data from tool of a course id
4247
 * @param int $course_id
4248
 * @param string $tool   tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4249
 * @param int $ref id of the item itself, linked to key of every tool ('id', ...), "*" = all items of the tool
4250
 * @param int $session_id
4251
 * @param int $groupId
4252
 *
4253
 * @return array with all fields from c_item_property, empty array if not found or false if course could not be found
4254
 */
4255
function api_get_item_property_info($course_id, $tool, $ref, $session_id = 0, $groupId = 0)
4256
{
4257
    $courseInfo = api_get_course_info_by_id($course_id);
4258
4259
    if (empty($courseInfo)) {
4260
        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...
4261
    }
4262
4263
    $tool = Database::escape_string($tool);
4264
    $ref = intval($ref);
4265
    $course_id = $courseInfo['real_id'];
4266
    $session_id = intval($session_id);
4267
4268
    $sessionCondition = " session_id = $session_id";
4269
    if (empty($session_id)) {
4270
        $sessionCondition = " (session_id = 0 OR session_id IS NULL) ";
4271
    }
4272
4273
    // Definition of tables.
4274
    $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4275
4276
    $sql = "SELECT * FROM $table
4277
            WHERE
4278
                c_id = $course_id AND
4279
                tool = '$tool' AND
4280
                ref = $ref AND
4281
                $sessionCondition ";
4282
4283
    if (!empty($groupId)) {
4284
        $groupId = intval($groupId);
4285
        $sql .= " AND to_group_id = $groupId ";
4286
    }
4287
4288
    $rs  = Database::query($sql);
4289
    $row = [];
4290
    if (Database::num_rows($rs) > 0) {
4291
        $row = Database::fetch_array($rs, 'ASSOC');
4292
    }
4293
4294
    return $row;
4295
}
4296
4297
/**
4298
 * Displays a combo box so the user can select his/her preferred language.
4299
 * @param string The desired name= value for the select
4300
 * @param bool Whether we use the JQuery Chozen library or not
4301
 * (in some cases, like the indexing language picker, it can alter the presentation)
4302
 * @return string
4303
 */
4304
function api_get_languages_combo($name = 'language')
4305
{
4306
    $ret = '';
4307
    $platformLanguage = api_get_setting('platformLanguage');
4308
4309
    // Retrieve a complete list of all the languages.
4310
    $language_list = api_get_languages();
4311
4312
    if (count($language_list['name']) < 2) {
4313
        return $ret;
4314
    }
4315
4316
    // The the current language of the user so that his/her language occurs as selected in the dropdown menu.
4317
    if (isset($_SESSION['user_language_choice'])) {
4318
        $default = $_SESSION['user_language_choice'];
4319
    } else {
4320
        $default = $platformLanguage;
4321
    }
4322
4323
    $languages = $language_list['name'];
4324
    $folder = $language_list['folder'];
4325
4326
    $ret .= '<select name="'.$name.'" id="language_chosen" class="selectpicker show-tick form-control">';
4327
    foreach ($languages as $key => $value) {
4328
        if ($folder[$key] == $default) {
4329
            $selected = ' selected="selected"';
4330
        } else {
4331
            $selected = '';
4332
        }
4333
        $ret .= sprintf('<option value=%s" %s>%s</option>', $folder[$key], $selected, $value);
4334
    }
4335
    $ret .= '</select>';
4336
4337
    return $ret;
4338
}
4339
4340
/**
4341
 * Displays a form (drop down menu) so the user can select his/her preferred language.
4342
 * The form works with or without javascript
4343
 * @param  boolean Hide form if only one language available (defaults to false = show the box anyway)
4344
 * @param bool $showAsButton
4345
 * @return null|string Display the box directly
4346
 */
4347
function api_display_language_form($hide_if_no_choice = false, $showAsButton = false)
4348
{
4349
    // Retrieve a complete list of all the languages.
4350
    $language_list = api_get_languages();
4351
    if (count($language_list['name']) <= 1 && $hide_if_no_choice) {
4352
        return; //don't show any form
4353
    }
4354
4355
    // The the current language of the user so that his/her language occurs as selected in the dropdown menu.
4356
    if (isset($_SESSION['user_language_choice'])) {
4357
        $user_selected_language = $_SESSION['user_language_choice'];
4358
    }
4359
    if (empty($user_selected_language)) {
4360
        $user_selected_language = api_get_setting('platformLanguage');
4361
    }
4362
4363
    $currentLanguageId = api_get_language_id($user_selected_language);
4364
    $currentLanguageInfo = api_get_language_info($currentLanguageId);
4365
    $countryCode = languageToCountryIsoCode($currentLanguageInfo['isocode']);
4366
    $url = api_get_self();
4367
    if ($showAsButton) {
4368
        $html = '<div class="btn-group">
4369
              <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
4370
                <span class="flag-icon flag-icon-'.$countryCode.'"></span>
4371
                '.$currentLanguageInfo['original_name'].'
4372
                <span class="caret">
4373
                </span>
4374
              </button>';
4375
    } else {
4376
        $html = '
4377
            <a href="'.$url.'" class="dropdown-toggle" data-toggle="dropdown" role="button">
4378
                <span class="flag-icon flag-icon-'.$countryCode.'"></span> 
4379
                '.$currentLanguageInfo['original_name'].'
4380
                <span class="caret"></span>
4381
            </a>
4382
            ';
4383
    }
4384
4385
    $html .= '<ul class="dropdown-menu" role="menu">';
4386
    foreach ($language_list['all'] as $key => $data) {
4387
        $urlLink = $url.'?language='.$data['english_name'];
4388
        $html .= '<li><a href="'.$urlLink.'"><span class="flag-icon flag-icon-'.languageToCountryIsoCode($data['isocode']).'"></span> '.$data['original_name'].'</a></li>';
4389
    }
4390
    $html .= '</ul>';
4391
4392
    if ($showAsButton) {
4393
        $html .= '</div>';
4394
    }
4395
4396
    return $html;
4397
}
4398
4399
/**
4400
 * @param string $languageIsoCode
4401
 * @return string
4402
 */
4403
function languageToCountryIsoCode($languageIsoCode)
4404
{
4405
    // @todo save in DB
4406
    switch ($languageIsoCode) {
4407
        case 'ko':
4408
            $country = 'kr';
4409
            break;
4410
        case 'ja':
4411
            $country = 'jp';
4412
            break;
4413
        case 'ca':
4414
            $country = 'es';
4415
            break;
4416
        case 'gl':
4417
            $country = 'es';
4418
            break;
4419
        case 'ka':
4420
            $country = 'ge';
4421
            break;
4422
        case 'sl':
4423
            $country = 'si';
4424
            break;
4425
        case 'eu':
4426
            $country = 'es';
4427
            break;
4428
        case 'cs':
4429
            $country = 'cz';
4430
            break;
4431
        case 'el':
4432
            $country = 'ae';
4433
            break;
4434
        case 'ar':
4435
            $country = 'ae';
4436
            break;
4437
        case 'en':
4438
            $country = 'gb';
4439
            break;
4440
        case 'he':
4441
            $country = 'il';
4442
            break;
4443
        case 'uk':
4444
            $country = 'ua'; //Ukraine
4445
            break;
4446
        case 'da':
4447
            $country = 'dk';
4448
            break;
4449
        case 'pt-BR':
4450
            $country = 'br';
4451
            break;
4452
        case 'qu':
4453
            $country = 'pe';
4454
            break;
4455
        case 'sv':
4456
            $country = 'se';
4457
            break;
4458
        case 'zh-TW':
4459
        case 'zh':
4460
            $country = 'cn';
4461
            break;
4462
        default:
4463
            $country = $languageIsoCode;
4464
            break;
4465
    }
4466
    $country = strtolower($country);
4467
    return $country;
4468
}
4469
4470
4471
/**
4472
 * Returns a list of all the languages that are made available by the admin.
4473
 * @return array An array with all languages. Structure of the array is
4474
 *  array['name'] = An array with the name of every language
4475
 *  array['folder'] = An array with the corresponding names of the language-folders in the filesystem
4476
 */
4477
function api_get_languages()
4478
{
4479
    $tbl_language = Database::get_main_table(TABLE_MAIN_LANGUAGE);
4480
    $sql = "SELECT * FROM $tbl_language WHERE available='1' 
4481
            ORDER BY original_name ASC";
4482
    $result = Database::query($sql);
4483
    $language_list = [];
4484
    while ($row = Database::fetch_array($result)) {
4485
        $language_list['name'][] = $row['original_name'];
4486
        $language_list['folder'][] = $row['dokeos_folder'];
4487
        $language_list['all'][] = $row;
4488
    }
4489
    return $language_list;
4490
}
4491
4492
/**
4493
 * Returns a list of all the languages that are made available by the admin.
4494
 * @return array
4495
 */
4496
function api_get_languages_to_array()
4497
{
4498
    $tbl_language = Database::get_main_table(TABLE_MAIN_LANGUAGE);
4499
    $sql = "SELECT * FROM $tbl_language WHERE available='1' ORDER BY original_name ASC";
4500
    $result = Database::query($sql);
4501
    $languages = [];
4502
    while ($row = Database::fetch_array($result)) {
4503
        $languages[$row['dokeos_folder']] = $row['original_name'];
4504
    }
4505
    return $languages;
4506
}
4507
4508
/**
4509
 * Returns the id (the database id) of a language
4510
 * @param   string  language name (the corresponding name of the language-folder in the filesystem)
4511
 * @return  int     id of the language
4512
 */
4513
function api_get_language_id($language)
4514
{
4515
    $tbl_language = Database::get_main_table(TABLE_MAIN_LANGUAGE);
4516
    if (empty($language)) {
4517
        return null;
4518
    }
4519
    $language = Database::escape_string($language);
4520
    $sql = "SELECT id FROM $tbl_language
4521
            WHERE dokeos_folder = '$language' LIMIT 1";
4522
    $result = Database::query($sql);
4523
    $row = Database::fetch_array($result);
4524
    return $row['id'];
4525
}
4526
4527
/**
4528
 * Gets language of the requested type for the current user. Types are :
4529
 * user_profil_lang : profile language of current user
4530
 * user_select_lang : language selected by user at login
4531
 * course_lang : language of the current course
4532
 * platform_lang : default platform language
4533
 * @param string $lang_type
4534
 * @return string
4535
 **/
4536
function api_get_language_from_type($lang_type)
4537
{
4538
    $return = false;
4539
    switch ($lang_type) {
4540
        case 'platform_lang':
4541
            $temp_lang = api_get_setting('platformLanguage');
4542
            if (!empty($temp_lang)) {
4543
                $return = $temp_lang;
4544
            }
4545
            break;
4546
        case 'user_profil_lang':
4547
            $_user = api_get_user_info();
4548
            if (isset($_user['language']) && !empty($_user['language'])) {
4549
                $return = $_user['language'];
4550
            }
4551
            break;
4552
        case 'user_selected_lang':
4553
            if (isset($_SESSION['user_language_choice']) && !empty($_SESSION['user_language_choice'])) {
4554
                $return = $_SESSION['user_language_choice'];
4555
            }
4556
            break;
4557
        case 'course_lang':
4558
            global $_course;
4559
            $cidReq = null;
4560
            if (empty($_course)) {
4561
                // Code modified because the local.inc.php file it's declarated after this work
4562
                // causing the function api_get_course_info() returns a null value
4563
                $cidReq = isset($_GET["cidReq"]) ? Database::escape_string($_GET["cidReq"]) : null;
4564
                $cDir = (!empty($_GET['cDir']) ? $_GET['cDir'] : null);
4565
                if (empty($cidReq) && !empty($cDir)) {
4566
                    $c = CourseManager::getCourseCodeFromDirectory($cDir);
4567
                    if ($c) {
4568
                        $cidReq = $c;
4569
                    }
4570
                }
4571
            }
4572
            $_course = api_get_course_info($cidReq);
4573
            if (isset($_course['language']) && !empty($_course['language'])) {
4574
                $return = $_course['language'];
4575
                $showCourseInUserLanguage = api_get_course_setting('show_course_in_user_language');
4576
                if ($showCourseInUserLanguage == 1) {
4577
                    $userInfo = api_get_user_info();
4578
                    if (isset($userInfo['language'])) {
4579
                        $return = $userInfo['language'];
4580
                    }
4581
                }
4582
            }
4583
            break;
4584
        default:
4585
            $return = false;
4586
            break;
4587
    }
4588
4589
    return $return;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $return could also return false which is incompatible with the documented return type string. 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...
4590
}
4591
4592
/**
4593
 * Get the language information by its id
4594
 * @param int $languageId
4595
 * @return array
4596
 */
4597
function api_get_language_info($languageId)
4598
{
4599
    $language = Database::getManager()
4600
        ->find('ChamiloCoreBundle:Language', intval($languageId));
4601
4602
    if (!$language) {
4603
        return [];
4604
    }
4605
4606
    return [
4607
        'id' => $language->getId(),
4608
        'original_name' => $language->getOriginalName(),
4609
        'english_name' => $language->getEnglishName(),
4610
        'isocode' => $language->getIsocode(),
4611
        'dokeos_folder' => $language->getDokeosFolder(),
4612
        'available' => $language->getAvailable(),
4613
        'parent_id' => $language->getParent() ? $language->getParent()->getId() : null
4614
    ];
4615
}
4616
4617
/**
4618
 * Returns the name of the visual (CSS) theme to be applied on the current page.
4619
 * The returned name depends on the platform, course or user -wide settings.
4620
 * @return string The visual theme's name, it is the name of a folder inside web/css/themes
4621
 */
4622
function api_get_visual_theme()
4623
{
4624
    static $visual_theme;
4625
    if (!isset($visual_theme)) {
4626
        // Get style directly from DB
4627
        $styleFromDatabase = api_get_settings_params_simple(
4628
            [
4629
                'variable = ? AND access_url = ?' => [
4630
                    'stylesheets',
4631
                    api_get_current_access_url_id(),
4632
                ],
4633
            ]
4634
        );
4635
        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...
4636
            $platform_theme = $styleFromDatabase['selected_value'];
4637
        } else {
4638
            $platform_theme = api_get_setting('stylesheets');
4639
        }
4640
4641
        // Platform's theme.
4642
        $visual_theme = $platform_theme;
4643
        if (api_get_setting('user_selected_theme') == 'true') {
4644
            $user_info = api_get_user_info();
4645
            if (isset($user_info['theme'])) {
4646
                $user_theme = $user_info['theme'];
4647
4648
                if (!empty($user_theme)) {
4649
                    $visual_theme = $user_theme;
4650
                    // User's theme.
4651
                }
4652
            }
4653
        }
4654
4655
        $course_id = api_get_course_id();
4656
        if (!empty($course_id) && $course_id != -1) {
4657
            if (api_get_setting('allow_course_theme') == 'true') {
4658
                $course_theme = api_get_course_setting('course_theme');
4659
4660
                if (!empty($course_theme) && $course_theme != -1) {
4661
                    if (!empty($course_theme)) {
4662
                        // Course's theme.
4663
                        $visual_theme = $course_theme;
4664
                    }
4665
                }
4666
4667
                $allow_lp_theme = api_get_course_setting('allow_learning_path_theme');
4668
                if ($allow_lp_theme == 1) {
4669
                    global $lp_theme_css, $lp_theme_config;
4670
                    // These variables come from the file lp_controller.php.
4671
                    if (!$lp_theme_config) {
4672
                        if (!empty($lp_theme_css)) {
4673
                            // LP's theme.
4674
                            $visual_theme = $lp_theme_css;
4675
                        }
4676
                    }
4677
                }
4678
            }
4679
        }
4680
4681
        if (empty($visual_theme)) {
4682
            $visual_theme = 'chamilo';
4683
        }
4684
4685
        global $lp_theme_log;
4686
        if ($lp_theme_log) {
4687
            $visual_theme = $platform_theme;
4688
        }
4689
    }
4690
4691
    return $visual_theme;
4692
}
4693
4694
/**
4695
 * Returns a list of CSS themes currently available in the CSS folder
4696
 * The folder must have a default.css file
4697
 * @param bool $getOnlyThemeFromVirtualInstance Used by the vchamilo plugin
4698
 * @return array        List of themes directories from the css folder
4699
 * Note: Directory names (names of themes) in the file system should contain ASCII-characters only.
4700
 */
4701
function api_get_themes($getOnlyThemeFromVirtualInstance = false)
4702
{
4703
    // This configuration value is set by the vchamilo plugin
4704
    $virtualTheme = api_get_configuration_value('virtual_css_theme_folder');
4705
4706
    $readCssFolder = function ($dir) use ($virtualTheme) {
4707
        $finder = new Finder();
4708
        $themes = $finder->directories()->in($dir)->depth(0)->sortByName();
4709
        $list = [];
4710
        /** @var Symfony\Component\Finder\SplFileInfo $theme */
4711
        foreach ($themes as $theme) {
4712
            $folder = $theme->getFilename();
4713
            // A theme folder is consider if there's a default.css file
4714
            if (!file_exists($theme->getPathname().'/default.css')) {
4715
                continue;
4716
            }
4717
            $name = ucwords(str_replace('_', ' ', $folder));
4718
            if ($folder == $virtualTheme) {
4719
                continue;
4720
            }
4721
            $list[$folder] = $name;
4722
        }
4723
        return $list;
4724
    };
4725
4726
    $dir = api_get_path(SYS_CSS_PATH).'themes/';
4727
    $list = $readCssFolder($dir);
4728
4729
    if (!empty($virtualTheme)) {
4730
        $newList = $readCssFolder($dir.'/'.$virtualTheme);
4731
        if ($getOnlyThemeFromVirtualInstance) {
4732
            return $newList;
4733
        }
4734
        $list = $list + $newList;
4735
        asort($list);
4736
    }
4737
4738
    return $list;
4739
}
4740
4741
/**
4742
 * Find the largest sort value in a given user_course_category
4743
 * This function is used when we are moving a course to a different category
4744
 * and also when a user subscribes to courses (the new course is added at the end of the main category
4745
 * @author Patrick Cool <[email protected]>, Ghent University
4746
 * @param int $user_course_category the id of the user_course_category
4747
 * @param integer $user_id
4748
 * @return int the value of the highest sort of the user_course_category
4749
 */
4750
function api_max_sort_value($user_course_category, $user_id)
4751
{
4752
    $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4753
    $sql = "SELECT max(sort) as max_sort FROM $tbl_course_user
4754
            WHERE
4755
                user_id='".intval($user_id)."' AND
4756
                relation_type<>".COURSE_RELATION_TYPE_RRHH." AND
4757
                user_course_cat='".intval($user_course_category)."'";
4758
    $result_max = Database::query($sql);
4759
    if (Database::num_rows($result_max) == 1) {
4760
        $row_max = Database::fetch_array($result_max);
4761
        return $row_max['max_sort'];
4762
    }
4763
    return 0;
4764
}
4765
4766
/**
4767
 * Transforms a number of seconds in hh:mm:ss format
4768
 * @author Julian Prud'homme
4769
 * @param integer the number of seconds
4770
 * @return string the formated time
4771
 */
4772
function api_time_to_hms($seconds)
4773
{
4774
    // $seconds = -1 means that we have wrong data in the db.
4775
    if ($seconds == -1) {
4776
        return
4777
            get_lang('Unknown').
4778
            Display::return_icon(
4779
                'info2.gif',
4780
                get_lang('WrongDatasForTimeSpentOnThePlatform'),
4781
                ['align' => 'absmiddle', 'hspace' => '3px']
4782
            );
4783
    }
4784
4785
    // How many hours ?
4786
    $hours = floor($seconds / 3600);
4787
4788
    // How many minutes ?
4789
    $min = floor(($seconds - ($hours * 3600)) / 60);
4790
4791
    // How many seconds
4792
    $sec = floor($seconds - ($hours * 3600) - ($min * 60));
4793
4794
    if ($sec < 10) {
4795
        $sec = "0$sec";
4796
    }
4797
4798
    if ($min < 10) {
4799
        $min = "0$min";
4800
    }
4801
4802
    return "$hours:$min:$sec";
4803
}
4804
4805
/* FILE SYSTEM RELATED FUNCTIONS */
4806
4807
/**
4808
 * Returns the permissions to be assigned to every newly created directory by the web-server.
4809
 * The return value is based on the platform administrator's setting
4810
 * "Administration > Configuration settings > Security > Permissions for new directories".
4811
 * @return int  Returns the permissions in the format "Owner-Group-Others, Read-Write-Execute", as an integer value.
4812
 */
4813
function api_get_permissions_for_new_directories()
4814
{
4815
    static $permissions;
4816
    if (!isset($permissions)) {
4817
        $permissions = trim(api_get_setting('permissions_for_new_directories'));
4818
        // The default value 0777 is according to that in the platform administration panel after fresh system installation.
4819
        $permissions = octdec(!empty($permissions) ? $permissions : '0777');
4820
    }
4821
    return $permissions;
4822
}
4823
4824
/**
4825
 * Returns the permissions to be assigned to every newly created directory by the web-server.
4826
 * The return value is based on the platform administrator's setting
4827
 * "Administration > Configuration settings > Security > Permissions for new files".
4828
 * @return int Returns the permissions in the format
4829
 * "Owner-Group-Others, Read-Write-Execute", as an integer value.
4830
 */
4831
function api_get_permissions_for_new_files()
4832
{
4833
    static $permissions;
4834
    if (!isset($permissions)) {
4835
        $permissions = trim(api_get_setting('permissions_for_new_files'));
4836
        // The default value 0666 is according to that in the platform
4837
        // administration panel after fresh system installation.
4838
        $permissions = octdec(!empty($permissions) ? $permissions : '0666');
4839
    }
4840
    return $permissions;
4841
}
4842
4843
/**
4844
 * Deletes a file, or a folder and its contents
4845
 *
4846
 * @author      Aidan Lister <[email protected]>
4847
 * @version     1.0.3
4848
 * @param       string   $dirname    Directory to delete
4849
 * @param       bool     Deletes only the content or not
4850
 * @param       bool     $strict if one folder/file fails stop the loop
4851
 * @return      bool     Returns TRUE on success, FALSE on failure
4852
 * @link http://aidanlister.com/2004/04/recursively-deleting-a-folder-in-php/
4853
 * @author      Yannick Warnier, adaptation for the Chamilo LMS, April, 2008
4854
 * @author      Ivan Tcholakov, a sanity check about Directory class creation has been added, September, 2009
4855
 */
4856
function rmdirr($dirname, $delete_only_content_in_folder = false, $strict = false)
4857
{
4858
    $res = true;
4859
    // A sanity check.
4860
    if (!file_exists($dirname)) {
4861
        return false;
4862
    }
4863
    $php_errormsg = '';
4864
    // Simple delete for a file.
4865
    if (is_file($dirname) || is_link($dirname)) {
4866
        $res = unlink($dirname);
4867
        if ($res === false) {
4868
            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);
4869
        }
4870
        return $res;
4871
    }
4872
4873
    // Loop through the folder.
4874
    $dir = dir($dirname);
0 ignored issues
show
Bug introduced by
The call to dir() has too few arguments starting with context. ( Ignorable by Annotation )

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

4874
    $dir = /** @scrutinizer ignore-call */ dir($dirname);

This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
4875
    // A sanity check.
4876
    $is_object_dir = is_object($dir);
4877
    if ($is_object_dir) {
4878
        while (false !== $entry = $dir->read()) {
4879
            // Skip pointers.
4880
            if ($entry == '.' || $entry == '..') {
4881
                continue;
4882
            }
4883
4884
            // Recurse.
4885
            if ($strict) {
4886
                $result = rmdirr("$dirname/$entry");
4887
                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...
4888
                    $res = false;
4889
                    break;
4890
                }
4891
            } else {
4892
                rmdirr("$dirname/$entry");
4893
            }
4894
        }
4895
    }
4896
4897
    // Clean up.
4898
    if ($is_object_dir) {
4899
        $dir->close();
0 ignored issues
show
Bug introduced by
The call to Directory::close() has too few arguments starting with dir_handle. ( Ignorable by Annotation )

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

4899
        $dir->/** @scrutinizer ignore-call */ 
4900
              close();

This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
4900
    }
4901
4902
    if ($delete_only_content_in_folder == false) {
4903
        $res = rmdir($dirname);
4904
        if ($res === false) {
4905
            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);
4906
        }
4907
    }
4908
    return $res;
4909
}
4910
4911
// TODO: This function is to be simplified. File access modes to be implemented.
4912
/**
4913
 * function adapted from a php.net comment
4914
 * copy recursively a folder
4915
 * @param the source folder
4916
 * @param the dest folder
4917
 * @param an array of excluded file_name (without extension)
4918
 * @param copied_files the returned array of copied files
4919
 * @param string $source
4920
 * @param string $dest
4921
 */
4922
function copyr($source, $dest, $exclude = [], $copied_files = [])
4923
{
4924
    if (empty($dest)) {
4925
        return false;
4926
    }
4927
    // Simple copy for a file
4928
    if (is_file($source)) {
4929
        $path_info = pathinfo($source);
4930
        if (!in_array($path_info['filename'], $exclude)) {
4931
            copy($source, $dest);
4932
        }
4933
        return true;
4934
    } elseif (!is_dir($source)) {
4935
        //then source is not a dir nor a file, return
4936
        return false;
4937
    }
4938
4939
    // Make destination directory.
4940
    if (!is_dir($dest)) {
4941
        mkdir($dest, api_get_permissions_for_new_directories());
4942
    }
4943
4944
    // Loop through the folder.
4945
    $dir = dir($source);
0 ignored issues
show
Bug introduced by
The call to dir() has too few arguments starting with context. ( Ignorable by Annotation )

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

4945
    $dir = /** @scrutinizer ignore-call */ dir($source);

This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
4946
    while (false !== $entry = $dir->read()) {
4947
        // Skip pointers
4948
        if ($entry == '.' || $entry == '..') {
4949
            continue;
4950
        }
4951
4952
        // Deep copy directories.
4953
        if ($dest !== "$source/$entry") {
4954
            $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

4954
            $files = copyr("$source/$entry", "$dest/$entry", $exclude, /** @scrutinizer ignore-type */ $copied_files);
Loading history...
4955
        }
4956
    }
4957
    // Clean up.
4958
    $dir->close();
4959
    return true;
4960
}
4961
4962
// TODO: Using DIRECTORY_SEPARATOR is not recommended, this is an obsolete approach. Documentation header to be added here.
4963
/**
4964
 * @param string $pathname
4965
 * @param string $base_path_document
4966
 * @param integer $session_id
4967
 */
4968
function copy_folder_course_session(
4969
    $pathname,
4970
    $base_path_document,
4971
    $session_id,
4972
    $course_info,
4973
    $document,
4974
    $source_course_id
4975
) {
4976
    $table = Database::get_course_table(TABLE_DOCUMENT);
4977
    $session_id = intval($session_id);
4978
    $source_course_id = intval($source_course_id);
4979
4980
    // Check whether directory already exists.
4981
    if (is_dir($pathname) || empty($pathname)) {
4982
        return true;
4983
    }
4984
4985
    // Ensure that a file with the same name does not already exist.
4986
    if (is_file($pathname)) {
4987
        trigger_error('copy_folder_course_session(): File exists', E_USER_WARNING);
4988
        return false;
4989
    }
4990
4991
    $course_id = $course_info['real_id'];
4992
    $folders = explode(DIRECTORY_SEPARATOR, str_replace($base_path_document.DIRECTORY_SEPARATOR, '', $pathname));
4993
    $new_pathname = $base_path_document;
4994
    $path = '';
4995
4996
    foreach ($folders as $folder) {
4997
        $new_pathname .= DIRECTORY_SEPARATOR.$folder;
4998
        $path .= DIRECTORY_SEPARATOR.$folder;
4999
5000
        if (!file_exists($new_pathname)) {
5001
            $path = Database::escape_string($path);
5002
5003
            $sql = "SELECT * FROM $table
5004
                    WHERE
5005
                        c_id = $source_course_id AND
5006
                        path = '$path' AND
5007
                        filetype = 'folder' AND
5008
                        session_id = '$session_id'";
5009
            $rs1 = Database::query($sql);
5010
            $num_rows = Database::num_rows($rs1);
5011
5012
            if ($num_rows == 0) {
5013
                mkdir($new_pathname, api_get_permissions_for_new_directories());
5014
5015
                // Insert new folder with destination session_id.
5016
                $params = [
5017
                    'c_id' => $course_id,
5018
                    'path' => $path,
5019
                    'comment' => $document->comment,
5020
                    'title' => basename($new_pathname),
5021
                    'filetype' => 'folder',
5022
                    'size' => '0',
5023
                    'session_id' => $session_id
5024
                ];
5025
                $document_id = Database::insert($table, $params);
5026
                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...
5027
                    $sql = "UPDATE $table SET id = iid WHERE iid = $document_id";
5028
                    Database::query($sql);
5029
5030
                    api_item_property_update(
5031
                        $course_info,
5032
                        TOOL_DOCUMENT,
5033
                        $document_id,
5034
                        'FolderCreated',
5035
                        api_get_user_id(),
5036
                        0,
5037
                        0,
5038
                        null,
5039
                        null,
5040
                        $session_id
5041
                    );
5042
                }
5043
            }
5044
        }
5045
    } // en foreach
5046
}
5047
5048
// TODO: chmodr() is a better name. Some corrections are needed. Documentation header to be added here.
5049
/**
5050
 * @param string $path
5051
 */
5052
function api_chmod_R($path, $filemode)
5053
{
5054
    if (!is_dir($path)) {
5055
        return chmod($path, $filemode);
5056
    }
5057
5058
    $handler = opendir($path);
5059
    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

5059
    while ($file = readdir(/** @scrutinizer ignore-type */ $handler)) {
Loading history...
5060
        if ($file != '.' && $file != '..') {
5061
            $fullpath = "$path/$file";
5062
            if (!is_dir($fullpath)) {
5063
                if (!chmod($fullpath, $filemode)) {
5064
                    return false;
5065
                }
5066
            } else {
5067
                if (!api_chmod_R($fullpath, $filemode)) {
5068
                    return false;
5069
                }
5070
            }
5071
        }
5072
    }
5073
5074
    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

5074
    closedir(/** @scrutinizer ignore-type */ $handler);
Loading history...
5075
    return chmod($path, $filemode);
5076
}
5077
5078
5079
// TODO: Where the following function has been copy/pased from? There is no information about author and license. Style, coding conventions...
5080
/**
5081
 * Parse info file format. (e.g: file.info)
5082
 *
5083
 * Files should use an ini-like format to specify values.
5084
 * White-space generally doesn't matter, except inside values.
5085
 * e.g.
5086
 *
5087
 * @verbatim
5088
 *   key = value
5089
 *   key = "value"
5090
 *   key = 'value'
5091
 *   key = "multi-line
5092
 *
5093
 *   value"
5094
 *   key = 'multi-line
5095
 *
5096
 *   value'
5097
 *   key
5098
 *   =
5099
 *   'value'
5100
 * @endverbatim
5101
 *
5102
 * Arrays are created using a GET-like syntax:
5103
 *
5104
 * @verbatim
5105
 *   key[] = "numeric array"
5106
 *   key[index] = "associative array"
5107
 *   key[index][] = "nested numeric array"
5108
 *   key[index][index] = "nested associative array"
5109
 * @endverbatim
5110
 *
5111
 * PHP constants are substituted in, but only when used as the entire value:
5112
 *
5113
 * Comments should start with a semi-colon at the beginning of a line.
5114
 *
5115
 * This function is NOT for placing arbitrary module-specific settings. Use
5116
 * variable_get() and variable_set() for that.
5117
 *
5118
 * Information stored in the module.info file:
5119
 * - name: The real name of the module for display purposes.
5120
 * - description: A brief description of the module.
5121
 * - dependencies: An array of shortnames of other modules this module depends on.
5122
 * - package: The name of the package of modules this module belongs to.
5123
 *
5124
 * Example of .info file:
5125
 * <code>
5126
 * @verbatim
5127
 *   name = Forum
5128
 *   description = Enables threaded discussions about general topics.
5129
 *   dependencies[] = taxonomy
5130
 *   dependencies[] = comment
5131
 *   package = Core - optional
5132
 *   version = VERSION
5133
 * @endverbatim
5134
 * </code>
5135
 * @param string $filename
5136
 *   The file we are parsing. Accepts file with relative or absolute path.
5137
 * @return
5138
 *   The info array.
5139
 */
5140
function api_parse_info_file($filename)
5141
{
5142
    $info = [];
5143
5144
    if (!file_exists($filename)) {
5145
        return $info;
5146
    }
5147
5148
    $data = file_get_contents($filename);
5149
    if (preg_match_all('
5150
        @^\s*                           # Start at the beginning of a line, ignoring leading whitespace
5151
        ((?:
5152
          [^=;\[\]]|                    # Key names cannot contain equal signs, semi-colons or square brackets,
5153
          \[[^\[\]]*\]                  # unless they are balanced and not nested
5154
        )+?)
5155
        \s*=\s*                         # Key/value pairs are separated by equal signs (ignoring white-space)
5156
        (?:
5157
          ("(?:[^"]|(?<=\\\\)")*")|     # Double-quoted string, which may contain slash-escaped quotes/slashes
5158
          (\'(?:[^\']|(?<=\\\\)\')*\')| # Single-quoted string, which may contain slash-escaped quotes/slashes
5159
          ([^\r\n]*?)                   # Non-quoted string
5160
        )\s*$                           # Stop at the next end of a line, ignoring trailing whitespace
5161
        @msx', $data, $matches, PREG_SET_ORDER)) {
5162
        $key = $value1 = $value2 = $value3 = '';
5163
        foreach ($matches as $match) {
5164
            // Fetch the key and value string.
5165
            $i = 0;
5166
            foreach (['key', 'value1', 'value2', 'value3'] as $var) {
5167
                $$var = isset($match[++$i]) ? $match[$i] : '';
5168
            }
5169
            $value = stripslashes(substr($value1, 1, -1)).stripslashes(substr($value2, 1, -1)).$value3;
5170
5171
            // Parse array syntax.
5172
            $keys = preg_split('/\]?\[/', rtrim($key, ']'));
5173
            $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

5173
            $last = array_pop(/** @scrutinizer ignore-type */ $keys);
Loading history...
5174
            $parent = &$info;
5175
5176
            // Create nested arrays.
5177
            foreach ($keys as $key) {
5178
                if ($key == '') {
5179
                    $key = count($parent);
5180
                }
5181
                if (!isset($parent[$key]) || !is_array($parent[$key])) {
5182
                    $parent[$key] = [];
5183
                }
5184
                $parent = &$parent[$key];
5185
            }
5186
5187
            // Handle PHP constants.
5188
            if (defined($value)) {
5189
                $value = constant($value);
5190
            }
5191
5192
            // Insert actual value.
5193
            if ($last == '') {
5194
                $last = count($parent);
5195
            }
5196
            $parent[$last] = $value;
5197
        }
5198
    }
5199
    return $info;
5200
}
5201
5202
/**
5203
 * Gets Chamilo version from the configuration files
5204
 * @return string   A string of type "1.8.4", or an empty string if the version could not be found
5205
 */
5206
function api_get_version()
5207
{
5208
    return (string) api_get_configuration_value('system_version');
5209
}
5210
5211
/**
5212
 * Gets the software name (the name/brand of the Chamilo-based customized system)
5213
 * @return string
5214
 */
5215
function api_get_software_name()
5216
{
5217
    $name = api_get_configuration_value('software_name');
5218
    if (!empty($name)) {
5219
        return $name;
5220
    } else {
5221
        return 'Chamilo';
5222
    }
5223
}
5224
5225
/**
5226
 * Checks whether status given in parameter exists in the platform
5227
 * @param mixed the status (can be either int either string)
5228
 * @return boolean if the status exists, else returns false
5229
 */
5230
function api_status_exists($status_asked)
5231
{
5232
    global $_status_list;
5233
    return in_array($status_asked, $_status_list) ? true : isset($_status_list[$status_asked]);
5234
}
5235
5236
/**
5237
 * Checks whether status given in parameter exists in the platform. The function
5238
 * returns the status ID or false if it does not exist, but given the fact there
5239
 * is no "0" status, the return value can be checked against
5240
 * if(api_status_key()) to know if it exists.
5241
 * @param   mixed   The status (can be either int or string)
5242
 * @return  mixed   Status ID if exists, false otherwise
5243
 */
5244
function api_status_key($status)
5245
{
5246
    global $_status_list;
5247
    return isset($_status_list[$status]) ? $status : array_search($status, $_status_list);
5248
}
5249
5250
/**
5251
 * Gets the status langvars list
5252
 * @return string[] the list of status with their translations
5253
 */
5254
function api_get_status_langvars()
5255
{
5256
    return [
5257
        COURSEMANAGER => get_lang('Teacher', ''),
5258
        SESSIONADMIN => get_lang('SessionsAdmin', ''),
5259
        DRH => get_lang('Drh', ''),
5260
        STUDENT => get_lang('Student', ''),
5261
        ANONYMOUS => get_lang('Anonymous', ''),
5262
        STUDENT_BOSS => get_lang('RoleStudentBoss', ''),
5263
        INVITEE => get_lang('Invited'),
5264
    ];
5265
}
5266
5267
/**
5268
 * The function that retrieves all the possible settings for a certain config setting
5269
 * @author Patrick Cool <[email protected]>, Ghent University
5270
 */
5271
function api_get_settings_options($var)
5272
{
5273
    $table_settings_options = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
5274
    $var = Database::escape_string($var);
5275
    $sql = "SELECT * FROM $table_settings_options
5276
            WHERE variable = '$var'
5277
            ORDER BY id";
5278
    $result = Database::query($sql);
5279
    $settings_options_array = [];
5280
    while ($row = Database::fetch_array($result, 'ASSOC')) {
5281
        $settings_options_array[] = $row;
5282
    }
5283
    return $settings_options_array;
5284
}
5285
5286
/**
5287
 * @param array $params
5288
 */
5289
function api_set_setting_option($params)
5290
{
5291
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
5292
    if (empty($params['id'])) {
5293
        Database::insert($table, $params);
5294
    } else {
5295
        Database::update($table, $params, ['id = ? '=> $params['id']]);
5296
    }
5297
}
5298
5299
/**
5300
 * @param array $params
5301
 */
5302
function api_set_setting_simple($params)
5303
{
5304
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5305
    $url_id = api_get_current_access_url_id();
5306
5307
    if (empty($params['id'])) {
5308
        $params['access_url'] = $url_id;
5309
        Database::insert($table, $params);
5310
    } else {
5311
        Database::update($table, $params, ['id = ? '=> [$params['id']]]);
5312
    }
5313
}
5314
5315
/**
5316
 * @param int $id
5317
 */
5318
function api_delete_setting_option($id)
5319
{
5320
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
5321
    if (!empty($id)) {
5322
        Database::delete($table, ['id = ? '=> $id]);
5323
    }
5324
}
5325
5326
/**
5327
 * Sets a platform configuration setting to a given value
5328
 * @param string    The variable we want to update
5329
 * @param string    The value we want to record
5330
 * @param string    The sub-variable if any (in most cases, this will remain null)
5331
 * @param string    The category if any (in most cases, this will remain null)
5332
 * @param int       The access_url for which this parameter is valid
5333
 * @param string $cat
5334
 * @return bool|null
5335
 */
5336
function api_set_setting($var, $value, $subvar = null, $cat = null, $access_url = 1)
5337
{
5338
    if (empty($var)) {
5339
        return false;
5340
    }
5341
    $t_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5342
    $var = Database::escape_string($var);
5343
    $value = Database::escape_string($value);
5344
    $access_url = (int) $access_url;
5345
    if (empty($access_url)) {
5346
        $access_url = 1;
5347
    }
5348
    $select = "SELECT id FROM $t_settings WHERE variable = '$var' ";
5349
    if (!empty($subvar)) {
5350
        $subvar = Database::escape_string($subvar);
5351
        $select .= " AND subkey = '$subvar'";
5352
    }
5353
    if (!empty($cat)) {
5354
        $cat = Database::escape_string($cat);
5355
        $select .= " AND category = '$cat'";
5356
    }
5357
    if ($access_url > 1) {
5358
        $select .= " AND access_url = $access_url";
5359
    } else {
5360
        $select .= " AND access_url = 1 ";
5361
    }
5362
5363
    $res = Database::query($select);
5364
    if (Database::num_rows($res) > 0) {
5365
        // Found item for this access_url.
5366
        $row = Database::fetch_array($res);
5367
        $sql = "UPDATE $t_settings SET selected_value = '$value'
5368
                WHERE id = ".$row['id'];
5369
        Database::query($sql);
5370
    } else {
5371
        // Item not found for this access_url, we have to check if it exist with access_url = 1
5372
        $select = "SELECT * FROM $t_settings
5373
                   WHERE variable = '$var' AND access_url = 1 ";
5374
        // Just in case
5375
        if ($access_url == 1) {
5376
            if (!empty($subvar)) {
5377
                $select .= " AND subkey = '$subvar'";
5378
            }
5379
            if (!empty($cat)) {
5380
                $select .= " AND category = '$cat'";
5381
            }
5382
            $res = Database::query($select);
5383
            if (Database::num_rows($res) > 0) {
5384
                // We have a setting for access_url 1, but none for the current one, so create one.
5385
                $row = Database::fetch_array($res);
5386
                $insert = "INSERT INTO $t_settings (variable, subkey, type,category, selected_value, title, comment, scope, subkeytext, access_url)
5387
                        VALUES
5388
                        ('".$row['variable']."',".(!empty($row['subkey']) ? "'".$row['subkey']."'" : "NULL").",".
5389
                    "'".$row['type']."','".$row['category']."',".
5390
                    "'$value','".$row['title']."',".
5391
                    "".(!empty($row['comment']) ? "'".$row['comment']."'" : "NULL").",".(!empty($row['scope']) ? "'".$row['scope']."'" : "NULL").",".
5392
                    "".(!empty($row['subkeytext']) ? "'".$row['subkeytext']."'" : "NULL").",$access_url)";
5393
                Database::query($insert);
5394
            } 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...
5395
                // Such a setting does not exist.
5396
                //error_log(__FILE__.':'.__LINE__.': Attempting to update setting '.$var.' ('.$subvar.') which does not exist at all', 0);
5397
            }
5398
        } else {
5399
            // Other access url.
5400
            if (!empty($subvar)) {
5401
                $select .= " AND subkey = '$subvar'";
5402
            }
5403
            if (!empty($cat)) {
5404
                $select .= " AND category = '$cat'";
5405
            }
5406
            $res = Database::query($select);
5407
5408
            if (Database::num_rows($res) > 0) {
5409
                // We have a setting for access_url 1, but none for the current one, so create one.
5410
                $row = Database::fetch_array($res);
5411
                if ($row['access_url_changeable'] == 1) {
5412
                    $insert = "INSERT INTO $t_settings (variable,subkey, type,category, selected_value,title, comment,scope, subkeytext,access_url, access_url_changeable) VALUES
5413
                            ('".$row['variable']."',".
5414
                        (!empty($row['subkey']) ? "'".$row['subkey']."'" : "NULL").",".
5415
                        "'".$row['type']."','".$row['category']."',".
5416
                        "'$value','".$row['title']."',".
5417
                        "".(!empty($row['comment']) ? "'".$row['comment']."'" : "NULL").",".
5418
                        (!empty($row['scope']) ? "'".$row['scope']."'" : "NULL").",".
5419
                        "".(!empty($row['subkeytext']) ? "'".$row['subkeytext']."'" : "NULL").",$access_url,".$row['access_url_changeable'].")";
5420
                    Database::query($insert);
5421
                }
5422
            } 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...
5423
                //error_log(__FILE__.':'.__LINE__.': Attempting to update setting '.$var.' ('.$subvar.') which does not exist at all. The access_url is: '.$access_url.' ',0);
5424
            }
5425
        }
5426
    }
5427
}
5428
5429
/**
5430
 * Sets a whole category of settings to one specific value
5431
 * @param string    Category
5432
 * @param string    Value
5433
 * @param int       Access URL. Optional. Defaults to 1
5434
 * @param array     Optional array of filters on field type
5435
 * @param string $category
5436
 * @param string $value
5437
 * @return bool
5438
 */
5439
function api_set_settings_category($category, $value = null, $access_url = 1, $fieldtype = [])
5440
{
5441
    if (empty($category)) {
5442
        return false;
5443
    }
5444
    $category = Database::escape_string($category);
5445
    $t_s = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5446
    $access_url = (int) $access_url;
5447
    if (empty($access_url)) {
5448
        $access_url = 1;
5449
    }
5450
    if (isset($value)) {
5451
        $value = Database::escape_string($value);
5452
        $sql = "UPDATE $t_s SET selected_value = '$value'
5453
                WHERE category = '$category' AND access_url = $access_url";
5454
        if (is_array($fieldtype) && count($fieldtype) > 0) {
5455
            $sql .= " AND ( ";
5456
            $i = 0;
5457
            foreach ($fieldtype as $type) {
5458
                if ($i > 0) {
5459
                    $sql .= ' OR ';
5460
                }
5461
                $type = Database::escape_string($type);
5462
                $sql .= " type='".$type."' ";
5463
                $i++;
5464
            }
5465
            $sql .= ")";
5466
        }
5467
        $res = Database::query($sql);
5468
        return $res !== false;
5469
    } else {
5470
        $sql = "UPDATE $t_s SET selected_value = NULL
5471
                WHERE category = '$category' AND access_url = $access_url";
5472
        if (is_array($fieldtype) && count($fieldtype) > 0) {
5473
            $sql .= " AND ( ";
5474
            $i = 0;
5475
            foreach ($fieldtype as $type) {
5476
                if ($i > 0) {
5477
                    $sql .= ' OR ';
5478
                }
5479
                $type = Database::escape_string($type);
5480
                $sql .= " type='".$type."' ";
5481
                $i++;
5482
            }
5483
            $sql .= ")";
5484
        }
5485
        $res = Database::query($sql);
5486
        return $res !== false;
5487
    }
5488
}
5489
5490
/**
5491
 * Gets all available access urls in an array (as in the database)
5492
 * @return array    An array of database records
5493
 */
5494
function api_get_access_urls($from = 0, $to = 1000000, $order = 'url', $direction = 'ASC')
5495
{
5496
    $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5497
    $from = (int) $from;
5498
    $to = (int) $to;
5499
    $order = Database::escape_string($order, null, false);
5500
    $direction = Database::escape_string($direction, null, false);
5501
    $sql = "SELECT id, url, description, active, created_by, tms
5502
            FROM $table
5503
            ORDER BY $order $direction
5504
            LIMIT $to OFFSET $from";
5505
    $res = Database::query($sql);
5506
    return Database::store_result($res);
5507
}
5508
5509
/**
5510
 * Gets the access url info in an array
5511
 * @param int $id Id of the access url
5512
 * @param bool $returnDefault Set to false if you want the real URL if URL 1 is still 'http://localhost/'
5513
 * @return array All the info (url, description, active, created_by, tms)
5514
 * from the access_url table
5515
 * @author Julio Montoya
5516
 */
5517
function api_get_access_url($id, $returnDefault = true)
5518
{
5519
    static $staticResult;
5520
    $id = intval($id);
5521
5522
    if (isset($staticResult[$id])) {
5523
        $result = $staticResult[$id];
5524
    } else {
5525
        // Calling the Database:: library dont work this is handmade.
5526
        $table_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5527
        $sql = "SELECT url, description, active, created_by, tms
5528
                FROM $table_access_url WHERE id = '$id' ";
5529
        $res = Database::query($sql);
5530
        $result = @Database::fetch_array($res);
5531
        $staticResult[$id] = $result;
5532
    }
5533
5534
    // If the result url is 'http://localhost/' (the default) and the root_web
5535
    // (=current url) is different, and the $id is = 1 (which might mean
5536
    // api_get_current_access_url_id() returned 1 by default), then return the
5537
    // root_web setting instead of the current URL
5538
    // This is provided as an option to avoid breaking the storage of URL-specific
5539
    // homepages in home/localhost/
5540
    if ($id === 1 && $returnDefault === false) {
5541
        $currentUrl = api_get_current_access_url_id();
5542
        // only do this if we are on the main URL (=1), otherwise we could get
5543
        // information on another URL instead of the one asked as parameter
5544
        if ($currentUrl === 1) {
5545
            $rootWeb = api_get_path(WEB_PATH);
5546
            $default = 'http://localhost/';
5547
            if ($result['url'] === $default && $rootWeb != $default) {
5548
                $result['url'] = $rootWeb;
5549
            }
5550
        }
5551
    }
5552
5553
    return $result;
5554
}
5555
5556
/**
5557
 * Gets all the current settings for a specific access url
5558
 * @param string    The category, if any, that we want to get
5559
 * @param string    Whether we want a simple list (display a category) or
5560
 * a grouped list (group by variable as in settings.php default). Values: 'list' or 'group'
5561
 * @param int       Access URL's ID. Optional. Uses 1 by default, which is the unique URL
5562
 * @return array    Array of database results for the current settings of the current access URL
5563
 */
5564
function &api_get_settings($cat = null, $ordering = 'list', $access_url = 1, $url_changeable = 0)
5565
{
5566
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5567
    $access_url = (int) $access_url;
5568
    $where_condition = '';
5569
    if ($url_changeable == 1) {
5570
        $where_condition = " AND access_url_changeable= '1' ";
5571
    }
5572
    if (empty($access_url) || $access_url == -1) {
5573
        $access_url = 1;
5574
    }
5575
    $sql = "SELECT * FROM $table
5576
            WHERE access_url = $access_url  $where_condition ";
5577
5578
    if (!empty($cat)) {
5579
        $cat = Database::escape_string($cat);
5580
        $sql .= " AND category='$cat' ";
5581
    }
5582
    if ($ordering == 'group') {
5583
        $sql .= " ORDER BY id ASC";
5584
    } else {
5585
        $sql .= " ORDER BY 1,2 ASC";
5586
    }
5587
    $result = Database::query($sql);
5588
    if ($result === null) {
5589
        return [];
5590
    }
5591
    $result = Database::store_result($result, 'ASSOC');
5592
5593
    return $result;
5594
}
5595
5596
/**
5597
 * @param string $value The value we want to record
5598
 * @param string $variable The variable name we want to insert
5599
 * @param string $subKey The subkey for the variable we want to insert
5600
 * @param string $type The type for the variable we want to insert
5601
 * @param string $category The category for the variable we want to insert
5602
 * @param string $title The title
5603
 * @param string $comment The comment
5604
 * @param string $scope The scope
5605
 * @param string $subKeyText The subkey text
5606
 * @param int $accessUrlId The access_url for which this parameter is valid
5607
 * @param int $visibility The changeability of this setting for non-master urls
5608
 * @return int The setting ID
5609
 */
5610
function api_add_setting(
5611
    $value,
5612
    $variable,
5613
    $subKey = '',
5614
    $type = 'textfield',
5615
    $category = '',
5616
    $title = '',
5617
    $comment = '',
5618
    $scope = '',
5619
    $subKeyText = '',
5620
    $accessUrlId = 1,
5621
    $visibility = 0
5622
) {
5623
    $em = Database::getManager();
5624
    $settingRepo = $em->getRepository('ChamiloCoreBundle:SettingsCurrent');
5625
    $accessUrlId = (int) $accessUrlId ?: 1;
5626
5627
    if (is_array($value)) {
5628
        $value = serialize($value);
5629
    } else {
5630
        $value = trim($value);
5631
    }
5632
5633
    $criteria = ['variable' => $variable, 'accessUrl' => $accessUrlId];
5634
5635
    if (!empty($subKey)) {
5636
        $criteria['subkey'] = $subKey;
5637
    }
5638
5639
    // Check if this variable doesn't exist already
5640
    /** @var SettingsCurrent $setting */
5641
    $setting = $settingRepo->findOneBy($criteria);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $setting is correct as $settingRepo->findOneBy($criteria) targeting Doctrine\ORM\EntityRepository::findOneBy() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
5642
5643
    if ($setting) {
5644
        $setting->setSelectedValue($value);
5645
5646
        $em->persist($setting);
5647
        $em->flush();
5648
5649
        return $setting->getId();
5650
    }
5651
5652
    // Item not found for this access_url, we have to check if the whole thing is missing
5653
    // (in which case we ignore the insert) or if there *is* a record but just for access_url = 1
5654
    $setting = new SettingsCurrent();
5655
    $setting
5656
        ->setVariable($variable)
5657
        ->setSelectedValue($value)
5658
        ->setType($type)
5659
        ->setCategory($category)
5660
        ->setSubkey($subKey)
5661
        ->setTitle($title)
5662
        ->setComment($comment)
5663
        ->setScope($scope)
5664
        ->setSubkeytext($subKeyText)
5665
        ->setAccessUrl($accessUrlId)
5666
        ->setAccessUrlChangeable($visibility);
5667
5668
    $em->persist($setting);
5669
    $em->flush();
5670
5671
    return $setting->getId();
5672
}
5673
5674
/**
5675
 * Checks wether a user can or can't view the contents of a course.
5676
 * @deprecated use CourseManager::is_user_subscribed_in_course
5677
 * @param   int $userid     User id or NULL to get it from $_SESSION
5678
 * @param   int $cid        Course id to check whether the user is allowed.
5679
 * @return  bool
5680
 */
5681
function api_is_course_visible_for_user($userid = null, $cid = null)
5682
{
5683
    if ($userid === null) {
5684
        $userid = api_get_user_id();
5685
    }
5686
    if (empty($userid) || strval(intval($userid)) != $userid) {
5687
        if (api_is_anonymous()) {
5688
            $userid = api_get_anonymous_id();
5689
        } else {
5690
            return false;
5691
        }
5692
    }
5693
    $cid = Database::escape_string($cid);
5694
5695
    $courseInfo = api_get_course_info($cid);
5696
    $courseId = $courseInfo['real_id'];
5697
    $is_platformAdmin = api_is_platform_admin();
5698
5699
    $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
5700
    $course_cat_table = Database::get_main_table(TABLE_MAIN_CATEGORY);
5701
5702
    $sql = "SELECT
5703
                $course_table.category_code,
5704
                $course_table.visibility,
5705
                $course_table.code,
5706
                $course_cat_table.code
5707
            FROM $course_table
5708
            LEFT JOIN $course_cat_table
5709
                ON $course_table.category_code = $course_cat_table.code
5710
            WHERE
5711
                $course_table.code = '$cid'
5712
            LIMIT 1";
5713
5714
    $result = Database::query($sql);
5715
5716
    if (Database::num_rows($result) > 0) {
5717
        $visibility = Database::fetch_array($result);
5718
        $visibility = $visibility['visibility'];
5719
    } else {
5720
        $visibility = 0;
5721
    }
5722
    // Shortcut permissions in case the visibility is "open to the world".
5723
    if ($visibility === COURSE_VISIBILITY_OPEN_WORLD) {
5724
        return true;
5725
    }
5726
5727
    $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
5728
5729
    $sql = "SELECT
5730
                is_tutor, status
5731
            FROM $tbl_course_user
5732
            WHERE
5733
                user_id  = '$userid' AND
5734
                relation_type <> '".COURSE_RELATION_TYPE_RRHH."' AND
5735
                c_id = $courseId
5736
            LIMIT 1";
5737
5738
    $result = Database::query($sql);
5739
5740
    if (Database::num_rows($result) > 0) {
5741
        // This user has got a recorded state for this course.
5742
        $cuData = Database::fetch_array($result);
5743
        $is_courseMember = true;
5744
        $is_courseAdmin = ($cuData['status'] == 1);
5745
    }
5746
5747
    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...
5748
        // This user has no status related to this course.
5749
        // Is it the session coach or the session admin?
5750
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
5751
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
5752
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
5753
5754
        $sql = "SELECT
5755
                    session.id_coach, session_admin_id, session.id
5756
                FROM
5757
                    $tbl_session as session
5758
                INNER JOIN $tbl_session_course
5759
                    ON session_rel_course.session_id = session.id
5760
                    AND session_rel_course.c_id = '$courseId'
5761
                LIMIT 1";
5762
5763
        $result = Database::query($sql);
5764
        $row = Database::store_result($result);
5765
5766
        if ($row[0]['id_coach'] == $userid) {
5767
            $is_courseMember = true;
5768
            $is_courseAdmin = false;
5769
        } elseif ($row[0]['session_admin_id'] == $userid) {
5770
            $is_courseMember = false;
5771
            $is_courseAdmin = false;
5772
        } else {
5773
            // Check if the current user is the course coach.
5774
            $sql = "SELECT 1
5775
                    FROM $tbl_session_course
5776
                    WHERE session_rel_course.c_id = '$courseId'
5777
                    AND session_rel_course.id_coach = '$userid'
5778
                    LIMIT 1";
5779
5780
            $result = Database::query($sql);
5781
5782
            //if ($row = Database::fetch_array($result)) {
5783
            if (Database::num_rows($result) > 0) {
5784
                $is_courseMember = true;
5785
                $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
5786
5787
                $sql = "SELECT status FROM $tbl_user
5788
                        WHERE user_id = $userid
5789
                        LIMIT 1";
5790
5791
                $result = Database::query($sql);
5792
5793
                if (Database::result($result, 0, 0) == 1) {
5794
                    $is_courseAdmin = true;
5795
                } else {
5796
                    $is_courseAdmin = false;
5797
                }
5798
            } else {
5799
                // Check if the user is a student is this session.
5800
                $sql = "SELECT  id
5801
                        FROM $tbl_session_course_user
5802
                        WHERE
5803
                            user_id  = '$userid' AND
5804
                            c_id = '$courseId'
5805
                        LIMIT 1";
5806
5807
                if (Database::num_rows($result) > 0) {
5808
                    // This user haa got a recorded state for this course.
5809
                    while ($row = Database::fetch_array($result)) {
5810
                        $is_courseMember = true;
5811
                        $is_courseAdmin = false;
5812
                    }
5813
                }
5814
            }
5815
        }
5816
    }
5817
5818
    switch ($visibility) {
5819
        case COURSE_VISIBILITY_OPEN_WORLD:
5820
            return true;
5821
        case COURSE_VISIBILITY_OPEN_PLATFORM:
5822
            return isset($userid);
5823
        case COURSE_VISIBILITY_REGISTERED:
5824
        case COURSE_VISIBILITY_CLOSED:
5825
            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...
5826
        case COURSE_VISIBILITY_HIDDEN:
5827
            return $is_platformAdmin;
5828
    }
5829
5830
    return false;
5831
}
5832
5833
/**
5834
 * Returns whether an element (forum, message, survey ...) belongs to a session or not
5835
 * @param String the tool of the element
5836
 * @param int the element id in database
5837
 * @param int the session_id to compare with element session id
5838
 * @param string $tool
5839
 * @return boolean true if the element is in the session, false else
5840
 */
5841
function api_is_element_in_the_session($tool, $element_id, $session_id = null)
5842
{
5843
    if (is_null($session_id)) {
5844
        $session_id = api_get_session_id();
5845
    }
5846
5847
    // Get information to build query depending of the tool.
5848
    switch ($tool) {
5849
        case TOOL_SURVEY:
5850
            $table_tool = Database::get_course_table(TABLE_SURVEY);
5851
            $key_field = 'survey_id';
5852
            break;
5853
        case TOOL_ANNOUNCEMENT:
5854
            $table_tool = Database::get_course_table(TABLE_ANNOUNCEMENT);
5855
            $key_field = 'id';
5856
            break;
5857
        case TOOL_AGENDA:
5858
            $table_tool = Database::get_course_table(TABLE_AGENDA);
5859
            $key_field = 'id';
5860
            break;
5861
        case TOOL_GROUP:
5862
            $table_tool = Database::get_course_table(TABLE_GROUP);
5863
            $key_field = 'id';
5864
            break;
5865
        default:
5866
            return false;
5867
    }
5868
    $course_id = api_get_course_int_id();
5869
5870
    $sql = "SELECT session_id FROM $table_tool 
5871
            WHERE c_id = $course_id AND $key_field =  ".intval($element_id);
5872
    $rs = Database::query($sql);
5873
    if ($element_session_id = Database::result($rs, 0, 0)) {
5874
        if ($element_session_id == intval($session_id)) {
5875
            // The element belongs to the session.
5876
            return true;
5877
        }
5878
    }
5879
    return false;
5880
}
5881
5882
/**
5883
 * Replaces "forbidden" characters in a filename string.
5884
 *
5885
 * @param string $filename
5886
 * @param bool $treat_spaces_as_hyphens
5887
 *
5888
 * @return string
5889
 */
5890
function api_replace_dangerous_char($filename, $treat_spaces_as_hyphens = true)
5891
{
5892
    return URLify::filter(
5893
        $filename,
5894
        250,
5895
        '',
5896
        true,
5897
        true,
5898
        false,
5899
        false,
5900
        $treat_spaces_as_hyphens
5901
    );
5902
}
5903
5904
/**
5905
 * Fixes the $_SERVER['REQUEST_URI'] that is empty in IIS6.
5906
 * @author Ivan Tcholakov, 28-JUN-2006.
5907
 */
5908
function api_request_uri()
5909
{
5910
    if (!empty($_SERVER['REQUEST_URI'])) {
5911
        return $_SERVER['REQUEST_URI'];
5912
    }
5913
    $uri = $_SERVER['SCRIPT_NAME'];
5914
    if (!empty($_SERVER['QUERY_STRING'])) {
5915
        $uri .= '?'.$_SERVER['QUERY_STRING'];
5916
    }
5917
    $_SERVER['REQUEST_URI'] = $uri;
5918
    return $uri;
5919
}
5920
5921
5922
/** Gets the current access_url id of the Chamilo Platform
5923
 * @author Julio Montoya <[email protected]>
5924
 * @return int access_url_id of the current Chamilo Installation
5925
 */
5926
function api_get_current_access_url_id()
5927
{
5928
    $access_url_table = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5929
    $path = Database::escape_string(api_get_path(WEB_PATH));
5930
    $sql = "SELECT id FROM $access_url_table WHERE url = '".$path."'";
5931
    $result = Database::query($sql);
5932
    if (Database::num_rows($result) > 0) {
5933
        $access_url_id = Database::result($result, 0, 0);
5934
        return $access_url_id;
5935
    }
5936
    //if the url in WEB_PATH was not found, it can only mean that there is
5937
    // either a configuration problem or the first URL has not been defined yet
5938
    // (by default it is http://localhost/). Thus the more sensible thing we can
5939
    // do is return 1 (the main URL) as the user cannot hack this value anyway
5940
    return 1;
5941
}
5942
5943
/**
5944
 * Gets the registered urls from a given user id
5945
 * @author Julio Montoya <[email protected]>
5946
 * @return int user id
5947
 */
5948
function api_get_access_url_from_user($user_id)
5949
{
5950
    $user_id = intval($user_id);
5951
    $table_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
5952
    $table_url          = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5953
    $sql = "SELECT access_url_id
5954
            FROM $table_url_rel_user url_rel_user
5955
            INNER JOIN $table_url u
5956
            ON (url_rel_user.access_url_id = u.id)
5957
            WHERE user_id = ".intval($user_id);
5958
    $result = Database::query($sql);
5959
    $list = [];
5960
    while ($row = Database::fetch_array($result, 'ASSOC')) {
5961
        $list[] = $row['access_url_id'];
5962
    }
5963
    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...
5964
}
5965
5966
/**
5967
 * Gets the status of a user in a course
5968
 * @param int       $user_id
5969
 * @param int    $courseId
5970
 * @return int      user status
5971
 */
5972
function api_get_status_of_user_in_course($user_id, $courseId)
5973
{
5974
    $tbl_rel_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
5975
    if (!empty($user_id) && !empty($courseId)) {
5976
        $user_id = intval($user_id);
5977
        $courseId = intval($courseId);
5978
        $sql = 'SELECT status
5979
                FROM '.$tbl_rel_course_user.'
5980
                WHERE user_id='.$user_id.' AND c_id = '.$courseId;
5981
        $result = Database::query($sql);
5982
        $row_status = Database::fetch_array($result, 'ASSOC');
5983
        return $row_status['status'];
5984
    } else {
5985
        return 0;
5986
    }
5987
}
5988
5989
/**
5990
 * Checks whether the curent user is in a group or not.
5991
 *
5992
 * @param string        The group id - optional (takes it from session if not given)
5993
 * @param string        The course code - optional (no additional check by course if course code is not given)
5994
 * @return boolean
5995
 * @author Ivan Tcholakov
5996
 */
5997
function api_is_in_group($groupIdParam = null, $courseCodeParam = null)
5998
{
5999
    if (!empty($courseCodeParam)) {
6000
        $courseCode = api_get_course_id();
6001
        if (!empty($courseCode)) {
6002
            if ($courseCodeParam != $courseCode) {
6003
                return false;
6004
            }
6005
        } else {
6006
            return false;
6007
        }
6008
    }
6009
6010
    $groupId = api_get_group_id();
6011
6012
    if (isset($groupId) && $groupId != '') {
6013
        if (!empty($groupIdParam)) {
6014
            return $groupIdParam == $groupId;
6015
        } else {
6016
            return true;
6017
        }
6018
    }
6019
6020
    return false;
6021
}
6022
6023
/**
6024
 * Checks whether a secret key is valid
6025
 * @param string $original_key_secret  - secret key from (webservice) client
6026
 * @param string $security_key - security key from Chamilo
6027
 * @return boolean - true if secret key is valid, false otherwise
6028
 */
6029
function api_is_valid_secret_key($original_key_secret, $security_key)
6030
{
6031
    return $original_key_secret == sha1($security_key);
6032
}
6033
6034
/**
6035
 * Checks whether a user is into course
6036
 * @param int $course_id - the course id
6037
 * @param int $user_id - the user id
6038
 * @return bool
6039
 */
6040
function api_is_user_of_course($course_id, $user_id)
6041
{
6042
    $tbl_course_rel_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
6043
    $sql = 'SELECT user_id FROM '.$tbl_course_rel_user.'
6044
            WHERE
6045
                c_id ="'.intval($course_id).'" AND
6046
                user_id = "'.intval($user_id).'" AND
6047
                relation_type <> '.COURSE_RELATION_TYPE_RRHH.' ';
6048
    $result = Database::query($sql);
6049
    return Database::num_rows($result) == 1;
6050
}
6051
6052
/**
6053
 * Checks whether the server's operating system is Windows (TM).
6054
 * @return boolean - true if the operating system is Windows, false otherwise
6055
 */
6056
function api_is_windows_os()
6057
{
6058
    if (function_exists('php_uname')) {
6059
        // php_uname() exists as of PHP 4.0.2, according to the documentation.
6060
        // We expect that this function will always work for Chamilo 1.8.x.
6061
        $os = php_uname();
6062
    }
6063
    // The following methods are not needed, but let them stay, just in case.
6064
    elseif (isset($_ENV['OS'])) {
6065
        // Sometimes $_ENV['OS'] may not be present (bugs?)
6066
        $os = $_ENV['OS'];
6067
    } elseif (defined('PHP_OS')) {
6068
        // PHP_OS means on which OS PHP was compiled, this is why
6069
        // using PHP_OS is the last choice for detection.
6070
        $os = PHP_OS;
6071
    } else {
6072
        return false;
6073
    }
6074
    return strtolower(substr((string) $os, 0, 3)) == 'win';
6075
}
6076
6077
/**
6078
 * This function informs whether the sent request is XMLHttpRequest
6079
 */
6080
function api_is_xml_http_request()
6081
{
6082
    return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest';
6083
}
6084
6085
/**
6086
 * This wrapper function has been implemented for avoiding some known problems about the function getimagesize().
6087
 * @link http://php.net/manual/en/function.getimagesize.php
6088
 * @link http://www.dokeos.com/forum/viewtopic.php?t=12345
6089
 * @link http://www.dokeos.com/forum/viewtopic.php?t=16355
6090
 * @return integer
6091
 */
6092
function api_getimagesize($path)
6093
{
6094
    $image = new Image($path);
6095
    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...
6096
}
6097
6098
/**
6099
 * This function resizes an image, with preserving its proportions (or aspect ratio).
6100
 * @author Ivan Tcholakov, MAY-2009.
6101
 * @param int $image            System path or URL of the image
6102
 * @param int $target_width     Targeted width
6103
 * @param int $target_height    Targeted height
6104
 * @return array                Calculated new width and height
6105
 */
6106
function api_resize_image($image, $target_width, $target_height)
6107
{
6108
    $image_properties = api_getimagesize($image);
6109
6110
    return api_calculate_image_size(
6111
        $image_properties['width'],
6112
        $image_properties['height'],
6113
        $target_width,
6114
        $target_height
6115
    );
6116
}
6117
6118
/**
6119
 * This function calculates new image size, with preserving image's proportions (or aspect ratio).
6120
 * @author Ivan Tcholakov, MAY-2009.
6121
 * @author The initial idea has been taken from code by Patrick Cool, MAY-2004.
6122
 * @param int $image_width      Initial width
6123
 * @param int $image_height     Initial height
6124
 * @param int $target_width     Targeted width
6125
 * @param int $target_height    Targeted height
6126
 * @return array                Calculated new width and height
6127
 */
6128
function api_calculate_image_size(
6129
    $image_width,
6130
    $image_height,
6131
    $target_width,
6132
    $target_height
6133
) {
6134
    // Only maths is here.
6135
    $result = ['width' => $image_width, 'height' => $image_height];
6136
    if ($image_width <= 0 || $image_height <= 0) {
6137
        return $result;
6138
    }
6139
    $resize_factor_width = $target_width / $image_width;
6140
    $resize_factor_height = $target_height / $image_height;
6141
    $delta_width = $target_width - $image_width * $resize_factor_height;
6142
    $delta_height = $target_height - $image_height * $resize_factor_width;
6143
    if ($delta_width > $delta_height) {
6144
        $result['width'] = ceil($image_width * $resize_factor_height);
6145
        $result['height'] = ceil($image_height * $resize_factor_height);
6146
    } elseif ($delta_width < $delta_height) {
6147
        $result['width'] = ceil($image_width * $resize_factor_width);
6148
        $result['height'] = ceil($image_height * $resize_factor_width);
6149
    } else {
6150
        $result['width'] = ceil($target_width);
6151
        $result['height'] = ceil($target_height);
6152
    }
6153
    return $result;
6154
}
6155
6156
/**
6157
 * Returns a list of Chamilo's tools or
6158
 * checks whether a given identificator is a valid Chamilo's tool.
6159
 * @author Isaac flores paz
6160
 * @param string The tool name to filter
6161
 * @return mixed Filtered string or array
6162
 */
6163
function api_get_tools_lists($my_tool = null)
6164
{
6165
    $tools_list = [
6166
        TOOL_DOCUMENT,
6167
        TOOL_THUMBNAIL,
6168
        TOOL_HOTPOTATOES,
6169
        TOOL_CALENDAR_EVENT,
6170
        TOOL_LINK,
6171
        TOOL_COURSE_DESCRIPTION,
6172
        TOOL_SEARCH,
6173
        TOOL_LEARNPATH,
6174
        TOOL_ANNOUNCEMENT,
6175
        TOOL_FORUM,
6176
        TOOL_THREAD,
6177
        TOOL_POST,
6178
        TOOL_DROPBOX,
6179
        TOOL_QUIZ,
6180
        TOOL_USER,
6181
        TOOL_GROUP,
6182
        TOOL_BLOGS,
6183
        TOOL_CHAT,
6184
        TOOL_STUDENTPUBLICATION,
6185
        TOOL_TRACKING,
6186
        TOOL_HOMEPAGE_LINK,
6187
        TOOL_COURSE_SETTING,
6188
        TOOL_BACKUP,
6189
        TOOL_COPY_COURSE_CONTENT,
6190
        TOOL_RECYCLE_COURSE,
6191
        TOOL_COURSE_HOMEPAGE,
6192
        TOOL_COURSE_RIGHTS_OVERVIEW,
6193
        TOOL_UPLOAD,
6194
        TOOL_COURSE_MAINTENANCE,
6195
        TOOL_SURVEY,
6196
        TOOL_WIKI,
6197
        TOOL_GLOSSARY,
6198
        TOOL_GRADEBOOK,
6199
        TOOL_NOTEBOOK,
6200
        TOOL_ATTENDANCE,
6201
        TOOL_COURSE_PROGRESS,
6202
    ];
6203
    if (empty($my_tool)) {
6204
        return $tools_list;
6205
    }
6206
    return in_array($my_tool, $tools_list) ? $my_tool : '';
6207
}
6208
6209
/**
6210
 * Checks whether we already approved the last version term and condition
6211
 * @param int user id
6212
 * @return bool true if we pass false otherwise
6213
 */
6214
function api_check_term_condition($userId)
6215
{
6216
    if (api_get_setting('allow_terms_conditions') == 'true') {
6217
        // Check if exists terms and conditions
6218
        if (LegalManager::count() == 0) {
6219
            return true;
6220
        }
6221
6222
        $extraFieldValue = new ExtraFieldValue('user');
6223
        $data = $extraFieldValue->get_values_by_handler_and_field_variable(
6224
            $userId,
6225
            'legal_accept'
6226
        );
6227
6228
        if (!empty($data) && isset($data['value']) && !empty($data['value'])) {
6229
            $result = $data['value'];
6230
            $user_conditions = explode(':', $result);
6231
            $version = $user_conditions[0];
6232
            $lang_id = $user_conditions[1];
6233
            $real_version = LegalManager::get_last_version($lang_id);
6234
6235
            return $version >= $real_version;
6236
        }
6237
        return false;
6238
    }
6239
    return false;
6240
}
6241
6242
/**
6243
 * Gets all information of a tool into course
6244
 * @param int The tool id
6245
 * @return array
6246
 */
6247
function api_get_tool_information_by_name($name)
6248
{
6249
    $t_tool = Database::get_course_table(TABLE_TOOL_LIST);
6250
    $course_id = api_get_course_int_id();
6251
    $sql = "SELECT * FROM $t_tool
6252
            WHERE c_id = $course_id  AND name = '".Database::escape_string($name)."' ";
6253
    $rs  = Database::query($sql);
6254
    return Database::fetch_array($rs, 'ASSOC');
6255
}
6256
6257
/**
6258
 * Function used to protect a "global" admin script.
6259
 * The function blocks access when the user has no global platform admin rights.
6260
 * Global admins are the admins that are registered in the main.admin table
6261
 * AND the users who have access to the "principal" portal.
6262
 * That means that there is a record in the main.access_url_rel_user table
6263
 * with his user id and the access_url_id=1
6264
 *
6265
 * @author Julio Montoya
6266
 * @param integer $user_id
6267
 * @return bool
6268
 */
6269
function api_is_global_platform_admin($user_id = null)
6270
{
6271
    $user_id = intval($user_id);
6272
    if (empty($user_id)) {
6273
        $user_id = api_get_user_id();
6274
    }
6275
    if (api_is_platform_admin_by_id($user_id)) {
6276
        $urlList = api_get_access_url_from_user($user_id);
6277
        // The admin is registered in the first "main" site with access_url_id = 1
6278
        if (in_array(1, $urlList)) {
6279
            return true;
6280
        } else {
6281
            return false;
6282
        }
6283
    }
6284
    return false;
6285
}
6286
6287
/**
6288
 * @param int $admin_id_to_check
6289
 * @param int  $my_user_id
6290
 * @param bool $allow_session_admin
6291
 * @return bool
6292
 */
6293
function api_global_admin_can_edit_admin(
6294
    $admin_id_to_check,
6295
    $my_user_id = null,
6296
    $allow_session_admin = false
6297
) {
6298
    if (empty($my_user_id)) {
6299
        $my_user_id = api_get_user_id();
6300
    }
6301
6302
    $iam_a_global_admin = api_is_global_platform_admin($my_user_id);
6303
    $user_is_global_admin = api_is_global_platform_admin($admin_id_to_check);
6304
6305
    if ($iam_a_global_admin) {
6306
        // Global admin can edit everything
6307
        return true;
6308
    } else {
6309
        // If i'm a simple admin
6310
        $is_platform_admin = api_is_platform_admin_by_id($my_user_id);
6311
6312
        if ($allow_session_admin) {
6313
            $is_platform_admin = api_is_platform_admin_by_id($my_user_id) || (api_get_user_status($my_user_id) == SESSIONADMIN);
6314
        }
6315
6316
        if ($is_platform_admin) {
6317
            if ($user_is_global_admin) {
6318
                return false;
6319
            } else {
6320
                return true;
6321
            }
6322
        } else {
6323
            return false;
6324
        }
6325
    }
6326
}
6327
6328
/**
6329
 * @param int $admin_id_to_check
6330
 * @param int  $my_user_id
6331
 * @param bool $allow_session_admin
6332
 * @return boolean|null
6333
 */
6334
function api_protect_super_admin($admin_id_to_check, $my_user_id = null, $allow_session_admin = false)
6335
{
6336
    if (api_global_admin_can_edit_admin($admin_id_to_check, $my_user_id, $allow_session_admin)) {
6337
        return true;
6338
    } else {
6339
        api_not_allowed();
6340
    }
6341
}
6342
6343
/**
6344
 * Function used to protect a global admin script.
6345
 * The function blocks access when the user has no global platform admin rights.
6346
 * See also the api_is_global_platform_admin() function wich defines who's a "global" admin
6347
 *
6348
 * @author Julio Montoya
6349
 */
6350
function api_protect_global_admin_script()
6351
{
6352
    if (!api_is_global_platform_admin()) {
6353
        api_not_allowed();
6354
        return false;
6355
    }
6356
    return true;
6357
}
6358
6359
/**
6360
 * Get active template
6361
 * @param string    theme type (optional: default)
6362
 * @param string    path absolute(abs) or relative(rel) (optional:rel)
6363
 * @return string   actived template path
6364
 */
6365
function api_get_template($path_type = 'rel')
6366
{
6367
    $path_types = ['rel', 'abs'];
6368
    $template_path = '';
6369
    if (in_array($path_type, $path_types)) {
6370
        if ($path_type == 'rel') {
6371
            $template_path = api_get_path(SYS_TEMPLATE_PATH);
6372
        } else {
6373
            $template_path = api_get_path(WEB_TEMPLATE_PATH);
6374
        }
6375
    }
6376
    $actived_theme = 'default';
6377
    if (api_get_setting('active_template')) {
6378
        $actived_theme = api_get_setting('active_template');
6379
    }
6380
    $actived_theme_path = $template_path.$actived_theme.DIRECTORY_SEPARATOR;
6381
    return $actived_theme_path;
6382
}
6383
6384
/**
6385
 * Check browser support for specific file types or features
6386
 * This function checks if the user's browser supports a file format or given
6387
 * feature, or returns the current browser and major version when
6388
 * $format=check_browser. Only a limited number of formats and features are
6389
 * checked by this method. Make sure you check its definition first.
6390
 * @param string $format Can be a file format (extension like svg, webm, ...) or a feature (like autocapitalize, ...)
6391
 *
6392
 * @return bool or return text array if $format=check_browser
6393
 * @author Juan Carlos Raña Trabado
6394
 */
6395
function api_browser_support($format = '')
6396
{
6397
    $browser = new Browser();
6398
    $current_browser = $browser->getBrowser();
6399
    $a_versiontemp = explode('.', $browser->getVersion());
6400
    $current_majorver = $a_versiontemp[0];
6401
6402
    static $result;
6403
6404
    if (isset($result[$format])) {
6405
        return $result[$format];
6406
    }
6407
6408
    // Native svg support
6409
    if ($format == 'svg') {
6410
        if (($current_browser == 'Internet Explorer' && $current_majorver >= 9) ||
6411
            ($current_browser == 'Firefox' && $current_majorver > 1) ||
6412
            ($current_browser == 'Safari' && $current_majorver >= 4) ||
6413
            ($current_browser == 'Chrome' && $current_majorver >= 1) ||
6414
            ($current_browser == 'Opera' && $current_majorver >= 9)
6415
        ) {
6416
            $result[$format] = true;
6417
            return true;
6418
        } else {
6419
            $result[$format] = false;
6420
            return false;
6421
        }
6422
    } elseif ($format == 'pdf') {
6423
        //native pdf support
6424
        if ($current_browser == 'Chrome' && $current_majorver >= 6) {
6425
            $result[$format] = true;
6426
            return true;
6427
        } else {
6428
            $result[$format] = false;
6429
            return false;
6430
        }
6431
    } elseif ($format == 'tif' || $format == 'tiff') {
6432
        //native tif support
6433
        if ($current_browser == 'Safari' && $current_majorver >= 5) {
6434
            $result[$format] = true;
6435
            return true;
6436
        } else {
6437
            $result[$format] = false;
6438
            return false;
6439
        }
6440
    } elseif ($format == 'ogg' || $format == 'ogx' || $format == 'ogv' || $format == 'oga') {
6441
        //native ogg, ogv,oga support
6442
        if (($current_browser == 'Firefox' && $current_majorver >= 3) ||
6443
            ($current_browser == 'Chrome' && $current_majorver >= 3) ||
6444
            ($current_browser == 'Opera' && $current_majorver >= 9)) {
6445
            $result[$format] = true;
6446
            return true;
6447
        } else {
6448
            $result[$format] = false;
6449
            return false;
6450
        }
6451
    } elseif ($format == 'mpg' || $format == 'mpeg') {
6452
        //native mpg support
6453
        if (($current_browser == 'Safari' && $current_majorver >= 5)) {
6454
            $result[$format] = true;
6455
            return true;
6456
        } else {
6457
            $result[$format] = false;
6458
            return false;
6459
        }
6460
    } elseif ($format == 'mp4') {
6461
        //native mp4 support (TODO: Android, iPhone)
6462
        if ($current_browser == 'Android' || $current_browser == 'iPhone') {
6463
            $result[$format] = true;
6464
            return true;
6465
        } else {
6466
            $result[$format] = false;
6467
            return false;
6468
        }
6469
    } elseif ($format == 'mov') {
6470
        //native mov support( TODO:check iPhone)
6471
        if ($current_browser == 'Safari' && $current_majorver >= 5 || $current_browser == 'iPhone') {
6472
            $result[$format] = true;
6473
            return true;
6474
        } else {
6475
            $result[$format] = false;
6476
            return false;
6477
        }
6478
    } elseif ($format == 'avi') {
6479
        //native avi support
6480
        if ($current_browser == 'Safari' && $current_majorver >= 5) {
6481
            $result[$format] = true;
6482
            return true;
6483
        } else {
6484
            $result[$format] = false;
6485
            return false;
6486
        }
6487
    } elseif ($format == 'wmv') {
6488
        //native wmv support
6489
        if ($current_browser == 'Firefox' && $current_majorver >= 4) {
6490
            $result[$format] = true;
6491
            return true;
6492
        } else {
6493
            $result[$format] = false;
6494
            return false;
6495
        }
6496
    } elseif ($format == 'webm') {
6497
        //native webm support (TODO:check IE9, Chrome9, Android)
6498
        if (($current_browser == 'Firefox' && $current_majorver >= 4) ||
6499
            ($current_browser == 'Opera' && $current_majorver >= 9) ||
6500
            ($current_browser == 'Internet Explorer' && $current_majorver >= 9) ||
6501
            ($current_browser == 'Chrome' && $current_majorver >= 9) ||
6502
            $current_browser == 'Android'
6503
        ) {
6504
            $result[$format] = true;
6505
            return true;
6506
        } else {
6507
            $result[$format] = false;
6508
            return false;
6509
        }
6510
    } elseif ($format == 'wav') {
6511
        //native wav support (only some codecs !)
6512
        if (($current_browser == 'Firefox' && $current_majorver >= 4) ||
6513
            ($current_browser == 'Safari' && $current_majorver >= 5) ||
6514
            ($current_browser == 'Opera' && $current_majorver >= 9) ||
6515
            ($current_browser == 'Internet Explorer' && $current_majorver >= 9) ||
6516
            ($current_browser == 'Chrome' && $current_majorver > 9) ||
6517
            $current_browser == 'Android' ||
6518
            $current_browser == 'iPhone'
6519
        ) {
6520
            $result[$format] = true;
6521
            return true;
6522
        } else {
6523
            $result[$format] = false;
6524
            return false;
6525
        }
6526
    } elseif ($format == 'mid' || $format == 'kar') {
6527
        //native midi support (TODO:check Android)
6528
        if ($current_browser == 'Opera' && $current_majorver >= 9 || $current_browser == 'Android') {
6529
            $result[$format] = true;
6530
            return true;
6531
        } else {
6532
            $result[$format] = false;
6533
            return false;
6534
        }
6535
    } elseif ($format == 'wma') {
6536
        //native wma support
6537
        if ($current_browser == 'Firefox' && $current_majorver >= 4) {
6538
            $result[$format] = true;
6539
            return true;
6540
        } else {
6541
            $result[$format] = false;
6542
            return false;
6543
        }
6544
    } elseif ($format == 'au') {
6545
        //native au support
6546
        if ($current_browser == 'Safari' && $current_majorver >= 5) {
6547
            $result[$format] = true;
6548
            return true;
6549
        } else {
6550
            $result[$format] = false;
6551
            return false;
6552
        }
6553
    } elseif ($format == 'mp3') {
6554
        //native mp3 support (TODO:check Android, iPhone)
6555
        if (($current_browser == 'Safari' && $current_majorver >= 5) ||
6556
            ($current_browser == 'Chrome' && $current_majorver >= 6) ||
6557
            ($current_browser == 'Internet Explorer' && $current_majorver >= 9) ||
6558
            $current_browser == 'Android' ||
6559
            $current_browser == 'iPhone' ||
6560
            $current_browser == 'Firefox'
6561
        ) {
6562
            $result[$format] = true;
6563
            return true;
6564
        } else {
6565
            $result[$format] = false;
6566
            return false;
6567
        }
6568
    } elseif ($format == 'autocapitalize') {
6569
        // Help avoiding showing the autocapitalize option if the browser doesn't
6570
        // support it: this attribute is against the HTML5 standard
6571
        if ($current_browser == 'Safari' || $current_browser == 'iPhone') {
6572
            return true;
6573
        } else {
6574
            return false;
6575
        }
6576
    } elseif ($format == "check_browser") {
6577
        $array_check_browser = [$current_browser, $current_majorver];
6578
        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...
6579
    } else {
6580
        $result[$format] = false;
6581
        return false;
6582
    }
6583
}
6584
6585
/**
6586
 * This function checks if exist path and file browscap.ini
6587
 * In order for this to work, your browscap configuration setting in php.ini
6588
 * must point to the correct location of the browscap.ini file on your system
6589
 * http://php.net/manual/en/function.get-browser.php
6590
 *
6591
 * @return bool
6592
 *
6593
 * @author Juan Carlos Raña Trabado
6594
 */
6595
function api_check_browscap()
6596
{
6597
    $setting = ini_get('browscap');
6598
    if ($setting) {
6599
        $browser = get_browser($_SERVER['HTTP_USER_AGENT'], true);
6600
        if (strpos($setting, 'browscap.ini') && !empty($browser)) {
6601
            return true;
6602
        }
6603
    }
6604
    return false;
6605
}
6606
6607
/**
6608
 * Returns the <script> HTML tag
6609
 */
6610
function api_get_js($file)
6611
{
6612
    return '<script type="text/javascript" src="'.api_get_path(WEB_LIBRARY_PATH).'javascript/'.$file.'"></script>'."\n";
6613
}
6614
6615
/**
6616
 * Returns the <script> HTML tag
6617
 * @return string
6618
 */
6619
function api_get_asset($file)
6620
{
6621
    return '<script type="text/javascript" src="'.api_get_path(WEB_PUBLIC_PATH).'assets/'.$file.'"></script>'."\n";
6622
}
6623
6624
/**
6625
 * Returns the <script> HTML tag
6626
 * @return string
6627
 */
6628
function api_get_css_asset($file, $media = 'screen')
6629
{
6630
    return '<link href="'.api_get_path(WEB_PUBLIC_PATH).'assets/'.$file.'" rel="stylesheet" media="'.$media.'" type="text/css" />'."\n";
6631
}
6632
6633
/**
6634
 * Returns the <link> HTML tag
6635
 * @param string $file
6636
 */
6637
function api_get_css($file, $media = 'screen')
6638
{
6639
    return '<link href="'.$file.'" rel="stylesheet" media="'.$media.'" type="text/css" />'."\n";
6640
}
6641
6642
/**
6643
 * Returns the js header to include the jquery library
6644
 */
6645
function api_get_jquery_js()
6646
{
6647
    return api_get_asset('jquery/dist/jquery.min.js');
6648
}
6649
6650
/**
6651
 * Returns the jquery path
6652
 * @return string
6653
 */
6654
function api_get_jquery_web_path()
6655
{
6656
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery/dist/jquery.min.js';
6657
}
6658
6659
/**
6660
 * @return string
6661
 */
6662
function api_get_jquery_ui_js_web_path()
6663
{
6664
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery-ui/jquery-ui.min.js';
6665
}
6666
6667
/**
6668
 * @return string
6669
 */
6670
function api_get_jquery_ui_css_web_path()
6671
{
6672
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery-ui/themes/smoothness/jquery-ui.min.css';
6673
}
6674
6675
/**
6676
 * Returns the jquery-ui library js headers
6677
 * @param   bool    add the jqgrid library
6678
 * @return  string  html tags
6679
 *
6680
 */
6681
function api_get_jquery_ui_js($include_jqgrid = false)
6682
{
6683
    $libraries = [];
6684
    if ($include_jqgrid) {
6685
        $libraries[] = 'jqgrid';
6686
    }
6687
    return api_get_jquery_libraries_js($libraries);
6688
}
6689
6690
function api_get_jqgrid_js()
6691
{
6692
    return api_get_jquery_libraries_js(['jqgrid']);
6693
}
6694
6695
/**
6696
 * Returns the jquery library js and css headers
6697
 *
6698
 * @param   array   list of jquery libraries supported jquery-ui, jqgrid
6699
 * @param   bool    add the jquery library
6700
 * @return  string  html tags
6701
 *
6702
 */
6703
function api_get_jquery_libraries_js($libraries)
6704
{
6705
    $js = '';
6706
    $js_path = api_get_path(WEB_LIBRARY_PATH).'javascript/';
6707
6708
    //jqgrid js and css
6709
    if (in_array('jqgrid', $libraries)) {
6710
        $languaje = 'en';
6711
        $platform_isocode = strtolower(api_get_language_isocode());
6712
6713
        //languages supported by jqgrid see files in main/inc/lib/javascript/jqgrid/js/i18n
6714
        $jqgrid_langs = [
6715
            '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'
6716
        ];
6717
6718
        if (in_array($platform_isocode, $jqgrid_langs)) {
6719
            $languaje = $platform_isocode;
6720
        }
6721
        //$js .= '<link rel="stylesheet" href="'.$js_path.'jqgrid/css/ui.jqgrid.css" type="text/css">';
6722
        $js .= api_get_css($js_path.'jqgrid/css/ui.jqgrid.css');
6723
        $js .= api_get_js('jqgrid/js/i18n/grid.locale-'.$languaje.'.js');
6724
        $js .= api_get_js('jqgrid/js/jquery.jqGrid.min.js');
6725
    }
6726
6727
    //Document multiple upload funcionality
6728
    if (in_array('jquery-uploadzs', $libraries)) {
6729
        $js .= api_get_asset('blueimp-load-image/js/load-image.all.min.js');
6730
        $js .= api_get_asset('blueimp-canvas-to-blob/js/canvas-to-blob.min.js');
6731
        $js .= api_get_asset('jquery-file-upload/js/jquery.iframe-transport.js');
6732
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload.js');
6733
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-process.js');
6734
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-image.js');
6735
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-audio.js');
6736
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-video.js');
6737
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-validate.js');
6738
6739
        $js .= api_get_css(api_get_path(WEB_PUBLIC_PATH).'assets/jquery-file-upload/css/jquery.fileupload.css');
6740
        $js .= api_get_css(api_get_path(WEB_PUBLIC_PATH).'assets/jquery-file-upload/css/jquery.fileupload-ui.css');
6741
    }
6742
6743
    // jquery datepicker
6744
    if (in_array('datepicker', $libraries)) {
6745
        $languaje = 'en-GB';
6746
        $platform_isocode = strtolower(api_get_language_isocode());
6747
6748
        // languages supported by jqgrid see files in main/inc/lib/javascript/jqgrid/js/i18n
6749
        $datapicker_langs = [
6750
            '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'
6751
        ];
6752
        if (in_array($platform_isocode, $datapicker_langs)) {
6753
            $languaje = $platform_isocode;
6754
        }
6755
6756
        $js .= api_get_js('jquery-ui/jquery-ui-i18n.min.js');
6757
        $script = '<script>
6758
        $(function(){
6759
            $.datepicker.setDefaults($.datepicker.regional["'.$languaje.'"]);
6760
            $.datepicker.regional["local"] = $.datepicker.regional["'.$languaje.'"];
6761
        });
6762
        </script>
6763
        ';
6764
        $js .= $script;
6765
    }
6766
    return $js;
6767
}
6768
6769
/**
6770
 * Returns the course's URL
6771
 *
6772
 * This function relies on api_get_course_info()
6773
 * @param   string  The course code - optional (takes it from session if not given)
6774
 * @param   int     The session id  - optional (takes it from session if not given)
6775
 * @param integer $session_id
6776
 * @return  string|null   The URL of the course or null if something does not work
6777
 * @author  Julio Montoya <[email protected]>
6778
 */
6779
function api_get_course_url($course_code = null, $session_id = null)
6780
{
6781
    if (empty($course_code)) {
6782
        $course_info = api_get_course_info();
6783
    } else {
6784
        $course_info = api_get_course_info($course_code);
6785
    }
6786
    if (empty($session_id)) {
6787
        $session_url = '?id_session='.api_get_session_id();
6788
    } else {
6789
        $session_url = '?id_session='.intval($session_id);
6790
    }
6791
    /*
6792
    if (empty($group_id)) {
6793
        $group_url = '&gidReq='.api_get_group_id();
6794
    } else {
6795
        $group_url = '&gidReq='.intval($group_id);
6796
    }*/
6797
    if (!empty($course_info['path'])) {
6798
        return api_get_path(WEB_COURSE_PATH).$course_info['path'].'/index.php'.$session_url;
6799
    }
6800
    return null;
6801
}
6802
6803
/**
6804
 *
6805
 * Check if the current portal has the $_configuration['multiple_access_urls'] parameter on
6806
 * @return bool true if multi site is enabled
6807
 *
6808
 **/
6809
function api_get_multiple_access_url()
6810
{
6811
    global $_configuration;
6812
    if (isset($_configuration['multiple_access_urls']) && $_configuration['multiple_access_urls']) {
6813
        return true;
6814
    }
6815
    return false;
6816
}
6817
6818
/**
6819
 * @return bool
6820
 */
6821
function api_is_multiple_url_enabled()
6822
{
6823
    return api_get_multiple_access_url();
6824
}
6825
6826
/**
6827
 * Returns a md5 unique id
6828
 * @todo add more parameters
6829
 */
6830
function api_get_unique_id()
6831
{
6832
    $id = md5(time().uniqid().api_get_user_id().api_get_course_id().api_get_session_id());
6833
    return $id;
6834
}
6835
6836
/**
6837
 * Get home path
6838
 * @return string
6839
 */
6840
function api_get_home_path()
6841
{
6842
    // FIX : Start the routing determination from central path definition
6843
    $home = api_get_path(SYS_HOME_PATH);
6844
    if (api_get_multiple_access_url()) {
6845
        $access_url_id = api_get_current_access_url_id();
6846
        $url_info = api_get_access_url($access_url_id);
6847
        $url = api_remove_trailing_slash(preg_replace('/https?:\/\//i', '', $url_info['url']));
6848
        $clean_url = api_replace_dangerous_char($url);
6849
        $clean_url = str_replace('/', '-', $clean_url);
6850
        $clean_url .= '/';
6851
        if ($clean_url != 'localhost/') {
6852
            // means that the multiple URL was not well configured we don't rename the $home variable
6853
            return "{$home}{$clean_url}";
6854
        }
6855
    }
6856
6857
    return $home;
6858
}
6859
6860
/**
6861
 *
6862
 * @param int Course id
6863
 * @param int tool id: TOOL_QUIZ, TOOL_FORUM, TOOL_STUDENTPUBLICATION, TOOL_LEARNPATH
6864
 * @param int the item id (tool id, exercise id, lp id)
6865
 * @return bool
6866
 */
6867
function api_resource_is_locked_by_gradebook($item_id, $link_type, $course_code = null)
6868
{
6869
    if (api_is_platform_admin()) {
6870
        return false;
6871
    }
6872
    if (api_get_setting('gradebook_locking_enabled') == 'true') {
6873
        if (empty($course_code)) {
6874
            $course_code = api_get_course_id();
6875
        }
6876
        $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_LINK);
6877
        $item_id = intval($item_id);
6878
        $link_type = intval($link_type);
6879
        $course_code = Database::escape_string($course_code);
6880
        $sql = "SELECT locked FROM $table
6881
                WHERE locked = 1 AND ref_id = $item_id AND type = $link_type AND course_code = '$course_code' ";
6882
        $result = Database::query($sql);
6883
        if (Database::num_rows($result)) {
6884
            return true;
6885
        }
6886
    }
6887
    return false;
6888
}
6889
6890
/**
6891
 * Blocks a page if the item was added in a gradebook
6892
 *
6893
 * @param int       exercise id, work id, thread id,
6894
 * @param int       LINK_EXERCISE, LINK_STUDENTPUBLICATION, LINK_LEARNPATH LINK_FORUM_THREAD, LINK_ATTENDANCE
6895
 * see gradebook/lib/be/linkfactory
6896
 * @param string    course code
6897
 * @return false|null
6898
 */
6899
function api_block_course_item_locked_by_gradebook($item_id, $link_type, $course_code = null)
6900
{
6901
    if (api_is_platform_admin()) {
6902
        return false;
6903
    }
6904
6905
    if (api_resource_is_locked_by_gradebook($item_id, $link_type, $course_code)) {
6906
        $message = Display::return_message(get_lang('ResourceLockedByGradebook'), 'warning');
6907
        api_not_allowed(true, $message);
6908
    }
6909
}
6910
6911
/**
6912
 * Checks the PHP version installed is enough to run Chamilo
6913
 * @param string Include path (used to load the error page)
6914
 * @return void
6915
 */
6916
function api_check_php_version($my_inc_path = null)
6917
{
6918
    if (!function_exists('version_compare') || version_compare(phpversion(), REQUIRED_PHP_VERSION, '<')) {
6919
        $global_error_code = 1;
6920
        // Incorrect PHP version
6921
        $global_page = $my_inc_path.'global_error_message.inc.php';
6922
        if (file_exists($global_page)) {
6923
            require $global_page;
6924
        }
6925
        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...
6926
    }
6927
}
6928
6929
/**
6930
 * Checks whether the Archive directory is present and writeable. If not,
6931
 * prints a warning message.
6932
 */
6933
function api_check_archive_dir()
6934
{
6935
    if (is_dir(api_get_path(SYS_ARCHIVE_PATH)) && !is_writable(api_get_path(SYS_ARCHIVE_PATH))) {
6936
        $message = Display::return_message(get_lang('ArchivesDirectoryNotWriteableContactAdmin'), 'warning');
6937
        api_not_allowed(true, $message);
6938
    }
6939
}
6940
6941
/**
6942
 * Returns an array of global configuration settings which should be ignored
6943
 * when printing the configuration settings screens
6944
 * @return array Array of strings, each identifying one of the excluded settings
6945
 */
6946
function api_get_locked_settings()
6947
{
6948
    return [
6949
        'server_type',
6950
        'permanently_remove_deleted_files',
6951
        'account_valid_duration',
6952
        'service_ppt2lp',
6953
        'wcag_anysurfer_public_pages',
6954
        'upload_extensions_list_type',
6955
        'upload_extensions_blacklist',
6956
        'upload_extensions_whitelist',
6957
        'upload_extensions_skip',
6958
        'upload_extensions_replace_by',
6959
        'hide_dltt_markup',
6960
        'split_users_upload_directory',
6961
        'permissions_for_new_directories',
6962
        'permissions_for_new_files',
6963
        'platform_charset',
6964
        'ldap_description',
6965
        'cas_activate',
6966
        'cas_server',
6967
        'cas_server_uri',
6968
        'cas_port',
6969
        'cas_protocol',
6970
        'cas_add_user_activate',
6971
        'update_user_info_cas_with_ldap',
6972
        'languagePriority1',
6973
        'languagePriority2',
6974
        'languagePriority3',
6975
        'languagePriority4',
6976
        'login_is_email',
6977
        'chamilo_database_version'
6978
    ];
6979
}
6980
6981
/**
6982
 * Checks if the user is corrently logged in. Returns the user ID if he is, or
6983
 * false if he isn't. If the user ID is given and is an integer, then the same
6984
 * ID is simply returned
6985
 * @param  integer User ID
6986
 * @return boolean Integer User ID is logged in, or false otherwise
6987
 */
6988
function api_user_is_login($user_id = null)
6989
{
6990
    $user_id = empty($user_id) ? api_get_user_id() : intval($user_id);
6991
    return $user_id && !api_is_anonymous();
6992
}
6993
6994
/**
6995
 * Guess the real ip for register in the database, even in reverse proxy cases.
6996
 * To be recognized, the IP has to be found in either $_SERVER['REMOTE_ADDR'] or
6997
 * in $_SERVER['HTTP_X_FORWARDED_FOR'], which is in common use with rproxies.
6998
 * @return string the user's real ip (unsafe - escape it before inserting to db)
6999
 * @author Jorge Frisancho Jibaja <[email protected]>, USIL - Some changes to allow the use of real IP using reverse proxy
7000
 * @version CEV CHANGE 24APR2012
7001
 */
7002
function api_get_real_ip()
7003
{
7004
    // Guess the IP if behind a reverse proxy
7005
    global $debug;
7006
    $ip = trim($_SERVER['REMOTE_ADDR']);
7007
    if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
7008
        if (preg_match('/,/', $_SERVER['HTTP_X_FORWARDED_FOR'])) {
7009
            @list($ip1, $ip2) = @explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
7010
        } else {
7011
            $ip1 = $_SERVER['HTTP_X_FORWARDED_FOR'];
7012
        }
7013
        $ip = trim($ip1);
7014
    }
7015
    if (!empty($debug)) {
7016
        error_log('Real IP: '.$ip);
7017
    }
7018
    return $ip;
7019
}
7020
7021
/**
7022
 * Checks whether an IP is included inside an IP range
7023
 * @param string IP address
7024
 * @param string IP range
7025
 * @param string $ip
7026
 * @return bool True if IP is in the range, false otherwise
7027
 * @author claudiu at cnixs dot com  on http://www.php.net/manual/fr/ref.network.php#55230
7028
 * @author Yannick Warnier for improvements and managment of multiple ranges
7029
 * @todo check for IPv6 support
7030
 */
7031
function api_check_ip_in_range($ip, $range)
7032
{
7033
    if (empty($ip) or empty($range)) {
7034
        return false;
7035
    }
7036
    $ip_ip = ip2long($ip);
7037
    // divide range param into array of elements
7038
    if (strpos($range, ',') !== false) {
7039
        $ranges = explode(',', $range);
7040
    } else {
7041
        $ranges = [$range];
7042
    }
7043
    foreach ($ranges as $range) {
7044
        $range = trim($range);
7045
        if (empty($range)) {
7046
            continue;
7047
        }
7048
        if (strpos($range, '/') === false) {
7049
            if (strcmp($ip, $range) === 0) {
7050
                return true; // there is a direct IP match, return OK
7051
            }
7052
            continue; //otherwise, get to the next range
7053
        }
7054
        // the range contains a "/", so analyse completely
7055
        list($net, $mask) = explode("/", $range);
7056
7057
        $ip_net = ip2long($net);
7058
        // mask binary magic
7059
        $ip_mask = ~((1 << (32 - $mask)) - 1);
7060
7061
        $ip_ip_net = $ip_ip & $ip_mask;
7062
        if ($ip_ip_net == $ip_net) {
7063
            return true;
7064
        }
7065
    }
7066
7067
    return false;
7068
}
7069
7070
function api_check_user_access_to_legal($course_visibility)
7071
{
7072
    $course_visibility_list = [COURSE_VISIBILITY_OPEN_WORLD, COURSE_VISIBILITY_OPEN_PLATFORM];
7073
    return in_array($course_visibility, $course_visibility_list) || api_is_drh();
7074
}
7075
7076
/**
7077
 * Checks if the global chat is enabled or not
7078
 *
7079
 * @return bool
7080
 */
7081
function api_is_global_chat_enabled()
7082
{
7083
    return
7084
        !api_is_anonymous() &&
7085
        api_get_setting('allow_global_chat') == 'true' &&
7086
        api_get_setting('allow_social_tool') == 'true';
7087
}
7088
7089
/**
7090
 * @todo Fix tool_visible_by_default_at_creation labels
7091
 * @todo Add sessionId parameter to avoid using context
7092
 *
7093
 * @param int $item_id
7094
 * @param int $tool_id
7095
 * @param int $group_id id
7096
 * @param array $courseInfo
7097
 * @param int $sessionId
7098
 * @param int $userId
7099
 */
7100
function api_set_default_visibility(
7101
    $item_id,
7102
    $tool_id,
7103
    $group_id = 0,
7104
    $courseInfo = [],
7105
    $sessionId = 0,
7106
    $userId = 0
7107
) {
7108
    $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
7109
    $courseId = $courseInfo['real_id'];
7110
    $courseCode = $courseInfo['code'];
7111
    $sessionId = empty($sessionId) ? api_get_session_id() : $sessionId;
7112
    $userId = empty($userId) ? api_get_user_id() : $userId;
7113
7114
    if (empty($group_id)) {
7115
        $group_id = api_get_group_id();
7116
    }
7117
7118
    $groupInfo = GroupManager::get_group_properties($group_id);
7119
    $original_tool_id = $tool_id;
7120
7121
    switch ($tool_id) {
7122
        case TOOL_LINK:
7123
        case TOOL_LINK_CATEGORY:
7124
            $tool_id = 'links';
7125
            break;
7126
        case TOOL_DOCUMENT:
7127
            $tool_id = 'documents';
7128
            break;
7129
        case TOOL_LEARNPATH:
7130
            $tool_id = 'learning';
7131
            break;
7132
        case TOOL_ANNOUNCEMENT:
7133
            $tool_id = 'announcements';
7134
            break;
7135
        case TOOL_FORUM:
7136
        case TOOL_FORUM_CATEGORY:
7137
        case TOOL_FORUM_THREAD:
7138
            $tool_id = 'forums';
7139
            break;
7140
        case TOOL_QUIZ:
7141
            $tool_id = 'quiz';
7142
            break;
7143
    }
7144
    $setting = api_get_setting('tool_visible_by_default_at_creation');
7145
7146
    if (isset($setting[$tool_id])) {
7147
        $visibility = 'invisible';
7148
        if ($setting[$tool_id] == 'true') {
7149
            $visibility = 'visible';
7150
        }
7151
7152
        // Read the portal and course default visibility
7153
        if ($tool_id == 'documents') {
7154
            $visibility = DocumentManager::getDocumentDefaultVisibility($courseCode);
7155
        }
7156
7157
        api_item_property_update(
7158
            $courseInfo,
7159
            $original_tool_id,
7160
            $item_id,
7161
            $visibility,
7162
            $userId,
7163
            $groupInfo,
7164
            null,
7165
            null,
7166
            null,
7167
            $sessionId
7168
        );
7169
7170
        // Fixes default visibility for tests
7171
        switch ($original_tool_id) {
7172
            case TOOL_QUIZ:
7173
                if (empty($sessionId)) {
7174
                    $objExerciseTmp = new Exercise($courseId);
7175
                    $objExerciseTmp->read($item_id);
7176
                    if ($visibility == 'visible') {
7177
                        $objExerciseTmp->enable();
7178
                        $objExerciseTmp->save();
7179
                    } else {
7180
                        $objExerciseTmp->disable();
7181
                        $objExerciseTmp->save();
7182
                    }
7183
                }
7184
                break;
7185
        }
7186
    }
7187
}
7188
7189
/**
7190
 * @return string
7191
 */
7192
function api_get_security_key()
7193
{
7194
    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') could also return false which is incompatible with the documented return type string. 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...
7195
}
7196
7197
/**
7198
 * @param int $user_id
7199
 * @param int $courseId
7200
 * @param int $session_id
7201
 * @return array
7202
 */
7203
function api_detect_user_roles($user_id, $courseId, $session_id = 0)
7204
{
7205
    $user_roles = [];
7206
    $courseInfo = api_get_course_info_by_id($courseId);
7207
    $course_code = $courseInfo['code'];
7208
7209
    $url_id = api_get_current_access_url_id();
7210
    if (api_is_platform_admin_by_id($user_id, $url_id)) {
7211
        $user_roles[] = PLATFORM_ADMIN;
7212
    }
7213
7214
    /*if (api_is_drh()) {
7215
        $user_roles[] = DRH;
7216
    }*/
7217
7218
    if (!empty($session_id)) {
7219
        if (SessionManager::user_is_general_coach($user_id, $session_id)) {
7220
            $user_roles[] = SESSION_GENERAL_COACH;
7221
        }
7222
    }
7223
7224
    if (!empty($course_code)) {
7225
        if (empty($session_id)) {
7226
            if (CourseManager::is_course_teacher($user_id, $course_code)) {
7227
                $user_roles[] = COURSEMANAGER;
7228
            }
7229
            if (CourseManager::get_tutor_in_course_status($user_id, $courseInfo['real_id'])) {
7230
                $user_roles[] = COURSE_TUTOR;
7231
            }
7232
7233
            if (CourseManager::is_user_subscribed_in_course($user_id, $course_code)) {
7234
                $user_roles[] = COURSE_STUDENT;
7235
            }
7236
        } else {
7237
            $user_status_in_session = SessionManager::get_user_status_in_course_session(
7238
                $user_id,
7239
                $courseId,
7240
                $session_id
7241
            );
7242
7243
            if (!empty($user_status_in_session)) {
7244
                if ($user_status_in_session == 0) {
7245
                    $user_roles[] = SESSION_STUDENT;
7246
                }
7247
                if ($user_status_in_session == 2) {
7248
                    $user_roles[] = SESSION_COURSE_COACH;
7249
                }
7250
            }
7251
7252
            /*if (api_is_course_session_coach($user_id, $course_code, $session_id)) {
7253
               $user_roles[] = SESSION_COURSE_COACH;
7254
            }*/
7255
        }
7256
    }
7257
    return $user_roles;
7258
}
7259
7260
/**
7261
 * @param int $courseId
7262
 * @param int $session_id
7263
 * @return bool
7264
 */
7265
function api_coach_can_edit_view_results($courseId = null, $session_id = null)
7266
{
7267
    if (api_is_platform_admin()) {
7268
        return true;
7269
    }
7270
7271
    $user_id = api_get_user_id();
7272
7273
    if (empty($courseId)) {
7274
        $courseId = api_get_course_int_id();
7275
    }
7276
7277
    if (empty($session_id)) {
7278
        $session_id = api_get_session_id();
7279
    }
7280
7281
    $roles = api_detect_user_roles($user_id, $courseId, $session_id);
7282
7283
    if (in_array(SESSION_COURSE_COACH, $roles)) {
7284
        //return api_get_setting('session_tutor_reports_visibility') == 'true';
7285
        return true;
7286
    } else {
7287
        if (in_array(COURSEMANAGER, $roles)) {
7288
            return true;
7289
        }
7290
        return false;
7291
    }
7292
}
7293
7294
/**
7295
 * @param string $file
7296
 * @return string
7297
 */
7298
function api_get_js_simple($file)
7299
{
7300
    return '<script type="text/javascript" src="'.$file.'"></script>'."\n";
7301
}
7302
7303
function api_set_settings_and_plugins()
7304
{
7305
    global $_configuration;
7306
    $_setting = [];
7307
    $_plugins = [];
7308
7309
    // access_url == 1 is the default chamilo location
7310
    $settings_by_access_list = [];
7311
    $access_url_id = api_get_current_access_url_id();
7312
    if ($access_url_id != 1) {
7313
        $url_info = api_get_access_url($_configuration['access_url']);
7314
        if ($url_info['active'] == 1) {
7315
            $settings_by_access = & api_get_settings(null, 'list', $_configuration['access_url'], 1);
7316
            foreach ($settings_by_access as & $row) {
7317
                if (empty($row['variable'])) {
7318
                    $row['variable'] = 0;
7319
                }
7320
                if (empty($row['subkey'])) {
7321
                    $row['subkey'] = 0;
7322
                }
7323
                if (empty($row['category'])) {
7324
                    $row['category'] = 0;
7325
                }
7326
                $settings_by_access_list[$row['variable']][$row['subkey']][$row['category']] = $row;
7327
            }
7328
        }
7329
    }
7330
7331
    $result = api_get_settings(null, 'list', 1);
7332
7333
    foreach ($result as & $row) {
7334
        if ($access_url_id != 1) {
7335
            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...
7336
                $var = empty($row['variable']) ? 0 : $row['variable'];
7337
                $subkey = empty($row['subkey']) ? 0 : $row['subkey'];
7338
                $category = empty($row['category']) ? 0 : $row['category'];
7339
            }
7340
7341
            if ($row['access_url_changeable'] == 1 && $url_info['active'] == 1) {
7342
                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...
7343
                    $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...
7344
                    if ($row['subkey'] == null) {
7345
                        $_setting[$row['variable']] = $settings_by_access_list[$var][$subkey][$category]['selected_value'];
7346
                    } else {
7347
                        $_setting[$row['variable']][$row['subkey']] = $settings_by_access_list[$var][$subkey][$category]['selected_value'];
7348
                    }
7349
                } else {
7350
                    if ($row['subkey'] == null) {
7351
                        $_setting[$row['variable']] = $row['selected_value'];
7352
                    } else {
7353
                        $_setting[$row['variable']][$row['subkey']] = $row['selected_value'];
7354
                    }
7355
                }
7356
            } else {
7357
                if ($row['subkey'] == null) {
7358
                    $_setting[$row['variable']] = $row['selected_value'];
7359
                } else {
7360
                    $_setting[$row['variable']][$row['subkey']] = $row['selected_value'];
7361
                }
7362
            }
7363
        } else {
7364
            if ($row['subkey'] == null) {
7365
                $_setting[$row['variable']] = $row['selected_value'];
7366
            } else {
7367
                $_setting[$row['variable']][$row['subkey']] = $row['selected_value'];
7368
            }
7369
        }
7370
    }
7371
7372
    $result = api_get_settings('Plugins', 'list', $access_url_id);
7373
    $_plugins = [];
7374
    foreach ($result as & $row) {
7375
        $key = & $row['variable'];
7376
        if (is_string($_setting[$key])) {
7377
            $_setting[$key] = [];
7378
        }
7379
        $_setting[$key][] = $row['selected_value'];
7380
        $_plugins[$key][] = $row['selected_value'];
7381
    }
7382
7383
    $_SESSION['_setting'] = $_setting;
7384
    $_SESSION['_plugins'] = $_plugins;
7385
}
7386
7387
/**
7388
 * Tries to set memory limit, if authorized and new limit is higher than current
7389
 * @param string $mem New memory limit
7390
 * @return bool True on success, false on failure or current is higher than suggested
7391
 * @assert (null) === false
7392
 * @assert (-1) === false
7393
 * @assert (0) === true
7394
 * @assert ('1G') === true
7395
 */
7396
function api_set_memory_limit($mem)
7397
{
7398
    //if ini_set() not available, this function is useless
7399
    if (!function_exists('ini_set') || is_null($mem) || $mem == -1) {
7400
        return false;
7401
    }
7402
7403
    $memory_limit = ini_get('memory_limit');
7404
    if (api_get_bytes_memory_limit($mem) > api_get_bytes_memory_limit($memory_limit)) {
7405
        ini_set('memory_limit', $mem);
7406
        return true;
7407
    }
7408
    return false;
7409
}
7410
7411
/**
7412
 * Gets memory limit in bytes
7413
 * @param string The memory size (128M, 1G, 1000K, etc)
7414
 * @return int
7415
 * @assert (null) === false
7416
 * @assert ('1t')  === 1099511627776
7417
 * @assert ('1g')  === 1073741824
7418
 * @assert ('1m')  === 1048576
7419
 * @assert ('100k') === 102400
7420
 */
7421
function api_get_bytes_memory_limit($mem)
7422
{
7423
    $size = strtolower(substr($mem, -1));
7424
7425
    switch ($size) {
7426
        case 't':
7427
            $mem = intval(substr($mem, -1)) * 1024 * 1024 * 1024 * 1024;
7428
            break;
7429
        case 'g':
7430
            $mem = intval(substr($mem, 0, -1)) * 1024 * 1024 * 1024;
7431
            break;
7432
        case 'm':
7433
            $mem = intval(substr($mem, 0, -1)) * 1024 * 1024;
7434
            break;
7435
        case 'k':
7436
            $mem = intval(substr($mem, 0, -1)) * 1024;
7437
            break;
7438
        default:
7439
            // we assume it's integer only
7440
            $mem = intval($mem);
7441
            break;
7442
    }
7443
    return $mem;
7444
}
7445
7446
/**
7447
 * Finds all the information about a user from username instead of user id
7448
 *
7449
 * @param string $officialCode
7450
 * @return array $user_info user_id, lastname, firstname, username, email, ...
7451
 * @author Yannick Warnier <[email protected]>
7452
 */
7453
function api_get_user_info_from_official_code($officialCode)
7454
{
7455
    if (empty($officialCode)) {
7456
        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...
7457
    }
7458
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
7459
            WHERE official_code ='".Database::escape_string($officialCode)."'";
7460
    $result = Database::query($sql);
7461
    if (Database::num_rows($result) > 0) {
7462
        $result_array = Database::fetch_array($result);
7463
        return _api_format_user($result_array);
7464
    }
7465
    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...
7466
}
7467
7468
/**
7469
 * @param string $usernameInputId
7470
 * @param string $passwordInputId
7471
 * @return null|string
7472
 */
7473
function api_get_password_checker_js($usernameInputId, $passwordInputId)
7474
{
7475
    $checkPass = api_get_setting('allow_strength_pass_checker');
7476
    $useStrengthPassChecker = $checkPass === 'true';
7477
7478
    if ($useStrengthPassChecker === false) {
7479
        return null;
7480
    }
7481
7482
    $translations = [
7483
        'wordLength' => get_lang('PasswordIsTooShort'),
7484
        'wordNotEmail' => get_lang('YourPasswordCannotBeTheSameAsYourEmail'),
7485
        'wordSimilarToUsername' => get_lang('YourPasswordCannotContainYourUsername'),
7486
        'wordTwoCharacterClasses' => get_lang('WordTwoCharacterClasses'),
7487
        'wordRepetitions' => get_lang('TooManyRepetitions'),
7488
        'wordSequences' => get_lang('YourPasswordContainsSequences'),
7489
        'errorList' => get_lang('ErrorsFound'),
7490
        'veryWeak' => get_lang('PasswordVeryWeak'),
7491
        'weak' => get_lang('PasswordWeak'),
7492
        'normal' => get_lang('PasswordNormal'),
7493
        'medium' => get_lang('PasswordMedium'),
7494
        'strong' => get_lang('PasswordStrong'),
7495
        'veryStrong' => get_lang('PasswordVeryStrong')
7496
    ];
7497
7498
    $js = api_get_asset('pwstrength-bootstrap/dist/pwstrength-bootstrap.min.js');
7499
    $js .= "<script>    
7500
    var errorMessages = {
7501
        password_to_short : \"" . get_lang('PasswordIsTooShort')."\",
7502
        same_as_username : \"".get_lang('YourPasswordCannotBeTheSameAsYourUsername')."\"
7503
    };
7504
7505
    $(document).ready(function() {
7506
        var lang = ".json_encode($translations).";     
7507
        var options = {        
7508
            onLoad : function () {
7509
                //$('#messages').text('Start typing password');
7510
            },
7511
            onKeyUp: function (evt) {
7512
                $(evt.target).pwstrength('outputErrorList');
7513
            },
7514
            errorMessages : errorMessages,
7515
            viewports: {
7516
                progress: '#password_progress',
7517
                verdict: '#password-verdict',
7518
                errors: '#password-errors'
7519
            },
7520
            usernameField: '$usernameInputId'
7521
        };
7522
        options.i18n = {
7523
            t: function (key) {
7524
                var result = lang[key];
7525
                return result === key ? '' : result; // This assumes you return the                
7526
            }
7527
        };
7528
        $('".$passwordInputId."').pwstrength(options);
7529
    });
7530
    </script>";
7531
7532
    return $js;
7533
}
7534
7535
/**
7536
 * create an user extra field called 'captcha_blocked_until_date'
7537
 * @param string $username
7538
 * @return bool
7539
 */
7540
function api_block_account_captcha($username)
7541
{
7542
    $userInfo = api_get_user_info_from_username($username);
7543
    if (empty($userInfo)) {
7544
        return false;
7545
    }
7546
    $minutesToBlock = api_get_setting('captcha_time_to_block');
7547
    $time = time() + $minutesToBlock * 60;
7548
    UserManager::update_extra_field_value(
7549
        $userInfo['user_id'],
7550
        'captcha_blocked_until_date',
7551
        api_get_utc_datetime($time)
7552
    );
7553
    return true;
7554
}
7555
7556
/**
7557
 * @param string $username
7558
 * @return bool
7559
 */
7560
function api_clean_account_captcha($username)
7561
{
7562
    $userInfo = api_get_user_info_from_username($username);
7563
    if (empty($userInfo)) {
7564
        return false;
7565
    }
7566
    Session::erase('loginFailedCount');
7567
    UserManager::update_extra_field_value(
7568
        $userInfo['user_id'],
7569
        'captcha_blocked_until_date',
7570
        null
7571
    );
7572
    return true;
7573
}
7574
7575
/**
7576
 * @param string $username
7577
 * @return bool
7578
 */
7579
function api_get_user_blocked_by_captcha($username)
7580
{
7581
    $userInfo = api_get_user_info_from_username($username);
7582
    if (empty($userInfo)) {
7583
        return false;
7584
    }
7585
    $data = UserManager::get_extra_user_data_by_field(
7586
        $userInfo['user_id'],
7587
        'captcha_blocked_until_date'
7588
    );
7589
    if (isset($data) && isset($data['captcha_blocked_until_date'])) {
7590
        return $data['captcha_blocked_until_date'];
7591
    }
7592
    return false;
7593
}
7594
7595
/**
7596
 * Remove tags from HTML anf return the $in_number_char first non-HTML char
7597
 * Postfix the text with "..." if it has been truncated.
7598
 * @param string $text
7599
 * @param integer $number
7600
 *
7601
 * @return string
7602
 * @author hubert borderiou
7603
 */
7604
function api_get_short_text_from_html($text, $number)
7605
{
7606
    // Delete script and style tags
7607
    $text =  preg_replace('/(<(script|style)\b[^>]*>).*?(<\/\2>)/is', "$1$3", $text);
7608
    $text = api_html_entity_decode($text);
7609
    $out_res = api_remove_tags_with_space($text, false);
7610
    $postfix = "...";
7611
    if (strlen($out_res) > $number) {
7612
        $out_res = substr($out_res, 0, $number).$postfix;
7613
    }
7614
    return $out_res;
7615
}
7616
7617
/**
7618
 * Replace tags with a space in a text.
7619
 * If $in_double_quote_replace, replace " with '' (for HTML attribute purpose, for exemple)
7620
 * @return string
7621
 * @author hubert borderiou
7622
 */
7623
function api_remove_tags_with_space($in_html, $in_double_quote_replace = true)
7624
{
7625
    $out_res = $in_html;
7626
    if ($in_double_quote_replace) {
7627
        $out_res = str_replace('"', "''", $out_res);
7628
    }
7629
    // avoid text stuck together when tags are removed, adding a space after >
7630
    $out_res = str_replace(">", "> ", $out_res);
7631
    $out_res = strip_tags($out_res);
7632
7633
    return $out_res;
7634
}
7635
7636
/**
7637
 * If true, the drh can access all content (courses, users) inside a session
7638
 * @return bool
7639
 */
7640
function api_drh_can_access_all_session_content()
7641
{
7642
    $value = api_get_setting('drh_can_access_all_session_content');
7643
7644
    return $value === 'true';
7645
}
7646
7647
/**
7648
 * @param string $tool
7649
 * @param string $setting
7650
 * @param integer $defaultValue
7651
 * @return string
7652
 */
7653
function api_get_default_tool_setting($tool, $setting, $defaultValue)
7654
{
7655
    global $_configuration;
7656
    if (isset($_configuration[$tool]) &&
7657
        isset($_configuration[$tool]['default_settings']) &&
7658
        isset($_configuration[$tool]['default_settings'][$setting])
7659
    ) {
7660
        return $_configuration[$tool]['default_settings'][$setting];
7661
    }
7662
7663
    return $defaultValue;
7664
}
7665
7666
/**
7667
 * Checks if user can login as another user
7668
 *
7669
 * @param int $loginAsUserId the user id to log in
7670
 * @param int $userId my user id
7671
 * @return bool
7672
 */
7673
function api_can_login_as($loginAsUserId, $userId = null)
7674
{
7675
    if (empty($userId)) {
7676
        $userId = api_get_user_id();
7677
    }
7678
    if ($loginAsUserId == $userId) {
7679
        return false;
7680
    }
7681
7682
    if (empty($loginAsUserId)) {
7683
        return false;
7684
    }
7685
7686
    if ($loginAsUserId != strval(intval($loginAsUserId))) {
7687
        return false;
7688
    }
7689
7690
    // Check if the user to login is an admin
7691
    if (api_is_platform_admin_by_id($loginAsUserId)) {
7692
        // Only super admins can login to admin accounts
7693
        if (!api_global_admin_can_edit_admin($loginAsUserId)) {
7694
            return false;
7695
        }
7696
    }
7697
7698
    $userInfo = api_get_user_info($userId);
7699
    $isDrh = function () use ($loginAsUserId) {
7700
        if (api_is_drh()) {
7701
            if (api_drh_can_access_all_session_content()) {
7702
                $users = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus(
7703
                    'drh_all',
7704
                    api_get_user_id()
7705
                );
7706
                $userList = [];
7707
                if (is_array($users)) {
7708
                    foreach ($users as $user) {
7709
                        $userList[] = $user['user_id'];
7710
                    }
7711
                }
7712
                if (in_array($loginAsUserId, $userList)) {
7713
                    return true;
7714
                }
7715
            } else {
7716
                if (api_is_drh() &&
7717
                    UserManager::is_user_followed_by_drh($loginAsUserId, api_get_user_id())
7718
                ) {
7719
                    return true;
7720
                }
7721
            }
7722
        }
7723
        return false;
7724
    };
7725
7726
    return api_is_platform_admin() || (api_is_session_admin() && $userInfo['status'] == 5) || $isDrh();
7727
}
7728
7729
/**
7730
 * @return bool
7731
 */
7732
function api_is_allowed_in_course()
7733
{
7734
    if (api_is_platform_admin()) {
7735
        return true;
7736
    }
7737
7738
    return Session::read('is_allowed_in_course');
7739
}
7740
7741
/**
7742
 * Set the cookie to go directly to the course code $in_firstpage
7743
 * after login
7744
 * @param string $in_firstpage is the course code of the course to go
7745
 */
7746
function api_set_firstpage_parameter($in_firstpage)
7747
{
7748
    setcookie('GotoCourse', $in_firstpage);
7749
}
7750
7751
/**
7752
 * Delete the cookie to go directly to the course code $in_firstpage
7753
 * after login
7754
 */
7755
function api_delete_firstpage_parameter()
7756
{
7757
    setcookie('GotoCourse', '', time() - 3600);
7758
}
7759
7760
/**
7761
 * @return boolean if course_code for direct course access after login is set
7762
 */
7763
function exist_firstpage_parameter()
7764
{
7765
    return isset($_COOKIE['GotoCourse']) && $_COOKIE['GotoCourse'] != '';
7766
}
7767
7768
/**
7769
 * @return return the course_code of the course where user login
7770
 */
7771
function api_get_firstpage_parameter()
7772
{
7773
    return $_COOKIE['GotoCourse'];
7774
}
7775
7776
/**
7777
 * Return true on https install
7778
 * @return boolean
7779
 */
7780
function api_is_https()
7781
{
7782
    if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) &&
7783
        $_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...
7784
    ) {
7785
        $isSecured = true;
7786
    } else {
7787
        if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') {
7788
            $isSecured = true;
7789
        } else {
7790
            $isSecured = false;
7791
            // last chance
7792
            if (!empty($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443) {
7793
                $isSecured = true;
7794
            }
7795
        }
7796
    }
7797
7798
    return $isSecured;
7799
}
7800
7801
/**
7802
 * Return protocol (http or https)
7803
 * @return string
7804
 */
7805
function api_get_protocol()
7806
{
7807
    return api_is_https() ? 'https' : 'http';
7808
}
7809
7810
/**
7811
 * Return a string where " are replaced with 2 '
7812
 * It is useful when you pass a PHP variable in a Javascript browser dialog
7813
 * e.g. : alert("<?php get_lang('Message') ?>");
7814
 * and message contains character "
7815
 *
7816
 * @param string $in_text
7817
 * @return string
7818
 */
7819
function convert_double_quote_to_single($in_text)
7820
{
7821
    return api_preg_replace('/"/', "''", $in_text);
7822
}
7823
7824
/**
7825
 * Get origin
7826
 *
7827
 * @param string
7828
 * @return string
7829
 **/
7830
function api_get_origin()
7831
{
7832
    $origin = isset($_REQUEST['origin']) ? Security::remove_XSS($_REQUEST['origin']) : '';
7833
7834
    return $origin;
7835
}
7836
7837
/**
7838
 * Warns an user that the portal reach certain limit.
7839
 * @param string $limitName
7840
 */
7841
function api_warn_hosting_contact($limitName)
7842
{
7843
    $hostingParams = api_get_configuration_value(1);
7844
    $email = null;
7845
7846
    if (!empty($hostingParams)) {
7847
        if (isset($hostingParams['hosting_contact_mail'])) {
7848
            $email = $hostingParams['hosting_contact_mail'];
7849
        }
7850
    }
7851
7852
    if (!empty($email)) {
7853
        $subject = get_lang('HostingWarningReached');
7854
        $body = get_lang('PortalName').': '.api_get_path(WEB_PATH)." \n ";
7855
        $body .= get_lang('PortalLimitType').': '.$limitName." \n ";
7856
        if (isset($hostingParams[$limitName])) {
7857
            $body .= get_lang('Value').': '.$hostingParams[$limitName];
7858
        }
7859
        api_mail_html(null, $email, $subject, $body);
7860
    }
7861
}
7862
7863
/**
7864
 * Gets value of a variable from app/config/configuration.php
7865
 * Variables that are not set in the configuration.php file but set elsewhere:
7866
 * - virtual_css_theme_folder (vchamilo plugin)
7867
 * - access_url (global.inc.php)
7868
 * - apc/apc_prefix (global.inc.php)
7869
 *
7870
 * @param string $variable
7871
 *
7872
 * @return bool|mixed
7873
 */
7874
function api_get_configuration_value($variable)
7875
{
7876
    global $_configuration;
7877
    // Check the current url id, id = 1 by default
7878
    $urlId = isset($_configuration['access_url']) ? (int) $_configuration['access_url'] : 1;
7879
7880
    $variable = trim($variable);
7881
7882
    // Check if variable exists
7883
    if (isset($_configuration[$variable])) {
7884
        if (is_array($_configuration[$variable])) {
7885
            // Check if it exists for the sub portal
7886
            if (array_key_exists($urlId, $_configuration[$variable])) {
7887
                return $_configuration[$variable][$urlId];
7888
            } else {
7889
                // Try to found element with id = 1 (master portal)
7890
                if (array_key_exists(1, $_configuration[$variable])) {
7891
                    return $_configuration[$variable][1];
7892
                }
7893
            }
7894
        }
7895
7896
        return $_configuration[$variable];
7897
    }
7898
7899
    return false;
7900
}
7901
7902
/**
7903
 * Returns supported image extensions in the portal
7904
 * @param   bool    $supportVectors Whether vector images should also be accepted or not
7905
 * @return  array   Supported image extensions in the portal
7906
 */
7907
function api_get_supported_image_extensions($supportVectors = true)
7908
{
7909
    // jpg can also be called jpeg, jpe, jfif and jif. See https://en.wikipedia.org/wiki/JPEG#JPEG_filename_extensions
7910
    $supportedImageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'jpe', 'jfif', 'jif'];
7911
    if ($supportVectors) {
7912
        array_push($supportedImageExtensions, 'svg');
7913
    }
7914
    if (version_compare(PHP_VERSION, '5.5.0', '>=')) {
7915
        array_push($supportedImageExtensions, 'webp');
7916
    }
7917
    return $supportedImageExtensions;
7918
}
7919
7920
/**
7921
 * This setting changes the registration status for the campus
7922
 *
7923
 * @author Patrick Cool <[email protected]>, Ghent University
7924
 * @version August 2006
7925
 * @param   bool    $listCampus Whether we authorize
7926
 * @todo the $_settings should be reloaded here. => write api function for this and use this in global.inc.php also.
7927
 */
7928
function api_register_campus($listCampus = true)
7929
{
7930
    $tbl_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
7931
7932
    $sql = "UPDATE $tbl_settings SET selected_value='true' WHERE variable='registered'";
7933
    Database::query($sql);
7934
7935
    if (!$listCampus) {
7936
        $sql = "UPDATE $tbl_settings SET selected_value='true' WHERE variable='donotlistcampus'";
7937
        Database::query($sql);
7938
    }
7939
}
7940
7941
/**
7942
 * Checks whether current user is a student boss
7943
 * @global array $_user
7944
 * @return boolean
7945
 */
7946
function api_is_student_boss()
7947
{
7948
    $_user = api_get_user_info();
7949
7950
    return isset($_user['status']) && $_user['status'] == STUDENT_BOSS;
7951
}
7952
7953
/**
7954
 * Check whether the user type should be exclude.
7955
 * Such as invited or anonymous users
7956
 * @param boolean $checkDB Optional. Whether check the user status
7957
 * @param int $userId Options. The user id
7958
 *
7959
 * @return boolean
7960
 */
7961
function api_is_excluded_user_type($checkDB = false, $userId = 0)
7962
{
7963
    if ($checkDB) {
7964
        $userId = empty($userId) ? api_get_user_id() : intval($userId);
7965
7966
        if ($userId == 0) {
7967
            return true;
7968
        }
7969
7970
        $userInfo = api_get_user_info($userId);
7971
7972
        switch ($userInfo['status']) {
7973
            case INVITEE:
7974
            case ANONYMOUS:
7975
                return true;
7976
            default:
7977
                return false;
7978
        }
7979
    }
7980
7981
    $isInvited = api_is_invitee();
7982
    $isAnonymous = api_is_anonymous();
7983
7984
    if ($isInvited || $isAnonymous) {
7985
        return true;
7986
    }
7987
7988
    return false;
7989
}
7990
7991
/**
7992
 * Get the user status to ignore in reports
7993
 * @param string $format Optional. The result type (array or string)
7994
 * @return array|string
7995
 */
7996
function api_get_users_status_ignored_in_reports($format = 'array')
7997
{
7998
    $excludedTypes = [
7999
        INVITEE,
8000
        ANONYMOUS
8001
    ];
8002
8003
    if ($format == 'string') {
8004
        return implode(', ', $excludedTypes);
8005
    }
8006
8007
    return $excludedTypes;
8008
}
8009
8010
/**
8011
 * Set the Site Use Cookie Warning for 1 year
8012
 */
8013
function api_set_site_use_cookie_warning_cookie()
8014
{
8015
    setcookie('ChamiloUsesCookies', 'ok', time() + 31556926);
8016
}
8017
8018
/**
8019
 * Return true if the Site Use Cookie Warning Cookie warning exists
8020
 * @return bool
8021
 */
8022
function api_site_use_cookie_warning_cookie_exist()
8023
{
8024
    return isset($_COOKIE['ChamiloUsesCookies']);
8025
}
8026
8027
/**
8028
 * Given a number of seconds, format the time to show hours, minutes and seconds
8029
 * @param int $time The time in seconds
8030
 * @param string $originFormat Optional. PHP o JS
8031
 * @return string (00h00'00")
8032
 */
8033
function api_format_time($time, $originFormat = 'php')
8034
{
8035
    $h = get_lang('h');
8036
    $hours = $time / 3600;
8037
    $mins = ($time % 3600) / 60;
8038
    $secs = ($time % 60);
8039
8040
    if ($time < 0) {
8041
        $hours = 0;
8042
        $mins = 0;
8043
        $secs = 0;
8044
    }
8045
8046
    if ($originFormat == 'js') {
8047
        $formattedTime = trim(sprintf("%02d : %02d : %02d", $hours, $mins, $secs));
8048
    } else {
8049
        $formattedTime = trim(sprintf("%02d$h%02d'%02d\"", $hours, $mins, $secs));
8050
    }
8051
8052
    return $formattedTime;
8053
}
8054
8055
/**
8056
 * Create a new empty directory with index.html file
8057
 * @param string $name The new directory name
8058
 * @param string $parentDirectory Directory parent directory name
8059
 * @return boolean Return true if the directory was create. Otherwise return false
8060
 */
8061
function api_create_protected_dir($name, $parentDirectory)
8062
{
8063
    $isCreated = false;
8064
8065
    if (!is_writable($parentDirectory)) {
8066
        return false;
8067
    }
8068
8069
    $fullPath = $parentDirectory.api_replace_dangerous_char($name);
8070
8071
    if (mkdir($fullPath, api_get_permissions_for_new_directories(), true)) {
8072
        $fp = fopen($fullPath.'/index.html', 'w');
8073
8074
        if ($fp) {
8075
            if (fwrite($fp, '<html><head></head><body></body></html>')) {
8076
                $isCreated = true;
8077
            }
8078
        }
8079
8080
        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

8080
        fclose(/** @scrutinizer ignore-type */ $fp);
Loading history...
8081
    }
8082
8083
    return $isCreated;
8084
}
8085
8086
/**
8087
 * Sends an HTML email using the phpmailer class (and multipart/alternative to downgrade gracefully)
8088
 * Sender name and email can be specified, if not specified
8089
 * name and email of the platform admin are used
8090
 *
8091
 * @author Bert Vanderkimpen ICT&O UGent
8092
 * @author Yannick Warnier <[email protected]>
8093
 *
8094
 * @param string    name of recipient
8095
 * @param string    email of recipient
8096
 * @param string    email subject
8097
 * @param string    email body
8098
 * @param string    sender name
8099
 * @param string    sender e-mail
8100
 * @param array     extra headers in form $headers = array($name => $value) to allow parsing
8101
 * @param array     data file (path and filename)
8102
 * @param bool      True for attaching a embedded file inside content html (optional)
8103
 * @param array     Additional parameters
8104
 * @return          integer true if mail was sent
8105
 * @see             class.phpmailer.php
8106
 */
8107
function api_mail_html(
8108
    $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

8108
    /** @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...
8109
    $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

8109
    /** @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...
8110
    $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

8110
    /** @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...
8111
    $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

8111
    /** @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...
8112
    $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

8112
    /** @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...
8113
    $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

8113
    /** @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...
8114
    $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

8114
    /** @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...
8115
    $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

8115
    /** @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...
8116
    $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

8116
    /** @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...
8117
    $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

8117
    /** @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...
8118
) {
8119
    global $platform_email;
8120
    return;
8121
8122
    $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...
8123
    $mail->Mailer = $platform_email['SMTP_MAILER'];
8124
    $mail->Host = $platform_email['SMTP_HOST'];
8125
    $mail->Port = $platform_email['SMTP_PORT'];
8126
    $mail->CharSet = $platform_email['SMTP_CHARSET'];
8127
    // Stay far below SMTP protocol 980 chars limit.
8128
    $mail->WordWrap = 200;
8129
8130
    if ($platform_email['SMTP_AUTH']) {
8131
        $mail->SMTPAuth = 1;
8132
        $mail->Username = $platform_email['SMTP_USER'];
8133
        $mail->Password = $platform_email['SMTP_PASS'];
8134
        if (isset($platform_email['SMTP_SECURE'])) {
8135
            $mail->SMTPSecure = $platform_email['SMTP_SECURE'];
8136
        }
8137
    }
8138
    $mail->SMTPDebug = isset($platform_email['SMTP_DEBUG']) ? $platform_email['SMTP_DEBUG'] : 0;
8139
8140
    // 5 = low, 1 = high
8141
    $mail->Priority = 3;
8142
    $mail->SMTPKeepAlive = true;
8143
8144
    // Default values
8145
    $notification = new Notification();
8146
    $defaultEmail = $notification->getDefaultPlatformSenderEmail();
8147
    $defaultName = $notification->getDefaultPlatformSenderName();
8148
8149
    // If the parameter is set don't use the admin.
8150
    $senderName = !empty($senderName) ? $senderName : $defaultName;
8151
    $senderEmail = !empty($senderEmail) ? $senderEmail : $defaultEmail;
8152
8153
    // Reply to first
8154
    if (isset($extra_headers['reply_to']) && empty($platform_email['SMTP_UNIQUE_REPLY_TO'])) {
8155
        $mail->AddReplyTo(
8156
            $extra_headers['reply_to']['mail'],
8157
            $extra_headers['reply_to']['name']
8158
        );
8159
        // Errors to sender
8160
        $mail->AddCustomHeader('Errors-To: '.$extra_headers['reply_to']['mail']);
8161
        $mail->Sender = $extra_headers['reply_to']['mail'];
8162
        unset($extra_headers['reply_to']);
8163
    } else {
8164
        $mail->AddCustomHeader('Errors-To: '.$defaultEmail);
8165
    }
8166
8167
    //If the SMTP configuration only accept one sender
8168
    if (isset($platform_email['SMTP_UNIQUE_SENDER']) && $platform_email['SMTP_UNIQUE_SENDER']) {
8169
        $senderName = $platform_email['SMTP_FROM_NAME'];
8170
        $senderEmail = $platform_email['SMTP_FROM_EMAIL'];
8171
        $valid = PHPMailer::validateAddress($senderEmail);
8172
        if ($valid) {
8173
            //force-set Sender to $senderEmail, otherwise SetFrom only does it if it is currently empty
8174
            $mail->Sender = $senderEmail;
8175
        }
8176
    }
8177
8178
    $mail->SetFrom($senderEmail, $senderName);
8179
    $mail->Subject = $subject;
8180
    $mail->AltBody = strip_tags(
8181
        str_replace('<br />', "\n", api_html_entity_decode($message))
8182
    );
8183
8184
    $list = api_get_configuration_value('send_all_emails_to');
8185
    if (!empty($list) && isset($list['emails'])) {
8186
        foreach ($list['emails'] as $email) {
8187
            //$mail->AddBCC($email);
8188
            $mail->AddAddress($email);
8189
        }
8190
    }
8191
8192
    // Send embedded image.
8193
    if ($embedded_image) {
8194
        // Get all images html inside content.
8195
        preg_match_all("/<img\s+.*?src=[\"\']?([^\"\' >]*)[\"\']?[^>]*>/i", $message, $m);
8196
        // Prepare new tag images.
8197
        $new_images_html = [];
8198
        $i = 1;
8199
        if (!empty($m[1])) {
8200
            foreach ($m[1] as $image_path) {
8201
                $real_path = realpath($image_path);
8202
                $filename  = basename($image_path);
8203
                $image_cid = $filename.'_'.$i;
8204
                $encoding = 'base64';
8205
                $image_type = mime_content_type($real_path);
8206
                $mail->AddEmbeddedImage(
8207
                    $real_path,
8208
                    $image_cid,
8209
                    $filename,
8210
                    $encoding,
8211
                    $image_type
8212
                );
8213
                $new_images_html[] = '<img src="cid:'.$image_cid.'" />';
8214
                $i++;
8215
            }
8216
        }
8217
8218
        // Replace origin image for new embedded image html.
8219
        $x = 0;
8220
        if (!empty($m[0])) {
8221
            foreach ($m[0] as $orig_img) {
8222
                $message = str_replace($orig_img, $new_images_html[$x], $message);
8223
                $x++;
8224
            }
8225
        }
8226
    }
8227
8228
    $mailView = new Template(null, false, false, false, false, false, false);
8229
8230
    $noReply = api_get_setting('noreply_email_address');
8231
    if (!empty($noReply)) {
8232
        $message .= "<br />".get_lang('ThisIsAutomaticEmailNoReply');
8233
    }
8234
    $mailView->assign('content', $message);
8235
8236
    if (isset($additionalParameters['link'])) {
8237
        $mailView->assign('link', $additionalParameters['link']);
8238
    }
8239
    $mailView->assign('mail_header_style', api_get_configuration_value('mail_header_style'));
8240
    $mailView->assign('mail_content_style', api_get_configuration_value('mail_content_style'));
8241
    $layout = $mailView->get_template('mail/mail.tpl');
8242
    $mail->Body = $mailView->fetch($layout);
8243
8244
    // Attachment ...
8245
    if (!empty($data_file)) {
8246
        $o = 0;
8247
        foreach ($data_file as $file_attach) {
8248
            if (!empty($file_attach['path']) && !empty($file_attach['filename'])) {
8249
                $mail->AddAttachment($file_attach['path'], $file_attach['filename']);
8250
            }
8251
            $o++;
8252
        }
8253
    }
8254
8255
    // Only valid addresses are accepted.
8256
    if (is_array($recipient_email)) {
8257
        foreach ($recipient_email as $dest) {
8258
            if (api_valid_email($dest)) {
8259
                $mail->AddAddress($dest, $recipient_name);
8260
            }
8261
        }
8262
    } else {
8263
        if (api_valid_email($recipient_email)) {
8264
            $mail->AddAddress($recipient_email, $recipient_name);
8265
        } else {
8266
            return 0;
8267
        }
8268
    }
8269
8270
    if (is_array($extra_headers) && count($extra_headers) > 0) {
8271
        foreach ($extra_headers as $key => $value) {
8272
            switch (strtolower($key)) {
8273
                case 'encoding':
8274
                case 'content-transfer-encoding':
8275
                    $mail->Encoding = $value;
8276
                    break;
8277
                case 'charset':
8278
                    $mail->Charset = $value;
8279
                    break;
8280
                case 'contenttype':
8281
                case 'content-type':
8282
                    $mail->ContentType = $value;
8283
                    break;
8284
                default:
8285
                    $mail->AddCustomHeader($key.':'.$value);
8286
                    break;
8287
            }
8288
        }
8289
    } else {
8290
        if (!empty($extra_headers)) {
8291
            $mail->AddCustomHeader($extra_headers);
8292
        }
8293
    }
8294
8295
    // WordWrap the html body (phpMailer only fixes AltBody) FS#2988
8296
    $mail->Body = $mail->WrapText($mail->Body, $mail->WordWrap);
8297
8298
    // Send the mail message.
8299
    if (!$mail->Send()) {
8300
        error_log('ERROR: mail not sent to '.$recipient_name.' ('.$recipient_email.') because of '.$mail->ErrorInfo.'<br />');
8301
        if ($mail->SMTPDebug) {
8302
            error_log(
8303
                "Connection details :: ".
8304
                "Protocol: ".$mail->Mailer.' :: '.
8305
                "Host/Port: ".$mail->Host.':'.$mail->Port.' :: '.
8306
                "Authent/Open: ".($mail->SMTPAuth ? 'Authent' : 'Open').' :: '.
8307
                ($mail->SMTPAuth ? "  User/Pass: ".$mail->Username.':'.$mail->Password : '').' :: '.
8308
                "Sender: ".$mail->Sender
8309
            );
8310
        }
8311
        return 0;
8312
    }
8313
8314
    if (!empty($additionalParameters)) {
8315
        $plugin = new AppPlugin();
8316
        $smsPlugin = $plugin->getSMSPluginLibrary();
8317
        if ($smsPlugin) {
8318
            $smsPlugin->send($additionalParameters);
8319
        }
8320
    }
8321
8322
    // Clear all the addresses.
8323
    $mail->ClearAddresses();
8324
8325
    // Clear all attachments
8326
    $mail->ClearAttachments();
8327
8328
    return 1;
8329
}
8330
8331
/**
8332
 * @param string $tool Possible values: GroupManager::GROUP_TOOL_*
8333
 * @param bool $showHeader
8334
 */
8335
function api_protect_course_group($tool, $showHeader = true)
8336
{
8337
    $userId = api_get_user_id();
8338
    $groupId = api_get_group_id();
8339
    $groupInfo = GroupManager::get_group_properties($groupId);
8340
8341
    if (!empty($groupInfo)) {
8342
        $allow = GroupManager::user_has_access(
8343
            $userId,
8344
            $groupInfo['iid'],
8345
            $tool
8346
        );
8347
8348
        if (!$allow) {
8349
            api_not_allowed($showHeader);
8350
        }
8351
    }
8352
}
8353
8354
/**
8355
 * Check if a date is in a date range
8356
 *
8357
 * @param datetime $startDate
8358
 * @param datetime $endDate
8359
 * @param datetime $currentDate
8360
 * @return bool true if date is in rage, false otherwise
8361
 */
8362
function api_is_date_in_date_range($startDate, $endDate, $currentDate = null)
8363
{
8364
    $startDate = strtotime(api_get_local_time($startDate));
8365
    $endDate = strtotime(api_get_local_time($endDate));
8366
    $currentDate = strtotime(api_get_local_time($currentDate));
8367
8368
    if ($currentDate >= $startDate && $currentDate <= $endDate) {
8369
        return true;
8370
    }
8371
8372
    return false;
8373
}
8374
8375
/**
8376
 * Eliminate the duplicates of a multidimensional array by sending the key
8377
 *
8378
 * @param array $array multidimensional array
8379
 * @param int $key key to find to compare
8380
 * @return array
8381
 *
8382
 */
8383
function api_unique_multidim_array($array, $key)
8384
{
8385
    $temp_array = [];
8386
    $i = 0;
8387
    $key_array = [];
8388
8389
    foreach ($array as $val) {
8390
        if (!in_array($val[$key], $key_array)) {
8391
            $key_array[$i] = $val[$key];
8392
            $temp_array[$i] = $val;
8393
        }
8394
        $i++;
8395
    }
8396
    return $temp_array;
8397
}
8398
8399
/**
8400
 * Limit the access to Session Admins wheen the limit_session_admin_role
8401
 * configuration variable is set to true
8402
 */
8403
function api_protect_limit_for_session_admin()
8404
{
8405
    $limitAdmin = api_get_setting('limit_session_admin_role');
8406
    if (api_is_session_admin() && $limitAdmin === 'true') {
8407
        api_not_allowed(true);
8408
    }
8409
}
8410
8411
/**
8412
 * @return bool
8413
 */
8414
function api_is_student_view_active()
8415
{
8416
    $studentView = Session::read('studentview');
8417
    return $studentView == 'studentview';
8418
}
8419
8420
/**
8421
 * Adds a file inside the upload/$type/id
8422
 *
8423
 * @param string $type
8424
 * @param array $file
8425
 * @param int $itemId
8426
 * @param string $cropParameters
8427
 * @return array|bool
8428
 */
8429
function api_upload_file($type, $file, $itemId, $cropParameters = '')
8430
{
8431
    $upload = process_uploaded_file($file);
8432
    if ($upload) {
8433
        $name = api_replace_dangerous_char($file['name']);
8434
8435
        // No "dangerous" files
8436
        $name = disable_dangerous_file($name);
8437
8438
        $pathId = '/'.substr((string) $itemId, 0, 1).'/'.$itemId.'/';
8439
        $path = api_get_path(SYS_UPLOAD_PATH).$type.$pathId;
8440
8441
        if (!is_dir($path)) {
8442
            mkdir($path, api_get_permissions_for_new_directories(), true);
8443
        }
8444
8445
        $pathToSave = $path.$name;
8446
8447
        $result = move_uploaded_file($file['tmp_name'], $pathToSave);
8448
        if ($result) {
8449
            if (!empty($cropParameters)) {
8450
                $image = new Image($pathToSave);
8451
                $image->crop($cropParameters);
8452
            }
8453
8454
            return ['path_to_save' => $pathId.$name];
8455
        }
8456
        return false;
8457
    }
8458
}
8459
8460
/**
8461
 * @param string $type
8462
 * @param int $itemId
8463
 * @param string $file
8464
 *
8465
 * @return bool
8466
 */
8467
function api_get_uploaded_file($type, $itemId, $file)
8468
{
8469
    $itemId = (int) $itemId;
8470
    $pathId = '/'.substr((string) $itemId, 0, 1).'/'.$itemId.'/';
8471
    $path = api_get_path(SYS_UPLOAD_PATH).$type.$pathId;
8472
8473
    $file = basename($file);
8474
8475
    $file = $path.'/'.$file;
8476
    if (file_exists($file)) {
8477
        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...
8478
    }
8479
    return false;
8480
}
8481
8482
/**
8483
 * @param string $type
8484
 * @param int $itemId
8485
 * @param string $file
8486
 * @param string $title
8487
 */
8488
function api_download_uploaded_file($type, $itemId, $file, $title = '')
8489
{
8490
    $file = api_get_uploaded_file($type, $itemId, $file);
8491
    if ($file) {
8492
        if (Security::check_abs_path($file, api_get_path(SYS_UPLOAD_PATH).$type)) {
8493
            DocumentManager::file_send_for_download($file, true, $title);
8494
            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...
8495
        }
8496
    }
8497
    api_not_allowed(true);
8498
}
8499
8500
/**
8501
 * @param string $type
8502
 * @param string $file
8503
 */
8504
function api_remove_uploaded_file($type, $file)
8505
{
8506
    $path = api_get_path(SYS_UPLOAD_PATH).$type.'/'.$file;
8507
    if (file_exists($path)) {
8508
        unlink($path);
8509
    }
8510
}
8511
8512
/**
8513
 * Converts string value to float value
8514
 *
8515
 * 3.141516 => 3.141516
8516
 * 3,141516 => 3.141516
8517
 * @todo WIP
8518
 *
8519
 * @param string $number
8520
 * @return float
8521
 */
8522
function api_float_val($number)
8523
{
8524
    $number = (float) str_replace(',', '.', trim($number));
8525
    return $number;
8526
}
8527
8528
/**
8529
 * Converts float values
8530
 * Example if $decimals = 2
8531
 *
8532
 * 3.141516 => 3.14
8533
 * 3,141516 => 3,14
8534
 *
8535
 * @todo WIP
8536
 *
8537
 * @param string $number number in iso code
8538
 * @param int $decimals
8539
 * @return bool|string
8540
 */
8541
function api_number_format($number, $decimals = 0)
8542
{
8543
    $number = api_float_val($number);
8544
8545
    return number_format($number, $decimals);
8546
}
8547
8548
/**
8549
 * Set location url with a exit break by default
8550
 *
8551
 * @param $url
8552
 * @param bool $exit
8553
 * @return void
8554
 */
8555
function location($url, $exit = true)
8556
{
8557
    header('Location: '.$url);
8558
8559
    if ($exit) {
8560
        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...
8561
    }
8562
}
8563
8564
/**
8565
 * @return string
8566
 */
8567
function api_get_web_url()
8568
{
8569
    if (api_get_setting('server_type') == 'test') {
8570
        return api_get_path(WEB_PATH).'web/app_dev.php/';
8571
    } else {
8572
        return api_get_path(WEB_PATH).'web/';
8573
    }
8574
}
8575