Completed
Push — master ( 27e209...a08afa )
by Julito
186:04 queued 150:53
created

api_is_course_visible_for_user()   F

Complexity

Conditions 22
Paths 1130

Size

Total Lines 150
Code Lines 93

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 22
eloc 93
nc 1130
nop 2
dl 0
loc 150
rs 2
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

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

4862
    $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...
4863
    // A sanity check.
4864
    $is_object_dir = is_object($dir);
4865
    if ($is_object_dir) {
4866
        while (false !== $entry = $dir->read()) {
4867
            // Skip pointers.
4868
            if ($entry == '.' || $entry == '..') {
4869
                continue;
4870
            }
4871
4872
            // Recurse.
4873
            if ($strict) {
4874
                $result = rmdirr("$dirname/$entry");
4875
                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...
4876
                    $res = false;
4877
                    break;
4878
                }
4879
            } else {
4880
                rmdirr("$dirname/$entry");
4881
            }
4882
        }
4883
    }
4884
4885
    // Clean up.
4886
    if ($is_object_dir) {
4887
        $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

4887
        $dir->/** @scrutinizer ignore-call */ 
4888
              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...
4888
    }
4889
4890
    if ($delete_only_content_in_folder == false) {
4891
        $res = rmdir($dirname);
4892
        if ($res === false) {
4893
            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);
4894
        }
4895
    }
4896
    return $res;
4897
}
4898
4899
// TODO: This function is to be simplified. File access modes to be implemented.
4900
/**
4901
 * function adapted from a php.net comment
4902
 * copy recursively a folder
4903
 * @param the source folder
4904
 * @param the dest folder
4905
 * @param an array of excluded file_name (without extension)
4906
 * @param copied_files the returned array of copied files
4907
 * @param string $source
4908
 * @param string $dest
4909
 */
4910
function copyr($source, $dest, $exclude = [], $copied_files = [])
4911
{
4912
    if (empty($dest)) {
4913
        return false;
4914
    }
4915
    // Simple copy for a file
4916
    if (is_file($source)) {
4917
        $path_info = pathinfo($source);
4918
        if (!in_array($path_info['filename'], $exclude)) {
4919
            copy($source, $dest);
4920
        }
4921
        return true;
4922
    } elseif (!is_dir($source)) {
4923
        //then source is not a dir nor a file, return
4924
        return false;
4925
    }
4926
4927
    // Make destination directory.
4928
    if (!is_dir($dest)) {
4929
        mkdir($dest, api_get_permissions_for_new_directories());
4930
    }
4931
4932
    // Loop through the folder.
4933
    $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

4933
    $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...
4934
    while (false !== $entry = $dir->read()) {
4935
        // Skip pointers
4936
        if ($entry == '.' || $entry == '..') {
4937
            continue;
4938
        }
4939
4940
        // Deep copy directories.
4941
        if ($dest !== "$source/$entry") {
4942
            $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

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

5047
    while ($file = readdir(/** @scrutinizer ignore-type */ $handler)) {
Loading history...
5048
        if ($file != '.' && $file != '..') {
5049
            $fullpath = "$path/$file";
5050
            if (!is_dir($fullpath)) {
5051
                if (!chmod($fullpath, $filemode)) {
5052
                    return false;
5053
                }
5054
            } else {
5055
                if (!api_chmod_R($fullpath, $filemode)) {
5056
                    return false;
5057
                }
5058
            }
5059
        }
5060
    }
5061
5062
    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

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

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

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

8096
    /** @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...
8097
    $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

8097
    /** @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...
8098
    $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

8098
    /** @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...
8099
    $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

8099
    /** @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...
8100
    $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

8100
    /** @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...
8101
    $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

8101
    /** @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...
8102
    $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

8102
    /** @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...
8103
    $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

8103
    /** @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...
8104
    $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

8104
    /** @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...
8105
    $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

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