Passed
Push — master ( 3e4e56...30a646 )
by Julito
08:31
created

api_display_language_form()   B

Complexity

Conditions 8
Paths 33

Size

Total Lines 54
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 8
eloc 29
nc 33
nop 2
dl 0
loc 54
rs 8.2114
c 1
b 0
f 0

How to fix   Long Method   

Long Method

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

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

Commonly applied refactorings include:

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

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

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

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

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

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

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

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

    return false;
}

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

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

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

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

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

    return false;
}

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

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

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

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

Loading history...
2880
        $value = $result['selected_value'];
2881
        $serializedValue = @unserialize($result['selected_value'], []);
2882
        if ($serializedValue !== false) {
2883
            $value = $serializedValue;
2884
        }
2885
2886
        return $value;
2887
    }
2888
2889
    return null;
2890
    /// Old code
2891
2892
    $variableName = $plugin.'_'.$variable;
0 ignored issues
show
Unused Code introduced by
$variableName = $plugin . '_' . $variable is not reachable.

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

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

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

    return false;
}

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

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

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

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

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

Loading history...
3750
    $message = null,
3751
    $responseCode = 0
3752
) {
3753
    $debug = api_get_setting('server_type') == 'test';
3754
3755
    // Default code is 403 forbidden
3756
    $responseCode = empty($responseCode) ? 403 : $responseCode;
3757
    $message = empty($message) ? get_lang('NotAuthorized') : $message;
3758
3759
    // Create new exception rendered by template:
3760
    // src/ThemeBundle/Resources/views/Exception/error.html.twig
3761
3762
    // if error is 404 then the template is:
3763
    // src/ThemeBundle/Resources/views/Exception/error404.html.twig
3764
    $exception = new Exception($message);
3765
    $request = Container::getRequest();
3766
    $exception = \Symfony\Component\Debug\Exception\FlattenException::create($exception, $responseCode);
3767
    $controller = new \Chamilo\ThemeBundle\Controller\ExceptionController(Container::getTwig(), $debug);
3768
    $response = $controller->showAction($request, $exception);
3769
    $response->send();
3770
    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...
3771
3772
    if (api_get_setting('sso_authentication') === 'true') {
0 ignored issues
show
Unused Code introduced by
IfNode is not reachable.

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

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

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

    return false;
}

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

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

5302
            $files = copyr("$source/$entry", "$dest/$entry", $exclude, /** @scrutinizer ignore-type */ $copied_files);
Loading history...
5303
        }
5304
    }
5305
    // Clean up.
5306
    $dir->close();
5307
5308
    return true;
5309
}
5310
5311
/**
5312
 * @todo: Using DIRECTORY_SEPARATOR is not recommended, this is an obsolete approach.
5313
 * Documentation header to be added here.
5314
 *
5315
 * @param string $pathname
5316
 * @param string $base_path_document
5317
 * @param int    $session_id
5318
 *
5319
 * @return mixed True if directory already exists, false if a file already exists at
5320
 *               the destination and null if everything goes according to plan
5321
 */
5322
function copy_folder_course_session(
5323
    $pathname,
5324
    $base_path_document,
5325
    $session_id,
5326
    $course_info,
5327
    $document,
5328
    $source_course_id
5329
) {
5330
    $table = Database::get_course_table(TABLE_DOCUMENT);
5331
    $session_id = intval($session_id);
5332
    $source_course_id = intval($source_course_id);
5333
5334
    // Check whether directory already exists.
5335
    if (is_dir($pathname) || empty($pathname)) {
5336
        return true;
5337
    }
5338
5339
    // Ensure that a file with the same name does not already exist.
5340
    if (is_file($pathname)) {
5341
        trigger_error('copy_folder_course_session(): File exists', E_USER_WARNING);
5342
5343
        return false;
5344
    }
5345
5346
    $course_id = $course_info['real_id'];
5347
    $folders = explode(DIRECTORY_SEPARATOR, str_replace($base_path_document.DIRECTORY_SEPARATOR, '', $pathname));
5348
    $new_pathname = $base_path_document;
5349
    $path = '';
5350
5351
    foreach ($folders as $folder) {
5352
        $new_pathname .= DIRECTORY_SEPARATOR.$folder;
5353
        $path .= DIRECTORY_SEPARATOR.$folder;
5354
5355
        if (!file_exists($new_pathname)) {
5356
            $path = Database::escape_string($path);
5357
5358
            $sql = "SELECT * FROM $table
5359
                    WHERE
5360
                        c_id = $source_course_id AND
5361
                        path = '$path' AND
5362
                        filetype = 'folder' AND
5363
                        session_id = '$session_id'";
5364
            $rs1 = Database::query($sql);
5365
            $num_rows = Database::num_rows($rs1);
5366
5367
            if ($num_rows == 0) {
5368
                mkdir($new_pathname, api_get_permissions_for_new_directories());
5369
5370
                // Insert new folder with destination session_id.
5371
                $params = [
5372
                    'c_id' => $course_id,
5373
                    'path' => $path,
5374
                    'comment' => $document->comment,
5375
                    'title' => basename($new_pathname),
5376
                    'filetype' => 'folder',
5377
                    'size' => '0',
5378
                    'session_id' => $session_id,
5379
                ];
5380
                $document_id = Database::insert($table, $params);
5381
                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...
5382
                    $sql = "UPDATE $table SET id = iid WHERE iid = $document_id";
5383
                    Database::query($sql);
5384
5385
                    api_item_property_update(
5386
                        $course_info,
5387
                        TOOL_DOCUMENT,
5388
                        $document_id,
5389
                        'FolderCreated',
5390
                        api_get_user_id(),
5391
                        0,
5392
                        0,
5393
                        null,
5394
                        null,
5395
                        $session_id
5396
                    );
5397
                }
5398
            }
5399
        }
5400
    } // en foreach
5401
}
5402
5403
// TODO: chmodr() is a better name. Some corrections are needed. Documentation header to be added here.
5404
/**
5405
 * @param string $path
5406
 */
5407
function api_chmod_R($path, $filemode)
5408
{
5409
    if (!is_dir($path)) {
5410
        return chmod($path, $filemode);
5411
    }
5412
5413
    $handler = opendir($path);
5414
    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

5414
    while ($file = readdir(/** @scrutinizer ignore-type */ $handler)) {
Loading history...
5415
        if ($file != '.' && $file != '..') {
5416
            $fullpath = "$path/$file";
5417
            if (!is_dir($fullpath)) {
5418
                if (!chmod($fullpath, $filemode)) {
5419
                    return false;
5420
                }
5421
            } else {
5422
                if (!api_chmod_R($fullpath, $filemode)) {
5423
                    return false;
5424
                }
5425
            }
5426
        }
5427
    }
5428
5429
    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

5429
    closedir(/** @scrutinizer ignore-type */ $handler);
Loading history...
5430
5431
    return chmod($path, $filemode);
5432
}
5433
5434
// TODO: Where the following function has been copy/pased from? There is no information about author and license. Style, coding conventions...
5435
/**
5436
 * Parse info file format. (e.g: file.info).
5437
 *
5438
 * Files should use an ini-like format to specify values.
5439
 * White-space generally doesn't matter, except inside values.
5440
 * e.g.
5441
 *
5442
 * @verbatim
5443
 *   key = value
5444
 *   key = "value"
5445
 *   key = 'value'
5446
 *   key = "multi-line
5447
 *
5448
 *   value"
5449
 *   key = 'multi-line
5450
 *
5451
 *   value'
5452
 *   key
5453
 *   =
5454
 *   'value'
5455
 * @endverbatim
5456
 *
5457
 * Arrays are created using a GET-like syntax:
5458
 *
5459
 * @verbatim
5460
 *   key[] = "numeric array"
5461
 *   key[index] = "associative array"
5462
 *   key[index][] = "nested numeric array"
5463
 *   key[index][index] = "nested associative array"
5464
 * @endverbatim
5465
 *
5466
 * PHP constants are substituted in, but only when used as the entire value:
5467
 *
5468
 * Comments should start with a semi-colon at the beginning of a line.
5469
 *
5470
 * This function is NOT for placing arbitrary module-specific settings. Use
5471
 * variable_get() and variable_set() for that.
5472
 *
5473
 * Information stored in the module.info file:
5474
 * - name: The real name of the module for display purposes.
5475
 * - description: A brief description of the module.
5476
 * - dependencies: An array of shortnames of other modules this module depends on.
5477
 * - package: The name of the package of modules this module belongs to.
5478
 *
5479
 * Example of .info file:
5480
 * <code>
5481
 * @verbatim
5482
 *   name = Forum
5483
 *   description = Enables threaded discussions about general topics.
5484
 *   dependencies[] = taxonomy
5485
 *   dependencies[] = comment
5486
 *   package = Core - optional
5487
 *   version = VERSION
5488
 * @endverbatim
5489
 * </code>
5490
 *
5491
 * @param string $filename
5492
 *                         The file we are parsing. Accepts file with relative or absolute path.
5493
 *
5494
 * @return
5495
 *   The info array
5496
 */
5497
function api_parse_info_file($filename)
5498
{
5499
    $info = [];
5500
5501
    if (!file_exists($filename)) {
5502
        return $info;
5503
    }
5504
5505
    $data = file_get_contents($filename);
5506
    if (preg_match_all('
5507
        @^\s*                           # Start at the beginning of a line, ignoring leading whitespace
5508
        ((?:
5509
          [^=;\[\]]|                    # Key names cannot contain equal signs, semi-colons or square brackets,
5510
          \[[^\[\]]*\]                  # unless they are balanced and not nested
5511
        )+?)
5512
        \s*=\s*                         # Key/value pairs are separated by equal signs (ignoring white-space)
5513
        (?:
5514
          ("(?:[^"]|(?<=\\\\)")*")|     # Double-quoted string, which may contain slash-escaped quotes/slashes
5515
          (\'(?:[^\']|(?<=\\\\)\')*\')| # Single-quoted string, which may contain slash-escaped quotes/slashes
5516
          ([^\r\n]*?)                   # Non-quoted string
5517
        )\s*$                           # Stop at the next end of a line, ignoring trailing whitespace
5518
        @msx', $data, $matches, PREG_SET_ORDER)) {
5519
        $key = $value1 = $value2 = $value3 = '';
5520
        foreach ($matches as $match) {
5521
            // Fetch the key and value string.
5522
            $i = 0;
5523
            foreach (['key', 'value1', 'value2', 'value3'] as $var) {
5524
                $$var = isset($match[++$i]) ? $match[$i] : '';
5525
            }
5526
            $value = stripslashes(substr($value1, 1, -1)).stripslashes(substr($value2, 1, -1)).$value3;
5527
5528
            // Parse array syntax.
5529
            $keys = preg_split('/\]?\[/', rtrim($key, ']'));
5530
            $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

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

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

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

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

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

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

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

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

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

8700
        fclose(/** @scrutinizer ignore-type */ $fp);
Loading history...
8701
    }
8702
8703
    return $isCreated;
8704
}
8705
8706
/**
8707
 * Sends an email
8708
 * Sender name and email can be specified, if not specified
8709
 * name and email of the platform admin are used.
8710
 *
8711
 * @param string    name of recipient
8712
 * @param string    email of recipient
8713
 * @param string    email subject
8714
 * @param string    email body
8715
 * @param string    sender name
8716
 * @param string    sender e-mail
8717
 * @param array     extra headers in form $headers = array($name => $value) to allow parsing
8718
 * @param array     data file (path and filename)
8719
 * @param bool      True for attaching a embedded file inside content html (optional)
8720
 * @param array     Additional parameters
8721
 *
8722
 * @return bool true if mail was sent
8723
 */
8724
function api_mail_html(
8725
    $recipientName,
8726
    $recipientEmail,
8727
    $subject,
8728
    $body,
8729
    $senderName = '',
8730
    $senderEmail = '',
8731
    $extra_headers = [],
8732
    $data_file = [],
8733
    $embeddedImage = false,
0 ignored issues
show
Unused Code introduced by
The parameter $embeddedImage 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

8733
    /** @scrutinizer ignore-unused */ $embeddedImage = 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...
8734
    $additionalParameters = []
8735
) {
8736
    if (!api_valid_email($recipientEmail)) {
8737
        return false;
8738
    }
8739
8740
    // Default values
8741
    $notification = new Notification();
8742
    $defaultEmail = $notification->getDefaultPlatformSenderEmail();
8743
    $defaultName = $notification->getDefaultPlatformSenderName();
8744
8745
    // If the parameter is set don't use the admin.
8746
    $senderName = !empty($senderName) ? $senderName : $defaultName;
8747
    $senderEmail = !empty($senderEmail) ? $senderEmail : $defaultEmail;
8748
8749
    // Reply to first
8750
    $replyToName = '';
8751
    $replyToEmail = '';
8752
    if (isset($extra_headers['reply_to'])) {
8753
        $replyToEmail = $extra_headers['reply_to']['mail'];
8754
        $replyToName = $extra_headers['reply_to']['name'];
8755
    }
8756
8757
    //If the SMTP configuration only accept one sender
8758
    /*if (isset($platform_email['SMTP_UNIQUE_SENDER']) && $platform_email['SMTP_UNIQUE_SENDER']) {
8759
        $senderName = $platform_email['SMTP_FROM_NAME'];
8760
        $senderEmail = $platform_email['SMTP_FROM_EMAIL'];
8761
        $valid = PHPMailer::validateAddress($senderEmail);
8762
        if ($valid) {
8763
            //force-set Sender to $senderEmail, otherwise SetFrom only does it if it is currently empty
8764
            $mail->Sender = $senderEmail;
8765
        }
8766
    }*/
8767
8768
    /*$mail->SetFrom($senderEmail, $senderName);
8769
    $mail->Subject = $subject;
8770
    $mail->AltBody = strip_tags(
8771
        str_replace('<br />', "\n", api_html_entity_decode($message))
8772
    );*/
8773
8774
    /*if (is_array($extra_headers) && count($extra_headers) > 0) {
8775
        foreach ($extra_headers as $key => $value) {
8776
            switch (strtolower($key)) {
8777
                case 'encoding':
8778
                case 'content-transfer-encoding':
8779
                    $mail->Encoding = $value;
8780
                    break;
8781
                case 'charset':
8782
                    $mail->Charset = $value;
8783
                    break;
8784
                case 'contenttype':
8785
                case 'content-type':
8786
                    $mail->ContentType = $value;
8787
                    break;
8788
                default:
8789
                    $mail->AddCustomHeader($key.':'.$value);
8790
                    break;
8791
            }
8792
        }
8793
    } else {
8794
        if (!empty($extra_headers)) {
8795
            $mail->AddCustomHeader($extra_headers);
8796
        }
8797
    }*/
8798
8799
    // WordWrap the html body (phpMailer only fixes AltBody) FS#2988
8800
    //$mail->Body = $mail->WrapText($mail->Body, $mail->WordWrap);
8801
    try {
8802
        $message = new \Swift_Message($subject);
8803
8804
        $list = api_get_configuration_value('send_all_emails_to');
8805
        if (!empty($list) && isset($list['emails'])) {
8806
            foreach ($list['emails'] as $email) {
8807
                $message->addCc($email);
8808
            }
8809
        }
8810
8811
        // Attachment
8812
        if (!empty($data_file)) {
8813
            foreach ($data_file as $file_attach) {
8814
                if (!empty($file_attach['path']) && !empty($file_attach['filename'])) {
8815
                    //$message->attach(Swift_Attachment::fromPath($file_attach['path'], $file_attach['filename']);
8816
                    $message->attach(
8817
                        Swift_Attachment::fromPath($file_attach['path'])->setFilename($file_attach['filename'])
8818
                    );
8819
                }
8820
            }
8821
        }
8822
8823
        $noReply = api_get_setting('noreply_email_address');
8824
        $automaticEmailText = '';
8825
        if (!empty($noReply)) {
8826
            $automaticEmailText = '<br />'.get_lang('ThisIsAutomaticEmailNoReply');
8827
        }
8828
8829
        $params = [
8830
            'content' => '',
8831
            'mail_header_style' => api_get_configuration_value('mail_header_style'),
8832
            'mail_content_style' => api_get_configuration_value('mail_content_style'),
8833
            'link' => $additionalParameters['link'] ?? '',
8834
            'automatic_email_text' => $automaticEmailText,
8835
        ];
8836
8837
        $paramsHtml = $paramsText = $params;
8838
8839
        $paramsHtml['content'] = $body;
8840
        $paramsText['content'] = str_replace('<br />', "\n", api_html_entity_decode($body));
8841
8842
        if (!empty($senderEmail)) {
8843
            $message->setFrom([$senderEmail => $senderName]);
8844
        }
8845
8846
        if (!empty($recipientEmail)) {
8847
            $message->setTo([$recipientEmail => $recipientName]);
8848
        }
8849
8850
        if (!empty($replyToEmail)) {
8851
            $message->setReplyTo([$replyToEmail => $replyToName]);
8852
        }
8853
8854
        $message
8855
            ->setBody(
8856
                Container::getTwig()->render(
8857
                    'ChamiloCoreBundle:Mailer:Default/default.html.twig',
8858
                    $paramsHtml
8859
                ),
8860
                'text/html'
8861
            )
8862
            ->addPart(
8863
                Container::getTwig()->render(
8864
                    'ChamiloCoreBundle:Mailer:Default/default.text.twig',
8865
                    $paramsText
8866
                ),
8867
                'text/plain'
8868
            )
8869
            //->setEncoder(\Swift_Encoding::get8BitEncoding())
8870
        ;
8871
8872
        $type = $message->getHeaders()->get('Content-Type');
8873
        $type->setCharset('utf-8');
8874
        Container::getMailer()->send($message);
8875
8876
        return true;
8877
    } catch (Exception $e) {
8878
        error_log($e->getMessage());
8879
    }
8880
8881
    if (!empty($additionalParameters)) {
8882
        $plugin = new AppPlugin();
8883
        $smsPlugin = $plugin->getSMSPluginLibrary();
8884
        if ($smsPlugin) {
0 ignored issues
show
introduced by
$smsPlugin is of type SmsPluginLibraryInterface, thus it always evaluated to true.
Loading history...
8885
            $smsPlugin->send($additionalParameters);
8886
        }
8887
    }
8888
8889
    return 1;
0 ignored issues
show
Bug Best Practice introduced by
The expression return 1 returns the type integer which is incompatible with the documented return type boolean.
Loading history...
8890
}
8891
8892
/**
8893
 * @param string $tool       Possible values: GroupManager::GROUP_TOOL_*
8894
 * @param bool   $showHeader
8895
 */
8896
function api_protect_course_group($tool, $showHeader = true)
8897
{
8898
    $userId = api_get_user_id();
8899
    $groupId = api_get_group_id();
8900
    $groupInfo = GroupManager::get_group_properties($groupId);
8901
8902
    if (!empty($groupInfo)) {
8903
        $allow = GroupManager::user_has_access(
8904
            $userId,
8905
            $groupInfo['iid'],
8906
            $tool
8907
        );
8908
8909
        if (!$allow) {
8910
            api_not_allowed($showHeader);
8911
        }
8912
    }
8913
}
8914
8915
/**
8916
 * Check if a date is in a date range.
8917
 *
8918
 * @param datetime $startDate
8919
 * @param datetime $endDate
8920
 * @param datetime $currentDate
8921
 *
8922
 * @return bool true if date is in rage, false otherwise
8923
 */
8924
function api_is_date_in_date_range($startDate, $endDate, $currentDate = null)
8925
{
8926
    $startDate = strtotime(api_get_local_time($startDate));
8927
    $endDate = strtotime(api_get_local_time($endDate));
8928
    $currentDate = strtotime(api_get_local_time($currentDate));
8929
8930
    if ($currentDate >= $startDate && $currentDate <= $endDate) {
8931
        return true;
8932
    }
8933
8934
    return false;
8935
}
8936
8937
/**
8938
 * Eliminate the duplicates of a multidimensional array by sending the key.
8939
 *
8940
 * @param array $array multidimensional array
8941
 * @param int   $key   key to find to compare
8942
 *
8943
 * @return array
8944
 */
8945
function api_unique_multidim_array($array, $key)
8946
{
8947
    $temp_array = [];
8948
    $i = 0;
8949
    $key_array = [];
8950
8951
    foreach ($array as $val) {
8952
        if (!in_array($val[$key], $key_array)) {
8953
            $key_array[$i] = $val[$key];
8954
            $temp_array[$i] = $val;
8955
        }
8956
        $i++;
8957
    }
8958
8959
    return $temp_array;
8960
}
8961
8962
/**
8963
 * Limit the access to Session Admins when the limit_session_admin_role
8964
 * configuration variable is set to true.
8965
 */
8966
function api_protect_limit_for_session_admin()
8967
{
8968
    $limitAdmin = api_get_setting('limit_session_admin_role');
8969
    if (api_is_session_admin() && $limitAdmin === 'true') {
8970
        api_not_allowed(true);
8971
    }
8972
}
8973
8974
/**
8975
 * @return bool
8976
 */
8977
function api_is_student_view_active()
8978
{
8979
    $studentView = Session::read('studentview');
8980
8981
    return $studentView == 'studentview';
8982
}
8983
8984
/**
8985
 * Adds a file inside the upload/$type/id.
8986
 *
8987
 * @param string $type
8988
 * @param array  $file
8989
 * @param int    $itemId
8990
 * @param string $cropParameters
8991
 *
8992
 * @return array|bool
8993
 */
8994
function api_upload_file($type, $file, $itemId, $cropParameters = '')
8995
{
8996
    $upload = process_uploaded_file($file);
8997
    if ($upload) {
8998
        $name = api_replace_dangerous_char($file['name']);
8999
9000
        // No "dangerous" files
9001
        $name = disable_dangerous_file($name);
9002
9003
        $pathId = '/'.substr((string) $itemId, 0, 1).'/'.$itemId.'/';
9004
        $path = api_get_path(SYS_UPLOAD_PATH).$type.$pathId;
9005
9006
        if (!is_dir($path)) {
9007
            mkdir($path, api_get_permissions_for_new_directories(), true);
9008
        }
9009
9010
        $pathToSave = $path.$name;
9011
        $result = moveUploadedFile($file, $pathToSave);
9012
9013
        if ($result) {
9014
            if (!empty($cropParameters)) {
9015
                $image = new Image($pathToSave);
9016
                $image->crop($cropParameters);
9017
            }
9018
9019
            return ['path_to_save' => $pathId.$name];
9020
        }
9021
9022
        return false;
9023
    }
9024
}
9025
9026
/**
9027
 * @param string $type
9028
 * @param int    $itemId
9029
 * @param string $file
9030
 *
9031
 * @return bool
9032
 */
9033
function api_get_uploaded_web_url($type, $itemId, $file)
9034
{
9035
    return api_get_uploaded_file($type, $itemId, $file, true);
9036
}
9037
9038
/**
9039
 * @param string $type
9040
 * @param int    $itemId
9041
 * @param string $file
9042
 * @param bool   $getUrl
9043
 *
9044
 * @return bool
9045
 */
9046
function api_get_uploaded_file($type, $itemId, $file, $getUrl = false)
9047
{
9048
    $itemId = (int) $itemId;
9049
    $pathId = '/'.substr((string) $itemId, 0, 1).'/'.$itemId.'/';
9050
    $path = api_get_path(SYS_UPLOAD_PATH).$type.$pathId;
9051
    $file = basename($file);
9052
    $file = $path.'/'.$file;
9053
    if (Security::check_abs_path($file, $path) && is_file($file) && file_exists($file)) {
9054
        if ($getUrl) {
9055
            return str_replace(api_get_path(SYS_UPLOAD_PATH), api_get_path(WEB_UPLOAD_PATH), $file);
0 ignored issues
show
Bug Best Practice introduced by
The expression return str_replace(api_g...EB_UPLOAD_PATH), $file) returns the type string which is incompatible with the documented return type boolean.
Loading history...
9056
        }
9057
9058
        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...
9059
    }
9060
9061
    return false;
9062
}
9063
9064
/**
9065
 * @param string $type
9066
 * @param int    $itemId
9067
 * @param string $file
9068
 * @param string $title
9069
 */
9070
function api_download_uploaded_file($type, $itemId, $file, $title = '')
9071
{
9072
    $file = api_get_uploaded_file($type, $itemId, $file);
9073
    if ($file) {
9074
        if (Security::check_abs_path($file, api_get_path(SYS_UPLOAD_PATH).$type)) {
9075
            DocumentManager::file_send_for_download($file, true, $title);
9076
            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...
9077
        }
9078
    }
9079
    api_not_allowed(true);
9080
}
9081
9082
/**
9083
 * @param string $type
9084
 * @param string $file
9085
 */
9086
function api_remove_uploaded_file($type, $file)
9087
{
9088
    $typePath = api_get_path(SYS_UPLOAD_PATH).$type;
9089
    $path = $typePath.'/'.$file;
9090
    if (Security::check_abs_path($path, $typePath) && file_exists($path) && is_file($path)) {
9091
        unlink($path);
9092
    }
9093
}
9094
9095
/**
9096
 * @param string $type
9097
 * @param int    $itemId
9098
 * @param string $file
9099
 *
9100
 * @return bool
9101
 */
9102
function api_remove_uploaded_file_by_id($type, $itemId, $file)
9103
{
9104
    $file = api_get_uploaded_file($type, $itemId, $file, false);
9105
    $typePath = api_get_path(SYS_UPLOAD_PATH).$type;
9106
    if (Security::check_abs_path($file, $typePath) && file_exists($file) && is_file($file)) {
9107
        unlink($file);
9108
9109
        return true;
9110
    }
9111
9112
    return false;
9113
}
9114
9115
/**
9116
 * Converts string value to float value.
9117
 *
9118
 * 3.141516 => 3.141516
9119
 * 3,141516 => 3.141516
9120
 *
9121
 * @todo WIP
9122
 *
9123
 * @param string $number
9124
 *
9125
 * @return float
9126
 */
9127
function api_float_val($number)
9128
{
9129
    $number = (float) str_replace(',', '.', trim($number));
9130
9131
    return $number;
9132
}
9133
9134
/**
9135
 * Converts float values
9136
 * Example if $decimals = 2.
9137
 *
9138
 * 3.141516 => 3.14
9139
 * 3,141516 => 3,14
9140
 *
9141
 * @param string $number            number in iso code
9142
 * @param int    $decimals
9143
 * @param string $decimalSeparator
9144
 * @param string $thousandSeparator
9145
 *
9146
 * @return bool|string
9147
 */
9148
function api_number_format($number, $decimals = 0, $decimalSeparator = '.', $thousandSeparator = ',')
9149
{
9150
    $number = api_float_val($number);
9151
9152
    return number_format($number, $decimals, $decimalSeparator, $thousandSeparator);
9153
}
9154
9155
/**
9156
 * Set location url with a exit break by default.
9157
 *
9158
 * @param $url
9159
 * @param bool $exit
9160
 */
9161
function location($url, $exit = true)
9162
{
9163
    header('Location: '.$url);
9164
9165
    if ($exit) {
9166
        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...
9167
    }
9168
}
9169
9170
/**
9171
 * @return string
9172
 */
9173
function api_get_web_url()
9174
{
9175
    if (api_get_setting('server_type') === 'test') {
9176
        return api_get_path(WEB_PATH).'web/app_dev.php/';
9177
    } else {
9178
        return api_get_path(WEB_PATH).'web/';
9179
    }
9180
}
9181
9182
/**
9183
 * @param string $from
9184
 * @param string $to
9185
 *
9186
 * @return string
9187
 */
9188
function api_get_relative_path($from, $to)
9189
{
9190
    // some compatibility fixes for Windows paths
9191
    $from = is_dir($from) ? rtrim($from, '\/').'/' : $from;
9192
    $to = is_dir($to) ? rtrim($to, '\/').'/' : $to;
9193
    $from = str_replace('\\', '/', $from);
9194
    $to = str_replace('\\', '/', $to);
9195
9196
    $from = explode('/', $from);
9197
    $to = explode('/', $to);
9198
    $relPath = $to;
9199
9200
    foreach ($from as $depth => $dir) {
9201
        // find first non-matching dir
9202
        if ($dir === $to[$depth]) {
9203
            // ignore this directory
9204
            array_shift($relPath);
9205
        } else {
9206
            // get number of remaining dirs to $from
9207
            $remaining = count($from) - $depth;
9208
            if ($remaining > 1) {
9209
                // add traversals up to first matching dir
9210
                $padLength = (count($relPath) + $remaining - 1) * -1;
9211
                $relPath = array_pad($relPath, $padLength, '..');
9212
                break;
9213
            } else {
9214
                $relPath[0] = './'.$relPath[0];
9215
            }
9216
        }
9217
    }
9218
9219
    return implode('/', $relPath);
9220
}
9221