Passed
Push — master ( 518cb9...ab560b )
by Julito
10:37
created

api_is_ldap_activated()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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

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

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

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

2048
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...
2049
{
2050
    if (!empty($course_code)) {
2051
        $course_code = Database::escape_string($course_code);
2052
        $courseId = api_get_course_int_id($course_code);
2053
2054
        if (empty($courseId)) {
2055
            return [];
2056
        }
2057
2058
        $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
2059
        $course_cat_table = Database::get_main_table(TABLE_MAIN_CATEGORY);
2060
        $sql = "SELECT
2061
                    course.*,
2062
                    course_category.code faCode,
2063
                    course_category.name faName
2064
                FROM $course_table
2065
                LEFT JOIN $course_cat_table
2066
                ON course.category_code = course_category.code
2067
                WHERE course.id = $courseId";
2068
        $result = Database::query($sql);
2069
        $courseInfo = [];
2070
        if (Database::num_rows($result) > 0) {
2071
            $data = Database::fetch_array($result);
2072
            $courseInfo = api_format_course_array($data);
2073
        }
2074
2075
        return $courseInfo;
2076
    }
2077
2078
    $_course = Session::read('_course');
2079
    if ($_course == '-1') {
2080
        $_course = [];
2081
    }
2082
2083
    return $_course;
2084
}
2085
2086
/**
2087
 * @param int $courseId
2088
 *
2089
 * @return Course
2090
 */
2091
function api_get_course_entity($courseId = 0)
2092
{
2093
    if (empty($courseId)) {
2094
        $courseId = api_get_course_int_id();
2095
    }
2096
2097
    return CourseManager::getManager()->find($courseId);
2098
}
2099
2100
/**
2101
 * @param int $id
2102
 *
2103
 * @return SessionEntity
2104
 */
2105
function api_get_session_entity($id = 0)
2106
{
2107
    if (empty($id)) {
2108
        $id = api_get_session_id();
2109
    }
2110
2111
    return Database::getManager()->getRepository('ChamiloCoreBundle:Session')->find($id);
2112
}
2113
2114
/**
2115
 * @param int $id
2116
 *
2117
 * @return \Chamilo\CourseBundle\Entity\CGroupInfo
2118
 */
2119
function api_get_group_entity($id = 0)
2120
{
2121
    if (empty($id)) {
2122
        $id = api_get_group_id();
2123
    }
2124
2125
    return Database::getManager()->getRepository('ChamiloCourseBundle:CGroupInfo')->find($id);
2126
}
2127
2128
/**
2129
 * @param int $id
2130
 *
2131
 * @return \Chamilo\CoreBundle\Entity\AccessUrl
2132
 */
2133
function api_get_url_entity($id = 0)
2134
{
2135
    if (empty($id)) {
2136
        $id = api_get_current_access_url_id();
2137
    }
2138
2139
    return Database::getManager()->getRepository('ChamiloCoreBundle:AccessUrl')->find($id);
2140
}
2141
2142
/**
2143
 * Returns the current course info array.
2144
2145
 * Now if the course_code is given, the returned array gives info about that
2146
 * particular course, not specially the current one.
2147
 *
2148
 * @param int $id Numeric ID of the course
2149
 *
2150
 * @return array The course info as an array formatted by api_format_course_array, including category.name
2151
 */
2152
function api_get_course_info_by_id($id = 0)
2153
{
2154
    $id = (int) $id;
2155
    if (empty($id)) {
2156
        $course = Session::read('_course', []);
2157
2158
        return $course;
2159
    }
2160
2161
    $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
2162
    $course_cat_table = Database::get_main_table(TABLE_MAIN_CATEGORY);
2163
    $sql = "SELECT
2164
                course.*,
2165
                course_category.code faCode,
2166
                course_category.name faName
2167
            FROM $course_table
2168
            LEFT JOIN $course_cat_table
2169
            ON course.category_code = course_category.code
2170
            WHERE course.id = $id";
2171
    $result = Database::query($sql);
2172
2173
    if (Database::num_rows($result) > 0) {
2174
        $row = Database::fetch_array($result);
2175
        $course = api_format_course_array($row);
2176
2177
        return $course;
2178
    }
2179
2180
    return [];
2181
}
2182
2183
/**
2184
 * Reformat the course array (output by api_get_course_info()) in order, mostly,
2185
 * to switch from 'code' to 'id' in the array. This is a legacy feature and is
2186
 * now possibly causing massive confusion as a new "id" field has been added to
2187
 * the course table in 1.9.0.
2188
 *
2189
 * @param $course_data
2190
 *
2191
 * @return array
2192
 *
2193
 * @todo eradicate the false "id"=code field of the $_course array and use the int id
2194
 */
2195
function api_format_course_array($course_data)
2196
{
2197
    if (empty($course_data)) {
2198
        return [];
2199
    }
2200
2201
    $_course = [];
2202
    $_course['id'] = $course_data['code'];
2203
    $_course['real_id'] = $course_data['id'];
2204
2205
    // Added
2206
    $_course['code'] = $course_data['code'];
2207
    $_course['name'] = $course_data['title'];
2208
    $_course['title'] = $course_data['title'];
2209
    $_course['official_code'] = $course_data['visual_code'];
2210
    $_course['visual_code'] = $course_data['visual_code'];
2211
    $_course['sysCode'] = $course_data['code'];
2212
    $_course['path'] = $course_data['directory']; // Use as key in path.
2213
    $_course['directory'] = $course_data['directory'];
2214
    $_course['creation_date'] = $course_data['creation_date'];
2215
    $_course['titular'] = $course_data['tutor_name'];
2216
    $_course['language'] = $course_data['course_language'];
2217
    $_course['extLink']['url'] = $course_data['department_url'];
2218
    $_course['extLink']['name'] = $course_data['department_name'];
2219
    $_course['categoryCode'] = $course_data['faCode'];
2220
    $_course['categoryName'] = $course_data['faName'];
2221
    $_course['visibility'] = $course_data['visibility'];
2222
    $_course['subscribe_allowed'] = $course_data['subscribe'];
2223
    $_course['subscribe'] = $course_data['subscribe'];
2224
    $_course['unsubscribe'] = $course_data['unsubscribe'];
2225
    $_course['course_language'] = $course_data['course_language'];
2226
    $_course['activate_legal'] = isset($course_data['activate_legal']) ? $course_data['activate_legal'] : false;
2227
    $_course['legal'] = $course_data['legal'];
2228
    $_course['show_score'] = $course_data['show_score']; //used in the work tool
2229
    $_course['department_name'] = $course_data['department_name'];
2230
    $_course['department_url'] = $course_data['department_url'];
2231
2232
    $courseSys = api_get_path(SYS_COURSE_PATH).$course_data['directory'];
2233
    $webCourseHome = api_get_path(WEB_COURSE_PATH).$course_data['directory'];
2234
2235
    // Course password
2236
    $_course['registration_code'] = !empty($course_data['registration_code']) ? sha1($course_data['registration_code']) : null;
2237
    $_course['disk_quota'] = $course_data['disk_quota'];
2238
    $_course['course_public_url'] = $webCourseHome.'/index.php';
2239
2240
    if (array_key_exists('add_teachers_to_sessions_courses', $course_data)) {
2241
        $_course['add_teachers_to_sessions_courses'] = $course_data['add_teachers_to_sessions_courses'];
2242
    }
2243
2244
    // Course image
2245
    $_course['course_image_source'] = '';
2246
    if (file_exists($courseSys.'/course-pic85x85.png')) {
2247
        $url_image = $webCourseHome.'/course-pic85x85.png';
2248
        $_course['course_image_source'] = $courseSys.'/course-pic85x85.png';
2249
    } else {
2250
        $url_image = Display::return_icon(
2251
            'course.png',
2252
            null,
2253
            null,
2254
            ICON_SIZE_BIG,
2255
            null,
2256
            true,
2257
            false
2258
        );
2259
    }
2260
    $_course['course_image'] = $url_image;
2261
2262
    // Course large image
2263
    $_course['course_image_large_source'] = '';
2264
    if (file_exists($courseSys.'/course-pic.png')) {
2265
        $url_image = $webCourseHome.'/course-pic.png';
2266
        $_course['course_image_large_source'] = $courseSys.'/course-pic.png';
2267
    } else {
2268
        $url_image = Display::return_icon(
2269
            'session_default.png',
2270
            null,
2271
            null,
2272
            null,
2273
            null,
2274
            true,
2275
            false
2276
        );
2277
    }
2278
    $_course['course_image_large'] = $url_image;
2279
2280
    return $_course;
2281
}
2282
2283
/**
2284
 * Returns a difficult to guess password.
2285
 *
2286
 * @param int $length the length of the password
2287
 *
2288
 * @return string the generated password
2289
 */
2290
function api_generate_password($length = 8)
2291
{
2292
    if ($length < 2) {
2293
        $length = 2;
2294
    }
2295
2296
    $charactersLowerCase = 'abcdefghijkmnopqrstuvwxyz';
2297
    $charactersUpperCase = 'ABCDEFGHJKLMNPQRSTUVWXYZ';
2298
    $minNumbers = 2;
2299
    $length = $length - $minNumbers;
2300
    $minLowerCase = round($length / 2);
2301
    $minUpperCase = $length - $minLowerCase;
2302
2303
    $password = '';
2304
    $passwordRequirements = api_get_configuration_value('password_requirements');
2305
2306
    $factory = new RandomLib\Factory();
2307
    $generator = $factory->getGenerator(new SecurityLib\Strength(SecurityLib\Strength::MEDIUM));
2308
2309
    if (!empty($passwordRequirements)) {
2310
        $length = $passwordRequirements['min']['length'];
2311
        $minNumbers = $passwordRequirements['min']['numeric'];
2312
        $minLowerCase = $passwordRequirements['min']['lowercase'];
2313
        $minUpperCase = $passwordRequirements['min']['uppercase'];
2314
2315
        $rest = $length - $minNumbers - $minLowerCase - $minUpperCase;
2316
        // Add the rest to fill the length requirement
2317
        if ($rest > 0) {
2318
            $password .= $generator->generateString($rest, $charactersLowerCase.$charactersUpperCase);
2319
        }
2320
    }
2321
2322
    // Min digits default 2
2323
    for ($i = 0; $i < $minNumbers; $i++) {
2324
        $password .= $generator->generateInt(2, 9);
2325
    }
2326
2327
    // Min lowercase
2328
    $password .= $generator->generateString($minLowerCase, $charactersLowerCase);
2329
2330
    // Min uppercase
2331
    $password .= $generator->generateString($minUpperCase, $charactersUpperCase);
2332
    $password = str_shuffle($password);
2333
2334
    return $password;
2335
}
2336
2337
/**
2338
 * Checks a password to see wether it is OK to use.
2339
 *
2340
 * @param string $password
2341
 *
2342
 * @return bool if the password is acceptable, false otherwise
2343
 *              Notes about what a password "OK to use" is:
2344
 *              1. The password should be at least 5 characters long.
2345
 *              2. Only English letters (uppercase or lowercase, it doesn't matter) and digits are allowed.
2346
 *              3. The password should contain at least 3 letters.
2347
 *              4. It should contain at least 2 digits.
2348
 *              Settings will change if the configuration value is set: password_requirements
2349
 */
2350
function api_check_password($password)
2351
{
2352
    $passwordRequirements = Security::getPasswordRequirements();
2353
2354
    $minLength = $passwordRequirements['min']['length'];
2355
    $minNumbers = $passwordRequirements['min']['numeric'];
2356
    // Optional
2357
    $minLowerCase = $passwordRequirements['min']['lowercase'];
2358
    $minUpperCase = $passwordRequirements['min']['uppercase'];
2359
2360
    $minLetters = $minLowerCase + $minUpperCase;
2361
    $passwordLength = api_strlen($password);
2362
2363
    $conditions = [
2364
        'min_length' => $passwordLength >= $minLength,
2365
    ];
2366
2367
    $digits = 0;
2368
    $lowerCase = 0;
2369
    $upperCase = 0;
2370
2371
    for ($i = 0; $i < $passwordLength; $i++) {
2372
        $currentCharacterCode = api_ord(api_substr($password, $i, 1));
2373
        if ($currentCharacterCode >= 65 && $currentCharacterCode <= 90) {
2374
            $upperCase++;
2375
        }
2376
2377
        if ($currentCharacterCode >= 97 && $currentCharacterCode <= 122) {
2378
            $lowerCase++;
2379
        }
2380
        if ($currentCharacterCode >= 48 && $currentCharacterCode <= 57) {
2381
            $digits++;
2382
        }
2383
    }
2384
2385
    // Min number of digits
2386
    $conditions['min_numeric'] = $digits >= $minNumbers;
2387
2388
    if (!empty($minUpperCase)) {
2389
        // Uppercase
2390
        $conditions['min_uppercase'] = $upperCase >= $minUpperCase;
2391
    }
2392
2393
    if (!empty($minLowerCase)) {
2394
        // Lowercase
2395
        $conditions['min_lowercase'] = $upperCase >= $minLowerCase;
2396
    }
2397
2398
    // Min letters
2399
    $letters = $upperCase + $lowerCase;
2400
    $conditions['min_letters'] = $letters >= $minLetters;
2401
2402
    $isPasswordOk = true;
2403
    foreach ($conditions as $condition) {
2404
        if ($condition === false) {
2405
            $isPasswordOk = false;
2406
            break;
2407
        }
2408
    }
2409
2410
    if ($isPasswordOk === false) {
2411
        $output = get_lang('NewPasswordRequirementsNotMatched').'<br />';
2412
        $output .= Security::getPasswordRequirementsToString($conditions);
2413
2414
        Display::addFlash(Display::return_message($output, 'warning', false));
2415
    }
2416
2417
    return $isPasswordOk;
2418
}
2419
2420
/**
2421
 * Returns the status string corresponding to the status code.
2422
 *
2423
 * @author Noel Dieschburg
2424
 *
2425
 * @param the int status code
2426
 *
2427
 * @return string
2428
 */
2429
function get_status_from_code($status_code)
2430
{
2431
    switch ($status_code) {
2432
        case STUDENT:
2433
            return get_lang('Student', '');
2434
        case COURSEMANAGER:
2435
            return get_lang('Teacher', '');
2436
        case SESSIONADMIN:
2437
            return get_lang('SessionsAdmin', '');
2438
        case DRH:
2439
            return get_lang('Drh', '');
2440
    }
2441
}
2442
2443
/**
2444
 * Gets the current Chamilo (not PHP/cookie) session ID.
2445
 *
2446
 * @return int O if no active session, the session ID otherwise
2447
 */
2448
function api_get_session_id()
2449
{
2450
    return (int) Session::read('id_session', 0);
2451
}
2452
2453
/**
2454
 * Gets the current Chamilo (not social network) group ID.
2455
 *
2456
 * @return int O if no active session, the session ID otherwise
2457
 */
2458
function api_get_group_id()
2459
{
2460
    return Session::read('_gid', 0);
2461
}
2462
2463
/**
2464
 * Gets the current or given session name.
2465
 *
2466
 * @param   int     Session ID (optional)
2467
 *
2468
 * @return string The session name, or null if not found
2469
 */
2470
function api_get_session_name($session_id = 0)
2471
{
2472
    if (empty($session_id)) {
2473
        $session_id = api_get_session_id();
2474
        if (empty($session_id)) {
2475
            return null;
2476
        }
2477
    }
2478
    $t = Database::get_main_table(TABLE_MAIN_SESSION);
2479
    $s = "SELECT name FROM $t WHERE id = ".(int) $session_id;
2480
    $r = Database::query($s);
2481
    $c = Database::num_rows($r);
2482
    if ($c > 0) {
2483
        //technically, there can be only one, but anyway we take the first
2484
        $rec = Database::fetch_array($r);
2485
2486
        return $rec['name'];
2487
    }
2488
2489
    return null;
2490
}
2491
2492
/**
2493
 * Gets the session info by id.
2494
 *
2495
 * @param int $id Session ID
2496
 *
2497
 * @return array information of the session
2498
 */
2499
function api_get_session_info($id)
2500
{
2501
    return SessionManager::fetch($id);
2502
}
2503
2504
/**
2505
 * Gets the session visibility by session id.
2506
 *
2507
 * @param int  $session_id
2508
 * @param int  $courseId
2509
 * @param bool $ignore_visibility_for_admins
2510
 *
2511
 * @return int
2512
 *             0 = session still available,
2513
 *             SESSION_VISIBLE_READ_ONLY = 1,
2514
 *             SESSION_VISIBLE = 2,
2515
 *             SESSION_INVISIBLE = 3
2516
 */
2517
function api_get_session_visibility(
2518
    $session_id,
2519
    $courseId = null,
2520
    $ignore_visibility_for_admins = true
2521
) {
2522
    if (api_is_platform_admin()) {
2523
        if ($ignore_visibility_for_admins) {
2524
            return SESSION_AVAILABLE;
2525
        }
2526
    }
2527
2528
    $now = time();
2529
2530
    if (empty($session_id)) {
2531
        return 0; // Means that the session is still available.
2532
    }
2533
2534
    $session_id = (int) $session_id;
2535
    $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
2536
2537
    $result = Database::query("SELECT * FROM $tbl_session WHERE id = $session_id");
2538
2539
    if (Database::num_rows($result) <= 0) {
2540
        return SESSION_INVISIBLE;
2541
    }
2542
2543
    $row = Database::fetch_array($result, 'ASSOC');
2544
    $visibility = $original_visibility = $row['visibility'];
2545
2546
    // I don't care the session visibility.
2547
    if (empty($row['access_start_date']) && empty($row['access_end_date'])) {
2548
        // Session duration per student.
2549
        if (isset($row['duration']) && !empty($row['duration'])) {
2550
            $duration = $row['duration'] * 24 * 60 * 60;
2551
            $courseAccess = CourseManager::getFirstCourseAccessPerSessionAndUser($session_id, api_get_user_id());
2552
2553
            // If there is a session duration but there is no previous
2554
            // access by the user, then the session is still available
2555
            if (count($courseAccess) == 0) {
2556
                return SESSION_AVAILABLE;
2557
            }
2558
2559
            $currentTime = time();
2560
            $firstAccess = isset($courseAccess['login_course_date'])
2561
                ? api_strtotime($courseAccess['login_course_date'], 'UTC')
2562
                : 0;
2563
            $userDurationData = SessionManager::getUserSession(
2564
                api_get_user_id(),
2565
                $session_id
2566
            );
2567
            $userDuration = isset($userDurationData['duration'])
2568
                ? (intval($userDurationData['duration']) * 24 * 60 * 60)
2569
                : 0;
2570
2571
            $totalDuration = $firstAccess + $duration + $userDuration;
2572
2573
            return $totalDuration > $currentTime ? SESSION_AVAILABLE : SESSION_VISIBLE_READ_ONLY;
2574
        }
2575
2576
        return SESSION_AVAILABLE;
2577
    }
2578
2579
    // If start date was set.
2580
    if (!empty($row['access_start_date'])) {
2581
        $visibility = $now > api_strtotime($row['access_start_date'], 'UTC') ? SESSION_AVAILABLE : SESSION_INVISIBLE;
2582
    }
2583
2584
    // If the end date was set.
2585
    if (!empty($row['access_end_date'])) {
2586
        // Only if date_start said that it was ok
2587
        if ($visibility === SESSION_AVAILABLE) {
2588
            $visibility = $now < api_strtotime($row['access_end_date'], 'UTC')
2589
                ? SESSION_AVAILABLE // Date still available
2590
                : $row['visibility']; // Session ends
2591
        }
2592
    }
2593
2594
    // If I'm a coach the visibility can change in my favor depending in the coach dates.
2595
    $isCoach = api_is_coach($session_id, $courseId);
2596
2597
    if ($isCoach) {
2598
        // Test start date.
2599
        if (!empty($row['coach_access_start_date'])) {
2600
            $start = api_strtotime($row['coach_access_start_date'], 'UTC');
2601
            $visibility = $start < $now ? SESSION_AVAILABLE : SESSION_INVISIBLE;
2602
        }
2603
2604
        // Test end date.
2605
        if (!empty($row['coach_access_end_date'])) {
2606
            if ($visibility === SESSION_AVAILABLE) {
2607
                $endDateCoach = api_strtotime($row['coach_access_end_date'], 'UTC');
2608
                $visibility = $endDateCoach >= $now ? SESSION_AVAILABLE : $row['visibility'];
2609
            }
2610
        }
2611
    }
2612
2613
    return $visibility;
2614
}
2615
2616
/**
2617
 * This function returns a (star) session icon if the session is not null and
2618
 * the user is not a student.
2619
 *
2620
 * @param int $session_id
2621
 * @param int $status_id  User status id - if 5 (student), will return empty
2622
 *
2623
 * @return string Session icon
2624
 */
2625
function api_get_session_image($session_id, $status_id)
2626
{
2627
    $session_id = (int) $session_id;
2628
    $session_img = '';
2629
    if ((int) $status_id != 5) { //check whether is not a student
2630
        if ($session_id > 0) {
2631
            $session_img = "&nbsp;&nbsp;".Display::return_icon(
2632
                'star.png',
2633
                get_lang('SessionSpecificResource'),
2634
                ['align' => 'absmiddle'],
2635
                ICON_SIZE_SMALL
2636
            );
2637
        }
2638
    }
2639
2640
    return $session_img;
2641
}
2642
2643
/**
2644
 * This function add an additional condition according to the session of the course.
2645
 *
2646
 * @param int    $session_id        session id
2647
 * @param bool   $and               optional, true if more than one condition false if the only condition in the query
2648
 * @param bool   $with_base_content optional, true to accept content with session=0 as well,
2649
 *                                  false for strict session condition
2650
 * @param string $session_field
2651
 *
2652
 * @return string condition of the session
2653
 */
2654
function api_get_session_condition(
2655
    $session_id,
2656
    $and = true,
2657
    $with_base_content = false,
2658
    $session_field = 'session_id'
2659
) {
2660
    $session_id = (int) $session_id;
2661
2662
    if (empty($session_field)) {
2663
        $session_field = "session_id";
2664
    }
2665
    // Condition to show resources by session
2666
    $condition_add = $and ? " AND " : " WHERE ";
2667
2668
    if ($with_base_content) {
2669
        $condition_session = $condition_add." ( $session_field = $session_id OR $session_field = 0 OR $session_field IS NULL) ";
2670
    } else {
2671
        if (empty($session_id)) {
2672
            $condition_session = $condition_add." ($session_field = $session_id OR $session_field IS NULL)";
2673
        } else {
2674
            $condition_session = $condition_add." $session_field = $session_id ";
2675
        }
2676
    }
2677
2678
    return $condition_session;
2679
}
2680
2681
/**
2682
 * Returns the value of a setting from the web-adjustable admin config settings.
2683
 *
2684
 * WARNING true/false are stored as string, so when comparing you need to check e.g.
2685
 * if (api_get_setting('show_navigation_menu') == 'true') //CORRECT
2686
 * instead of
2687
 * if (api_get_setting('show_navigation_menu') == true) //INCORRECT
2688
 *
2689
 * @param string $variable The variable name
2690
 *
2691
 * @return string
2692
 */
2693
function api_get_setting($variable)
2694
{
2695
    $settingsManager = Container::getSettingsManager();
2696
    if (empty($settingsManager)) {
2697
        return '';
2698
    }
2699
    $variable = trim($variable);
2700
2701
    switch ($variable) {
2702
        case 'header_extra_content':
2703
            $filename = api_get_path(SYS_PATH).api_get_home_path().'header_extra_content.txt';
2704
            if (file_exists($filename)) {
2705
                $value = file_get_contents($filename);
2706
2707
                return $value;
2708
            } else {
2709
                return '';
2710
            }
2711
            break;
2712
        case 'footer_extra_content':
2713
            $filename = api_get_path(SYS_PATH).api_get_home_path().'footer_extra_content.txt';
2714
            if (file_exists($filename)) {
2715
                $value = file_get_contents($filename);
2716
2717
                return $value;
2718
            } else {
2719
                return '';
2720
            }
2721
            break;
2722
        case 'server_type':
2723
            $test = ['dev', 'test'];
2724
            $environment = Container::getEnvironment();
2725
            if (in_array($environment, $test)) {
2726
                return 'test';
2727
            }
2728
2729
            return 'prod';
2730
        case 'stylesheets':
2731
            $variable = 'platform.theme';
2732
        // deprecated settings
2733
        // no break
2734
        case 'openid_authentication':
2735
        case 'service_ppt2lp':
2736
        case 'formLogin_hide_unhide_label':
2737
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type string.
Loading history...
2738
            break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

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

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

5225
            $files = copyr("$source/$entry", "$dest/$entry", $exclude, /** @scrutinizer ignore-type */ $copied_files);
Loading history...
5226
        }
5227
    }
5228
    // Clean up.
5229
    $dir->close();
5230
5231
    return true;
5232
}
5233
5234
/**
5235
 * @todo: Using DIRECTORY_SEPARATOR is not recommended, this is an obsolete approach.
5236
 * Documentation header to be added here.
5237
 *
5238
 * @param string $pathname
5239
 * @param string $base_path_document
5240
 * @param int    $session_id
5241
 *
5242
 * @return mixed True if directory already exists, false if a file already exists at
5243
 *               the destination and null if everything goes according to plan
5244
 */
5245
function copy_folder_course_session(
5246
    $pathname,
5247
    $base_path_document,
5248
    $session_id,
5249
    $course_info,
5250
    $document,
5251
    $source_course_id
5252
) {
5253
    $table = Database::get_course_table(TABLE_DOCUMENT);
5254
    $session_id = intval($session_id);
5255
    $source_course_id = intval($source_course_id);
5256
5257
    // Check whether directory already exists.
5258
    if (is_dir($pathname) || empty($pathname)) {
5259
        return true;
5260
    }
5261
5262
    // Ensure that a file with the same name does not already exist.
5263
    if (is_file($pathname)) {
5264
        trigger_error('copy_folder_course_session(): File exists', E_USER_WARNING);
5265
5266
        return false;
5267
    }
5268
5269
    $course_id = $course_info['real_id'];
5270
    $folders = explode(DIRECTORY_SEPARATOR, str_replace($base_path_document.DIRECTORY_SEPARATOR, '', $pathname));
5271
    $new_pathname = $base_path_document;
5272
    $path = '';
5273
5274
    foreach ($folders as $folder) {
5275
        $new_pathname .= DIRECTORY_SEPARATOR.$folder;
5276
        $path .= DIRECTORY_SEPARATOR.$folder;
5277
5278
        if (!file_exists($new_pathname)) {
5279
            $path = Database::escape_string($path);
5280
5281
            $sql = "SELECT * FROM $table
5282
                    WHERE
5283
                        c_id = $source_course_id AND
5284
                        path = '$path' AND
5285
                        filetype = 'folder' AND
5286
                        session_id = '$session_id'";
5287
            $rs1 = Database::query($sql);
5288
            $num_rows = Database::num_rows($rs1);
5289
5290
            if ($num_rows == 0) {
5291
                mkdir($new_pathname, api_get_permissions_for_new_directories());
5292
5293
                // Insert new folder with destination session_id.
5294
                $params = [
5295
                    'c_id' => $course_id,
5296
                    'path' => $path,
5297
                    'comment' => $document->comment,
5298
                    'title' => basename($new_pathname),
5299
                    'filetype' => 'folder',
5300
                    'size' => '0',
5301
                    'session_id' => $session_id,
5302
                ];
5303
                $document_id = Database::insert($table, $params);
5304
                if ($document_id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $document_id of type false|integer 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...
5305
                    $sql = "UPDATE $table SET id = iid WHERE iid = $document_id";
5306
                    Database::query($sql);
5307
5308
                    api_item_property_update(
5309
                        $course_info,
5310
                        TOOL_DOCUMENT,
5311
                        $document_id,
5312
                        'FolderCreated',
5313
                        api_get_user_id(),
5314
                        0,
5315
                        0,
5316
                        null,
5317
                        null,
5318
                        $session_id
5319
                    );
5320
                }
5321
            }
5322
        }
5323
    } // en foreach
5324
}
5325
5326
// TODO: chmodr() is a better name. Some corrections are needed. Documentation header to be added here.
5327
/**
5328
 * @param string $path
5329
 */
5330
function api_chmod_R($path, $filemode)
5331
{
5332
    if (!is_dir($path)) {
5333
        return chmod($path, $filemode);
5334
    }
5335
5336
    $handler = opendir($path);
5337
    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

5337
    while ($file = readdir(/** @scrutinizer ignore-type */ $handler)) {
Loading history...
5338
        if ($file != '.' && $file != '..') {
5339
            $fullpath = "$path/$file";
5340
            if (!is_dir($fullpath)) {
5341
                if (!chmod($fullpath, $filemode)) {
5342
                    return false;
5343
                }
5344
            } else {
5345
                if (!api_chmod_R($fullpath, $filemode)) {
5346
                    return false;
5347
                }
5348
            }
5349
        }
5350
    }
5351
5352
    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

5352
    closedir(/** @scrutinizer ignore-type */ $handler);
Loading history...
5353
5354
    return chmod($path, $filemode);
5355
}
5356
5357
// TODO: Where the following function has been copy/pased from? There is no information about author and license. Style, coding conventions...
5358
/**
5359
 * Parse info file format. (e.g: file.info).
5360
 *
5361
 * Files should use an ini-like format to specify values.
5362
 * White-space generally doesn't matter, except inside values.
5363
 * e.g.
5364
 *
5365
 * @verbatim
5366
 *   key = value
5367
 *   key = "value"
5368
 *   key = 'value'
5369
 *   key = "multi-line
5370
 *
5371
 *   value"
5372
 *   key = 'multi-line
5373
 *
5374
 *   value'
5375
 *   key
5376
 *   =
5377
 *   'value'
5378
 * @endverbatim
5379
 *
5380
 * Arrays are created using a GET-like syntax:
5381
 *
5382
 * @verbatim
5383
 *   key[] = "numeric array"
5384
 *   key[index] = "associative array"
5385
 *   key[index][] = "nested numeric array"
5386
 *   key[index][index] = "nested associative array"
5387
 * @endverbatim
5388
 *
5389
 * PHP constants are substituted in, but only when used as the entire value:
5390
 *
5391
 * Comments should start with a semi-colon at the beginning of a line.
5392
 *
5393
 * This function is NOT for placing arbitrary module-specific settings. Use
5394
 * variable_get() and variable_set() for that.
5395
 *
5396
 * Information stored in the module.info file:
5397
 * - name: The real name of the module for display purposes.
5398
 * - description: A brief description of the module.
5399
 * - dependencies: An array of shortnames of other modules this module depends on.
5400
 * - package: The name of the package of modules this module belongs to.
5401
 *
5402
 * Example of .info file:
5403
 * <code>
5404
 * @verbatim
5405
 *   name = Forum
5406
 *   description = Enables threaded discussions about general topics.
5407
 *   dependencies[] = taxonomy
5408
 *   dependencies[] = comment
5409
 *   package = Core - optional
5410
 *   version = VERSION
5411
 * @endverbatim
5412
 * </code>
5413
 *
5414
 * @param string $filename
5415
 *                         The file we are parsing. Accepts file with relative or absolute path.
5416
 *
5417
 * @return
5418
 *   The info array
5419
 */
5420
function api_parse_info_file($filename)
5421
{
5422
    $info = [];
5423
5424
    if (!file_exists($filename)) {
5425
        return $info;
5426
    }
5427
5428
    $data = file_get_contents($filename);
5429
    if (preg_match_all('
5430
        @^\s*                           # Start at the beginning of a line, ignoring leading whitespace
5431
        ((?:
5432
          [^=;\[\]]|                    # Key names cannot contain equal signs, semi-colons or square brackets,
5433
          \[[^\[\]]*\]                  # unless they are balanced and not nested
5434
        )+?)
5435
        \s*=\s*                         # Key/value pairs are separated by equal signs (ignoring white-space)
5436
        (?:
5437
          ("(?:[^"]|(?<=\\\\)")*")|     # Double-quoted string, which may contain slash-escaped quotes/slashes
5438
          (\'(?:[^\']|(?<=\\\\)\')*\')| # Single-quoted string, which may contain slash-escaped quotes/slashes
5439
          ([^\r\n]*?)                   # Non-quoted string
5440
        )\s*$                           # Stop at the next end of a line, ignoring trailing whitespace
5441
        @msx', $data, $matches, PREG_SET_ORDER)) {
5442
        $key = $value1 = $value2 = $value3 = '';
5443
        foreach ($matches as $match) {
5444
            // Fetch the key and value string.
5445
            $i = 0;
5446
            foreach (['key', 'value1', 'value2', 'value3'] as $var) {
5447
                $$var = isset($match[++$i]) ? $match[$i] : '';
5448
            }
5449
            $value = stripslashes(substr($value1, 1, -1)).stripslashes(substr($value2, 1, -1)).$value3;
5450
5451
            // Parse array syntax.
5452
            $keys = preg_split('/\]?\[/', rtrim($key, ']'));
5453
            $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

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

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

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

8649
        fclose(/** @scrutinizer ignore-type */ $fp);
Loading history...
8650
    }
8651
8652
    return $isCreated;
8653
}
8654
8655
/**
8656
 * Sends an email
8657
 * Sender name and email can be specified, if not specified
8658
 * name and email of the platform admin are used.
8659
 *
8660
 * @param string    name of recipient
8661
 * @param string    email of recipient
8662
 * @param string    email subject
8663
 * @param string    email body
8664
 * @param string    sender name
8665
 * @param string    sender e-mail
8666
 * @param array     extra headers in form $headers = array($name => $value) to allow parsing
8667
 * @param array     data file (path and filename)
8668
 * @param bool      True for attaching a embedded file inside content html (optional)
8669
 * @param array     Additional parameters
8670
 *
8671
 * @return bool true if mail was sent
8672
 */
8673
function api_mail_html(
8674
    $recipientName,
8675
    $recipientEmail,
8676
    $subject,
8677
    $body,
8678
    $senderName = '',
8679
    $senderEmail = '',
8680
    $extra_headers = [],
8681
    $data_file = [],
8682
    $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

8682
    /** @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...
8683
    $additionalParameters = []
8684
) {
8685
    if (!api_valid_email($recipientEmail)) {
8686
        return false;
8687
    }
8688
8689
    // Default values
8690
    $notification = new Notification();
8691
    $defaultEmail = $notification->getDefaultPlatformSenderEmail();
8692
    $defaultName = $notification->getDefaultPlatformSenderName();
8693
8694
    // If the parameter is set don't use the admin.
8695
    $senderName = !empty($senderName) ? $senderName : $defaultName;
8696
    $senderEmail = !empty($senderEmail) ? $senderEmail : $defaultEmail;
8697
8698
    // Reply to first
8699
    $replyToName = '';
8700
    $replyToEmail = '';
8701
    if (isset($extra_headers['reply_to'])) {
8702
        $replyToEmail = $extra_headers['reply_to']['mail'];
8703
        $replyToName = $extra_headers['reply_to']['name'];
8704
    }
8705
8706
    //If the SMTP configuration only accept one sender
8707
    /*if (isset($platform_email['SMTP_UNIQUE_SENDER']) && $platform_email['SMTP_UNIQUE_SENDER']) {
8708
        $senderName = $platform_email['SMTP_FROM_NAME'];
8709
        $senderEmail = $platform_email['SMTP_FROM_EMAIL'];
8710
        $valid = PHPMailer::validateAddress($senderEmail);
8711
        if ($valid) {
8712
            //force-set Sender to $senderEmail, otherwise SetFrom only does it if it is currently empty
8713
            $mail->Sender = $senderEmail;
8714
        }
8715
    }*/
8716
8717
    /*$mail->SetFrom($senderEmail, $senderName);
8718
    $mail->Subject = $subject;
8719
    $mail->AltBody = strip_tags(
8720
        str_replace('<br />', "\n", api_html_entity_decode($message))
8721
    );*/
8722
8723
    /*if (is_array($extra_headers) && count($extra_headers) > 0) {
8724
        foreach ($extra_headers as $key => $value) {
8725
            switch (strtolower($key)) {
8726
                case 'encoding':
8727
                case 'content-transfer-encoding':
8728
                    $mail->Encoding = $value;
8729
                    break;
8730
                case 'charset':
8731
                    $mail->Charset = $value;
8732
                    break;
8733
                case 'contenttype':
8734
                case 'content-type':
8735
                    $mail->ContentType = $value;
8736
                    break;
8737
                default:
8738
                    $mail->AddCustomHeader($key.':'.$value);
8739
                    break;
8740
            }
8741
        }
8742
    } else {
8743
        if (!empty($extra_headers)) {
8744
            $mail->AddCustomHeader($extra_headers);
8745
        }
8746
    }*/
8747
8748
    // WordWrap the html body (phpMailer only fixes AltBody) FS#2988
8749
    //$mail->Body = $mail->WrapText($mail->Body, $mail->WordWrap);
8750
    try {
8751
        $message = new \Swift_Message($subject);
8752
8753
        $list = api_get_configuration_value('send_all_emails_to');
8754
        if (!empty($list) && isset($list['emails'])) {
8755
            foreach ($list['emails'] as $email) {
8756
                $message->addCc($email);
8757
            }
8758
        }
8759
8760
        // Attachment
8761
        if (!empty($data_file)) {
8762
            foreach ($data_file as $file_attach) {
8763
                if (!empty($file_attach['path']) && !empty($file_attach['filename'])) {
8764
                    //$message->attach(Swift_Attachment::fromPath($file_attach['path'], $file_attach['filename']);
8765
                    $message->attach(
8766
                        Swift_Attachment::fromPath($file_attach['path'])->setFilename($file_attach['filename'])
8767
                    );
8768
                }
8769
            }
8770
        }
8771
8772
        $noReply = api_get_setting('noreply_email_address');
8773
        $automaticEmailText = '';
8774
        if (!empty($noReply)) {
8775
            $automaticEmailText = '<br />'.get_lang('ThisIsAutomaticEmailNoReply');
8776
        }
8777
8778
        $params = [
8779
            'content' => '',
8780
            'mail_header_style' => api_get_configuration_value('mail_header_style'),
8781
            'mail_content_style' => api_get_configuration_value('mail_content_style'),
8782
            'link' => $additionalParameters['link'] ?? '',
8783
            'automatic_email_text' => $automaticEmailText,
8784
        ];
8785
8786
        $paramsHtml = $paramsText = $params;
8787
8788
        $paramsHtml['content'] = $body;
8789
        $paramsText['content'] = str_replace('<br />', "\n", api_html_entity_decode($body));
8790
8791
        if (!empty($senderEmail)) {
8792
            $message->setFrom([$senderEmail => $senderName]);
8793
        }
8794
8795
        if (!empty($recipientEmail)) {
8796
            $message->setTo([$recipientEmail => $recipientName]);
8797
        }
8798
8799
        if (!empty($replyToEmail)) {
8800
            $message->setReplyTo([$replyToEmail => $replyToName]);
8801
        }
8802
8803
        $message
8804
            ->setBody(
8805
                Container::getTwig()->render(
8806
                    'ChamiloCoreBundle:Mailer:Default/default.html.twig',
8807
                    $paramsHtml
8808
                ),
8809
                'text/html'
8810
            )
8811
            ->addPart(
8812
                Container::getTwig()->render(
8813
                    'ChamiloCoreBundle:Mailer:Default/default.text.twig',
8814
                    $paramsText
8815
                ),
8816
                'text/plain'
8817
            )
8818
            //->setEncoder(\Swift_Encoding::get8BitEncoding())
8819
        ;
8820
8821
        $type = $message->getHeaders()->get('Content-Type');
8822
        $type->setCharset('utf-8');
8823
        Container::getMailer()->send($message);
8824
8825
        return true;
8826
    } catch (Exception $e) {
8827
        error_log($e->getMessage());
8828
    }
8829
8830
    if (!empty($additionalParameters)) {
8831
        $plugin = new AppPlugin();
8832
        $smsPlugin = $plugin->getSMSPluginLibrary();
8833
        if ($smsPlugin) {
0 ignored issues
show
introduced by
$smsPlugin is of type SmsPluginLibraryInterface, thus it always evaluated to true.
Loading history...
8834
            $smsPlugin->send($additionalParameters);
8835
        }
8836
    }
8837
8838
    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...
8839
}
8840
8841
/**
8842
 * @param string $tool       Possible values: GroupManager::GROUP_TOOL_*
8843
 * @param bool   $showHeader
8844
 */
8845
function api_protect_course_group($tool, $showHeader = true)
8846
{
8847
    $userId = api_get_user_id();
8848
    $groupId = api_get_group_id();
8849
    $groupInfo = GroupManager::get_group_properties($groupId);
8850
8851
    if (!empty($groupInfo)) {
8852
        $allow = GroupManager::user_has_access(
8853
            $userId,
8854
            $groupInfo['iid'],
8855
            $tool
8856
        );
8857
8858
        if (!$allow) {
8859
            api_not_allowed($showHeader);
8860
        }
8861
    }
8862
}
8863
8864
/**
8865
 * Check if a date is in a date range.
8866
 *
8867
 * @param datetime $startDate
8868
 * @param datetime $endDate
8869
 * @param datetime $currentDate
8870
 *
8871
 * @return bool true if date is in rage, false otherwise
8872
 */
8873
function api_is_date_in_date_range($startDate, $endDate, $currentDate = null)
8874
{
8875
    $startDate = strtotime(api_get_local_time($startDate));
8876
    $endDate = strtotime(api_get_local_time($endDate));
8877
    $currentDate = strtotime(api_get_local_time($currentDate));
8878
8879
    if ($currentDate >= $startDate && $currentDate <= $endDate) {
8880
        return true;
8881
    }
8882
8883
    return false;
8884
}
8885
8886
/**
8887
 * Eliminate the duplicates of a multidimensional array by sending the key.
8888
 *
8889
 * @param array $array multidimensional array
8890
 * @param int   $key   key to find to compare
8891
 *
8892
 * @return array
8893
 */
8894
function api_unique_multidim_array($array, $key)
8895
{
8896
    $temp_array = [];
8897
    $i = 0;
8898
    $key_array = [];
8899
8900
    foreach ($array as $val) {
8901
        if (!in_array($val[$key], $key_array)) {
8902
            $key_array[$i] = $val[$key];
8903
            $temp_array[$i] = $val;
8904
        }
8905
        $i++;
8906
    }
8907
8908
    return $temp_array;
8909
}
8910
8911
/**
8912
 * Limit the access to Session Admins when the limit_session_admin_role
8913
 * configuration variable is set to true.
8914
 */
8915
function api_protect_limit_for_session_admin()
8916
{
8917
    $limitAdmin = api_get_setting('limit_session_admin_role');
8918
    if (api_is_session_admin() && $limitAdmin === 'true') {
8919
        api_not_allowed(true);
8920
    }
8921
}
8922
8923
/**
8924
 * Limits that a session admin has access to list users.
8925
 * When limit_session_admin_list_users configuration variable is set to true.
8926
 */
8927
function api_protect_session_admin_list_users()
8928
{
8929
    $limitAdmin = api_get_configuration_value('limit_session_admin_list_users');
8930
8931
    if (api_is_session_admin() && true === $limitAdmin) {
8932
        api_not_allowed(true);
8933
    }
8934
}
8935
8936
/**
8937
 * @return bool
8938
 */
8939
function api_is_student_view_active()
8940
{
8941
    $studentView = Session::read('studentview');
8942
8943
    return $studentView === 'studentview';
8944
}
8945
8946
/**
8947
 * Adds a file inside the upload/$type/id.
8948
 *
8949
 * @param string $type
8950
 * @param array  $file
8951
 * @param int    $itemId
8952
 * @param string $cropParameters
8953
 *
8954
 * @return array|bool
8955
 */
8956
function api_upload_file($type, $file, $itemId, $cropParameters = '')
8957
{
8958
    $upload = process_uploaded_file($file);
8959
    if ($upload) {
8960
        $name = api_replace_dangerous_char($file['name']);
8961
8962
        // No "dangerous" files
8963
        $name = disable_dangerous_file($name);
8964
8965
        $pathId = '/'.substr((string) $itemId, 0, 1).'/'.$itemId.'/';
8966
        $path = api_get_path(SYS_UPLOAD_PATH).$type.$pathId;
8967
8968
        if (!is_dir($path)) {
8969
            mkdir($path, api_get_permissions_for_new_directories(), true);
8970
        }
8971
8972
        $pathToSave = $path.$name;
8973
        $result = moveUploadedFile($file, $pathToSave);
8974
8975
        if ($result) {
8976
            if (!empty($cropParameters)) {
8977
                $image = new Image($pathToSave);
8978
                $image->crop($cropParameters);
8979
            }
8980
8981
            return ['path_to_save' => $pathId.$name];
8982
        }
8983
8984
        return false;
8985
    }
8986
}
8987
8988
/**
8989
 * @param string $type
8990
 * @param int    $itemId
8991
 * @param string $file
8992
 *
8993
 * @return bool
8994
 */
8995
function api_get_uploaded_web_url($type, $itemId, $file)
8996
{
8997
    return api_get_uploaded_file($type, $itemId, $file, true);
8998
}
8999
9000
/**
9001
 * @param string $type
9002
 * @param int    $itemId
9003
 * @param string $file
9004
 * @param bool   $getUrl
9005
 *
9006
 * @return bool
9007
 */
9008
function api_get_uploaded_file($type, $itemId, $file, $getUrl = false)
9009
{
9010
    $itemId = (int) $itemId;
9011
    $pathId = '/'.substr((string) $itemId, 0, 1).'/'.$itemId.'/';
9012
    $path = api_get_path(SYS_UPLOAD_PATH).$type.$pathId;
9013
    $file = basename($file);
9014
    $file = $path.'/'.$file;
9015
    if (Security::check_abs_path($file, $path) && is_file($file) && file_exists($file)) {
9016
        if ($getUrl) {
9017
            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...
9018
        }
9019
9020
        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...
9021
    }
9022
9023
    return false;
9024
}
9025
9026
/**
9027
 * @param string $type
9028
 * @param int    $itemId
9029
 * @param string $file
9030
 * @param string $title
9031
 */
9032
function api_download_uploaded_file($type, $itemId, $file, $title = '')
9033
{
9034
    $file = api_get_uploaded_file($type, $itemId, $file);
9035
    if ($file) {
9036
        if (Security::check_abs_path($file, api_get_path(SYS_UPLOAD_PATH).$type)) {
9037
            DocumentManager::file_send_for_download($file, true, $title);
9038
            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...
9039
        }
9040
    }
9041
    api_not_allowed(true);
9042
}
9043
9044
/**
9045
 * @param string $type
9046
 * @param string $file
9047
 */
9048
function api_remove_uploaded_file($type, $file)
9049
{
9050
    $typePath = api_get_path(SYS_UPLOAD_PATH).$type;
9051
    $path = $typePath.'/'.$file;
9052
    if (Security::check_abs_path($path, $typePath) && file_exists($path) && is_file($path)) {
9053
        unlink($path);
9054
    }
9055
}
9056
9057
/**
9058
 * @param string $type
9059
 * @param int    $itemId
9060
 * @param string $file
9061
 *
9062
 * @return bool
9063
 */
9064
function api_remove_uploaded_file_by_id($type, $itemId, $file)
9065
{
9066
    $file = api_get_uploaded_file($type, $itemId, $file, false);
9067
    $typePath = api_get_path(SYS_UPLOAD_PATH).$type;
9068
    if (Security::check_abs_path($file, $typePath) && file_exists($file) && is_file($file)) {
9069
        unlink($file);
9070
9071
        return true;
9072
    }
9073
9074
    return false;
9075
}
9076
9077
/**
9078
 * Converts string value to float value.
9079
 *
9080
 * 3.141516 => 3.141516
9081
 * 3,141516 => 3.141516
9082
 *
9083
 * @todo WIP
9084
 *
9085
 * @param string $number
9086
 *
9087
 * @return float
9088
 */
9089
function api_float_val($number)
9090
{
9091
    $number = (float) str_replace(',', '.', trim($number));
9092
9093
    return $number;
9094
}
9095
9096
/**
9097
 * Converts float values
9098
 * Example if $decimals = 2.
9099
 *
9100
 * 3.141516 => 3.14
9101
 * 3,141516 => 3,14
9102
 *
9103
 * @param string $number            number in iso code
9104
 * @param int    $decimals
9105
 * @param string $decimalSeparator
9106
 * @param string $thousandSeparator
9107
 *
9108
 * @return bool|string
9109
 */
9110
function api_number_format($number, $decimals = 0, $decimalSeparator = '.', $thousandSeparator = ',')
9111
{
9112
    $number = api_float_val($number);
9113
9114
    return number_format($number, $decimals, $decimalSeparator, $thousandSeparator);
9115
}
9116
9117
/**
9118
 * Set location url with a exit break by default.
9119
 *
9120
 * @param $url
9121
 * @param bool $exit
9122
 */
9123
function location($url, $exit = true)
9124
{
9125
    header('Location: '.$url);
9126
9127
    if ($exit) {
9128
        exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
9129
    }
9130
}
9131
9132
/**
9133
 * @return string
9134
 */
9135
function api_get_web_url()
9136
{
9137
    if (api_get_setting('server_type') === 'test') {
9138
        return api_get_path(WEB_PATH).'web/app_dev.php/';
9139
    } else {
9140
        return api_get_path(WEB_PATH).'web/';
9141
    }
9142
}
9143
9144
/**
9145
 * @param string $from
9146
 * @param string $to
9147
 *
9148
 * @return string
9149
 */
9150
function api_get_relative_path($from, $to)
9151
{
9152
    // some compatibility fixes for Windows paths
9153
    $from = is_dir($from) ? rtrim($from, '\/').'/' : $from;
9154
    $to = is_dir($to) ? rtrim($to, '\/').'/' : $to;
9155
    $from = str_replace('\\', '/', $from);
9156
    $to = str_replace('\\', '/', $to);
9157
9158
    $from = explode('/', $from);
9159
    $to = explode('/', $to);
9160
    $relPath = $to;
9161
9162
    foreach ($from as $depth => $dir) {
9163
        // find first non-matching dir
9164
        if ($dir === $to[$depth]) {
9165
            // ignore this directory
9166
            array_shift($relPath);
9167
        } else {
9168
            // get number of remaining dirs to $from
9169
            $remaining = count($from) - $depth;
9170
            if ($remaining > 1) {
9171
                // add traversals up to first matching dir
9172
                $padLength = (count($relPath) + $remaining - 1) * -1;
9173
                $relPath = array_pad($relPath, $padLength, '..');
9174
                break;
9175
            } else {
9176
                $relPath[0] = './'.$relPath[0];
9177
            }
9178
        }
9179
    }
9180
9181
    return implode('/', $relPath);
9182
}
9183