Passed
Push — master ( d0b226...f5358a )
by Julito
10:41
created

api_get_language_translate_html()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 29
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

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

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

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

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

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

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

5260
            $files = copyr("$source/$entry", "$dest/$entry", $exclude, /** @scrutinizer ignore-type */ $copied_files);
Loading history...
5261
        }
5262
    }
5263
    // Clean up.
5264
    $dir->close();
5265
5266
    return true;
5267
}
5268
5269
/**
5270
 * @todo: Using DIRECTORY_SEPARATOR is not recommended, this is an obsolete approach.
5271
 * Documentation header to be added here.
5272
 *
5273
 * @param string $pathname
5274
 * @param string $base_path_document
5275
 * @param int    $session_id
5276
 *
5277
 * @return mixed True if directory already exists, false if a file already exists at
5278
 *               the destination and null if everything goes according to plan
5279
 */
5280
function copy_folder_course_session(
5281
    $pathname,
5282
    $base_path_document,
5283
    $session_id,
5284
    $course_info,
5285
    $document,
5286
    $source_course_id
5287
) {
5288
    $table = Database::get_course_table(TABLE_DOCUMENT);
5289
    $session_id = intval($session_id);
5290
    $source_course_id = intval($source_course_id);
5291
5292
    // Check whether directory already exists.
5293
    if (is_dir($pathname) || empty($pathname)) {
5294
        return true;
5295
    }
5296
5297
    // Ensure that a file with the same name does not already exist.
5298
    if (is_file($pathname)) {
5299
        trigger_error('copy_folder_course_session(): File exists', E_USER_WARNING);
5300
5301
        return false;
5302
    }
5303
5304
    $course_id = $course_info['real_id'];
5305
    $folders = explode(DIRECTORY_SEPARATOR, str_replace($base_path_document.DIRECTORY_SEPARATOR, '', $pathname));
5306
    $new_pathname = $base_path_document;
5307
    $path = '';
5308
5309
    foreach ($folders as $folder) {
5310
        $new_pathname .= DIRECTORY_SEPARATOR.$folder;
5311
        $path .= DIRECTORY_SEPARATOR.$folder;
5312
5313
        if (!file_exists($new_pathname)) {
5314
            $path = Database::escape_string($path);
5315
5316
            $sql = "SELECT * FROM $table
5317
                    WHERE
5318
                        c_id = $source_course_id AND
5319
                        path = '$path' AND
5320
                        filetype = 'folder' AND
5321
                        session_id = '$session_id'";
5322
            $rs1 = Database::query($sql);
5323
            $num_rows = Database::num_rows($rs1);
5324
5325
            if ($num_rows == 0) {
5326
                mkdir($new_pathname, api_get_permissions_for_new_directories());
5327
5328
                // Insert new folder with destination session_id.
5329
                $params = [
5330
                    'c_id' => $course_id,
5331
                    'path' => $path,
5332
                    'comment' => $document->comment,
5333
                    'title' => basename($new_pathname),
5334
                    'filetype' => 'folder',
5335
                    'size' => '0',
5336
                    'session_id' => $session_id,
5337
                ];
5338
                $document_id = Database::insert($table, $params);
5339
                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...
5340
                    $sql = "UPDATE $table SET id = iid WHERE iid = $document_id";
5341
                    Database::query($sql);
5342
5343
                    api_item_property_update(
5344
                        $course_info,
5345
                        TOOL_DOCUMENT,
5346
                        $document_id,
5347
                        'FolderCreated',
5348
                        api_get_user_id(),
5349
                        0,
5350
                        0,
5351
                        null,
5352
                        null,
5353
                        $session_id
5354
                    );
5355
                }
5356
            }
5357
        }
5358
    } // en foreach
5359
}
5360
5361
// TODO: chmodr() is a better name. Some corrections are needed. Documentation header to be added here.
5362
/**
5363
 * @param string $path
5364
 */
5365
function api_chmod_R($path, $filemode)
5366
{
5367
    if (!is_dir($path)) {
5368
        return chmod($path, $filemode);
5369
    }
5370
5371
    $handler = opendir($path);
5372
    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

5372
    while ($file = readdir(/** @scrutinizer ignore-type */ $handler)) {
Loading history...
5373
        if ($file != '.' && $file != '..') {
5374
            $fullpath = "$path/$file";
5375
            if (!is_dir($fullpath)) {
5376
                if (!chmod($fullpath, $filemode)) {
5377
                    return false;
5378
                }
5379
            } else {
5380
                if (!api_chmod_R($fullpath, $filemode)) {
5381
                    return false;
5382
                }
5383
            }
5384
        }
5385
    }
5386
5387
    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

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

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

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

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

8674
        fclose(/** @scrutinizer ignore-type */ $fp);
Loading history...
8675
    }
8676
8677
    return $isCreated;
8678
}
8679
8680
/**
8681
 * Sends an email
8682
 * Sender name and email can be specified, if not specified
8683
 * name and email of the platform admin are used.
8684
 *
8685
 * @param string    name of recipient
8686
 * @param string    email of recipient
8687
 * @param string    email subject
8688
 * @param string    email body
8689
 * @param string    sender name
8690
 * @param string    sender e-mail
8691
 * @param array     extra headers in form $headers = array($name => $value) to allow parsing
8692
 * @param array     data file (path and filename)
8693
 * @param bool      True for attaching a embedded file inside content html (optional)
8694
 * @param array     Additional parameters
8695
 *
8696
 * @return bool true if mail was sent
8697
 */
8698
function api_mail_html(
8699
    $recipientName,
8700
    $recipientEmail,
8701
    $subject,
8702
    $body,
8703
    $senderName = '',
8704
    $senderEmail = '',
8705
    $extra_headers = [],
8706
    $data_file = [],
8707
    $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

8707
    /** @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...
8708
    $additionalParameters = []
8709
) {
8710
    if (!api_valid_email($recipientEmail)) {
8711
        return false;
8712
    }
8713
8714
    // Default values
8715
    $notification = new Notification();
8716
    $defaultEmail = $notification->getDefaultPlatformSenderEmail();
8717
    $defaultName = $notification->getDefaultPlatformSenderName();
8718
8719
    // If the parameter is set don't use the admin.
8720
    $senderName = !empty($senderName) ? $senderName : $defaultName;
8721
    $senderEmail = !empty($senderEmail) ? $senderEmail : $defaultEmail;
8722
8723
    // Reply to first
8724
    $replyToName = '';
8725
    $replyToEmail = '';
8726
    if (isset($extra_headers['reply_to'])) {
8727
        $replyToEmail = $extra_headers['reply_to']['mail'];
8728
        $replyToName = $extra_headers['reply_to']['name'];
8729
    }
8730
8731
    //If the SMTP configuration only accept one sender
8732
    /*if (isset($platform_email['SMTP_UNIQUE_SENDER']) && $platform_email['SMTP_UNIQUE_SENDER']) {
8733
        $senderName = $platform_email['SMTP_FROM_NAME'];
8734
        $senderEmail = $platform_email['SMTP_FROM_EMAIL'];
8735
        $valid = PHPMailer::validateAddress($senderEmail);
8736
        if ($valid) {
8737
            //force-set Sender to $senderEmail, otherwise SetFrom only does it if it is currently empty
8738
            $mail->Sender = $senderEmail;
8739
        }
8740
    }*/
8741
8742
    /*$mail->SetFrom($senderEmail, $senderName);
8743
    $mail->Subject = $subject;
8744
    $mail->AltBody = strip_tags(
8745
        str_replace('<br />', "\n", api_html_entity_decode($message))
8746
    );*/
8747
8748
    /*if (is_array($extra_headers) && count($extra_headers) > 0) {
8749
        foreach ($extra_headers as $key => $value) {
8750
            switch (strtolower($key)) {
8751
                case 'encoding':
8752
                case 'content-transfer-encoding':
8753
                    $mail->Encoding = $value;
8754
                    break;
8755
                case 'charset':
8756
                    $mail->Charset = $value;
8757
                    break;
8758
                case 'contenttype':
8759
                case 'content-type':
8760
                    $mail->ContentType = $value;
8761
                    break;
8762
                default:
8763
                    $mail->AddCustomHeader($key.':'.$value);
8764
                    break;
8765
            }
8766
        }
8767
    } else {
8768
        if (!empty($extra_headers)) {
8769
            $mail->AddCustomHeader($extra_headers);
8770
        }
8771
    }*/
8772
8773
    // WordWrap the html body (phpMailer only fixes AltBody) FS#2988
8774
    //$mail->Body = $mail->WrapText($mail->Body, $mail->WordWrap);
8775
    try {
8776
        $message = new \Swift_Message($subject);
8777
8778
        $list = api_get_configuration_value('send_all_emails_to');
8779
        if (!empty($list) && isset($list['emails'])) {
8780
            foreach ($list['emails'] as $email) {
8781
                $message->addCc($email);
8782
            }
8783
        }
8784
8785
        // Attachment
8786
        if (!empty($data_file)) {
8787
            foreach ($data_file as $file_attach) {
8788
                if (!empty($file_attach['path']) && !empty($file_attach['filename'])) {
8789
                    //$message->attach(Swift_Attachment::fromPath($file_attach['path'], $file_attach['filename']);
8790
                    $message->attach(
8791
                        Swift_Attachment::fromPath($file_attach['path'])->setFilename($file_attach['filename'])
8792
                    );
8793
                }
8794
            }
8795
        }
8796
8797
        $noReply = api_get_setting('noreply_email_address');
8798
        $automaticEmailText = '';
8799
        if (!empty($noReply)) {
8800
            $automaticEmailText = '<br />'.get_lang('ThisIsAutomaticEmailNoReply');
8801
        }
8802
8803
        $params = [
8804
            'content' => '',
8805
            'mail_header_style' => api_get_configuration_value('mail_header_style'),
8806
            'mail_content_style' => api_get_configuration_value('mail_content_style'),
8807
            'link' => $additionalParameters['link'] ?? '',
8808
            'automatic_email_text' => $automaticEmailText,
8809
        ];
8810
8811
        $paramsHtml = $paramsText = $params;
8812
8813
        $paramsHtml['content'] = $body;
8814
        $paramsText['content'] = str_replace('<br />', "\n", api_html_entity_decode($body));
8815
8816
        if (!empty($senderEmail)) {
8817
            $message->setFrom([$senderEmail => $senderName]);
8818
        }
8819
8820
        if (!empty($recipientEmail)) {
8821
            $message->setTo([$recipientEmail => $recipientName]);
8822
        }
8823
8824
        if (!empty($replyToEmail)) {
8825
            $message->setReplyTo([$replyToEmail => $replyToName]);
8826
        }
8827
8828
        $message
8829
            ->setBody(
8830
                Container::getTwig()->render(
8831
                    'ChamiloThemeBundle:Mailer:Default/default.html.twig',
8832
                    $paramsHtml
8833
                ),
8834
                'text/html'
8835
            )
8836
            ->addPart(
8837
                Container::getTwig()->render(
8838
                    'ChamiloThemeBundle:Mailer:Default/default.text.twig',
8839
                    $paramsText
8840
                ),
8841
                'text/plain'
8842
            )
8843
            //->setEncoder(\Swift_Encoding::get8BitEncoding())
8844
        ;
8845
8846
        $type = $message->getHeaders()->get('Content-Type');
8847
        $type->setCharset('utf-8');
8848
        Container::getMailer()->send($message);
8849
8850
        return true;
8851
    } catch (Exception $e) {
8852
        error_log($e->getMessage());
8853
    }
8854
8855
    if (!empty($additionalParameters)) {
8856
        $plugin = new AppPlugin();
8857
        $smsPlugin = $plugin->getSMSPluginLibrary();
8858
        if ($smsPlugin) {
0 ignored issues
show
introduced by
$smsPlugin is of type SmsPluginLibraryInterface, thus it always evaluated to true.
Loading history...
8859
            $smsPlugin->send($additionalParameters);
8860
        }
8861
    }
8862
8863
    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...
8864
}
8865
8866
/**
8867
 * @param string $tool       Possible values: GroupManager::GROUP_TOOL_*
8868
 * @param bool   $showHeader
8869
 */
8870
function api_protect_course_group($tool, $showHeader = true)
8871
{
8872
    $userId = api_get_user_id();
8873
    $groupId = api_get_group_id();
8874
    $groupInfo = GroupManager::get_group_properties($groupId);
8875
8876
    if (!empty($groupInfo)) {
8877
        $allow = GroupManager::user_has_access(
8878
            $userId,
8879
            $groupInfo['iid'],
8880
            $tool
8881
        );
8882
8883
        if (!$allow) {
8884
            api_not_allowed($showHeader);
8885
        }
8886
    }
8887
}
8888
8889
/**
8890
 * Check if a date is in a date range.
8891
 *
8892
 * @param datetime $startDate
8893
 * @param datetime $endDate
8894
 * @param datetime $currentDate
8895
 *
8896
 * @return bool true if date is in rage, false otherwise
8897
 */
8898
function api_is_date_in_date_range($startDate, $endDate, $currentDate = null)
8899
{
8900
    $startDate = strtotime(api_get_local_time($startDate));
8901
    $endDate = strtotime(api_get_local_time($endDate));
8902
    $currentDate = strtotime(api_get_local_time($currentDate));
8903
8904
    if ($currentDate >= $startDate && $currentDate <= $endDate) {
8905
        return true;
8906
    }
8907
8908
    return false;
8909
}
8910
8911
/**
8912
 * Eliminate the duplicates of a multidimensional array by sending the key.
8913
 *
8914
 * @param array $array multidimensional array
8915
 * @param int   $key   key to find to compare
8916
 *
8917
 * @return array
8918
 */
8919
function api_unique_multidim_array($array, $key)
8920
{
8921
    $temp_array = [];
8922
    $i = 0;
8923
    $key_array = [];
8924
8925
    foreach ($array as $val) {
8926
        if (!in_array($val[$key], $key_array)) {
8927
            $key_array[$i] = $val[$key];
8928
            $temp_array[$i] = $val;
8929
        }
8930
        $i++;
8931
    }
8932
8933
    return $temp_array;
8934
}
8935
8936
/**
8937
 * Limit the access to Session Admins when the limit_session_admin_role
8938
 * configuration variable is set to true.
8939
 */
8940
function api_protect_limit_for_session_admin()
8941
{
8942
    $limitAdmin = api_get_setting('limit_session_admin_role');
8943
    if (api_is_session_admin() && $limitAdmin === 'true') {
8944
        api_not_allowed(true);
8945
    }
8946
}
8947
8948
/**
8949
 * Limits that a session admin has access to list users.
8950
 * When limit_session_admin_list_users configuration variable is set to true.
8951
 */
8952
function api_protect_session_admin_list_users()
8953
{
8954
    $limitAdmin = api_get_configuration_value('limit_session_admin_list_users');
8955
8956
    if (api_is_session_admin() && true === $limitAdmin) {
8957
        api_not_allowed(true);
8958
    }
8959
}
8960
8961
/**
8962
 * @return bool
8963
 */
8964
function api_is_student_view_active()
8965
{
8966
    $studentView = Session::read('studentview');
8967
8968
    return $studentView === 'studentview';
8969
}
8970
8971
/**
8972
 * Adds a file inside the upload/$type/id.
8973
 *
8974
 * @param string $type
8975
 * @param array  $file
8976
 * @param int    $itemId
8977
 * @param string $cropParameters
8978
 *
8979
 * @return array|bool
8980
 */
8981
function api_upload_file($type, $file, $itemId, $cropParameters = '')
8982
{
8983
    $upload = process_uploaded_file($file);
8984
    if ($upload) {
8985
        $name = api_replace_dangerous_char($file['name']);
8986
8987
        // No "dangerous" files
8988
        $name = disable_dangerous_file($name);
8989
8990
        $pathId = '/'.substr((string) $itemId, 0, 1).'/'.$itemId.'/';
8991
        $path = api_get_path(SYS_UPLOAD_PATH).$type.$pathId;
8992
8993
        if (!is_dir($path)) {
8994
            mkdir($path, api_get_permissions_for_new_directories(), true);
8995
        }
8996
8997
        $pathToSave = $path.$name;
8998
        $result = moveUploadedFile($file, $pathToSave);
8999
9000
        if ($result) {
9001
            if (!empty($cropParameters)) {
9002
                $image = new Image($pathToSave);
9003
                $image->crop($cropParameters);
9004
            }
9005
9006
            return ['path_to_save' => $pathId.$name];
9007
        }
9008
9009
        return false;
9010
    }
9011
}
9012
9013
/**
9014
 * @param string $type
9015
 * @param int    $itemId
9016
 * @param string $file
9017
 *
9018
 * @return bool
9019
 */
9020
function api_get_uploaded_web_url($type, $itemId, $file)
9021
{
9022
    return api_get_uploaded_file($type, $itemId, $file, true);
9023
}
9024
9025
/**
9026
 * @param string $type
9027
 * @param int    $itemId
9028
 * @param string $file
9029
 * @param bool   $getUrl
9030
 *
9031
 * @return bool
9032
 */
9033
function api_get_uploaded_file($type, $itemId, $file, $getUrl = false)
9034
{
9035
    $itemId = (int) $itemId;
9036
    $pathId = '/'.substr((string) $itemId, 0, 1).'/'.$itemId.'/';
9037
    $path = api_get_path(SYS_UPLOAD_PATH).$type.$pathId;
9038
    $file = basename($file);
9039
    $file = $path.'/'.$file;
9040
    if (Security::check_abs_path($file, $path) && is_file($file) && file_exists($file)) {
9041
        if ($getUrl) {
9042
            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...
9043
        }
9044
9045
        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...
9046
    }
9047
9048
    return false;
9049
}
9050
9051
/**
9052
 * @param string $type
9053
 * @param int    $itemId
9054
 * @param string $file
9055
 * @param string $title
9056
 */
9057
function api_download_uploaded_file($type, $itemId, $file, $title = '')
9058
{
9059
    $file = api_get_uploaded_file($type, $itemId, $file);
9060
    if ($file) {
9061
        if (Security::check_abs_path($file, api_get_path(SYS_UPLOAD_PATH).$type)) {
9062
            DocumentManager::file_send_for_download($file, true, $title);
9063
            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...
9064
        }
9065
    }
9066
    api_not_allowed(true);
9067
}
9068
9069
/**
9070
 * @param string $type
9071
 * @param string $file
9072
 */
9073
function api_remove_uploaded_file($type, $file)
9074
{
9075
    $typePath = api_get_path(SYS_UPLOAD_PATH).$type;
9076
    $path = $typePath.'/'.$file;
9077
    if (Security::check_abs_path($path, $typePath) && file_exists($path) && is_file($path)) {
9078
        unlink($path);
9079
    }
9080
}
9081
9082
/**
9083
 * @param string $type
9084
 * @param int    $itemId
9085
 * @param string $file
9086
 *
9087
 * @return bool
9088
 */
9089
function api_remove_uploaded_file_by_id($type, $itemId, $file)
9090
{
9091
    $file = api_get_uploaded_file($type, $itemId, $file, false);
9092
    $typePath = api_get_path(SYS_UPLOAD_PATH).$type;
9093
    if (Security::check_abs_path($file, $typePath) && file_exists($file) && is_file($file)) {
9094
        unlink($file);
9095
9096
        return true;
9097
    }
9098
9099
    return false;
9100
}
9101
9102
/**
9103
 * Converts string value to float value.
9104
 *
9105
 * 3.141516 => 3.141516
9106
 * 3,141516 => 3.141516
9107
 *
9108
 * @todo WIP
9109
 *
9110
 * @param string $number
9111
 *
9112
 * @return float
9113
 */
9114
function api_float_val($number)
9115
{
9116
    $number = (float) str_replace(',', '.', trim($number));
9117
9118
    return $number;
9119
}
9120
9121
/**
9122
 * Converts float values
9123
 * Example if $decimals = 2.
9124
 *
9125
 * 3.141516 => 3.14
9126
 * 3,141516 => 3,14
9127
 *
9128
 * @param string $number            number in iso code
9129
 * @param int    $decimals
9130
 * @param string $decimalSeparator
9131
 * @param string $thousandSeparator
9132
 *
9133
 * @return bool|string
9134
 */
9135
function api_number_format($number, $decimals = 0, $decimalSeparator = '.', $thousandSeparator = ',')
9136
{
9137
    $number = api_float_val($number);
9138
9139
    return number_format($number, $decimals, $decimalSeparator, $thousandSeparator);
9140
}
9141
9142
/**
9143
 * Set location url with a exit break by default.
9144
 *
9145
 * @param $url
9146
 * @param bool $exit
9147
 */
9148
function location($url, $exit = true)
9149
{
9150
    header('Location: '.$url);
9151
9152
    if ($exit) {
9153
        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...
9154
    }
9155
}
9156
9157
/**
9158
 * @return string
9159
 */
9160
function api_get_web_url()
9161
{
9162
    if (api_get_setting('server_type') === 'test') {
9163
        return api_get_path(WEB_PATH).'web/app_dev.php/';
9164
    } else {
9165
        return api_get_path(WEB_PATH).'web/';
9166
    }
9167
}
9168
9169
/**
9170
 * @param string $from
9171
 * @param string $to
9172
 *
9173
 * @return string
9174
 */
9175
function api_get_relative_path($from, $to)
9176
{
9177
    // some compatibility fixes for Windows paths
9178
    $from = is_dir($from) ? rtrim($from, '\/').'/' : $from;
9179
    $to = is_dir($to) ? rtrim($to, '\/').'/' : $to;
9180
    $from = str_replace('\\', '/', $from);
9181
    $to = str_replace('\\', '/', $to);
9182
9183
    $from = explode('/', $from);
9184
    $to = explode('/', $to);
9185
    $relPath = $to;
9186
9187
    foreach ($from as $depth => $dir) {
9188
        // find first non-matching dir
9189
        if ($dir === $to[$depth]) {
9190
            // ignore this directory
9191
            array_shift($relPath);
9192
        } else {
9193
            // get number of remaining dirs to $from
9194
            $remaining = count($from) - $depth;
9195
            if ($remaining > 1) {
9196
                // add traversals up to first matching dir
9197
                $padLength = (count($relPath) + $remaining - 1) * -1;
9198
                $relPath = array_pad($relPath, $padLength, '..');
9199
                break;
9200
            } else {
9201
                $relPath[0] = './'.$relPath[0];
9202
            }
9203
        }
9204
    }
9205
9206
    return implode('/', $relPath);
9207
}
9208
9209
/**
9210
 * Unserialize content using Brummann\Polyfill\Unserialize.
9211
 *
9212
 * @param string $type
9213
 * @param string $serialized
9214
 * @param bool   $ignoreErrors. Optional.
9215
 *
9216
 * @return mixed
9217
 */
9218
function api_unserialize_content($type, $serialized, $ignoreErrors = false)
9219
{
9220
    switch ($type) {
9221
        case 'career':
9222
        case 'sequence_graph':
9223
            $allowedClasses = [Graph::class, VerticesMap::class, Vertices::class, Edges::class];
9224
            break;
9225
        case 'lp':
9226
            $allowedClasses = [
9227
                learnpath::class,
9228
                learnpathItem::class,
9229
                aicc::class,
9230
                aiccBlock::class,
9231
                aiccItem::class,
9232
                aiccObjective::class,
9233
                aiccResource::class,
9234
                scorm::class,
9235
                scormItem::class,
9236
                scormMetadata::class,
9237
                scormOrganization::class,
9238
                scormResource::class,
9239
                Link::class,
9240
                LpItem::class,
9241
            ];
9242
            break;
9243
        case 'course':
9244
            $allowedClasses = [
9245
                Course::class,
9246
                Announcement::class,
9247
                Attendance::class,
9248
                CalendarEvent::class,
9249
                CourseCopyLearnpath::class,
9250
                CourseCopyTestCategory::class,
9251
                CourseDescription::class,
9252
                CourseSession::class,
9253
                Document::class,
9254
                Forum::class,
9255
                ForumCategory::class,
9256
                ForumPost::class,
9257
                ForumTopic::class,
9258
                Glossary::class,
9259
                GradeBookBackup::class,
9260
                Link::class,
9261
                LinkCategory::class,
9262
                Quiz::class,
9263
                QuizQuestion::class,
9264
                QuizQuestionOption::class,
9265
                ScormDocument::class,
9266
                Survey::class,
9267
                SurveyInvitation::class,
9268
                SurveyQuestion::class,
9269
                Thematic::class,
9270
                ToolIntro::class,
9271
                Wiki::class,
9272
                Work::class,
9273
                stdClass::class,
9274
            ];
9275
            break;
9276
        case 'not_allowed_classes':
9277
        default:
9278
            $allowedClasses = false;
9279
    }
9280
9281
    if ($ignoreErrors) {
9282
        return @Unserialize::unserialize(
9283
            $serialized,
9284
            ['allowed_classes' => $allowedClasses]
9285
        );
9286
    }
9287
9288
    return Unserialize::unserialize(
9289
        $serialized,
9290
        ['allowed_classes' => $allowedClasses]
9291
    );
9292
}
9293
9294
/**
9295
 * Set the From and ReplyTo properties to PHPMailer instance.
9296
 *
9297
 * @param PHPMailer $mailer
9298
 * @param array     $sender
9299
 * @param array     $replyToAddress
9300
 *
9301
 * @throws phpmailerException
9302
 */
9303
function api_set_noreply_and_from_address_to_mailer(PHPMailer $mailer, array $sender, array $replyToAddress = [])
9304
{
9305
    $platformEmail = $GLOBALS['platform_email'];
9306
9307
    $noReplyAddress = api_get_setting('noreply_email_address');
9308
    $avoidReplyToAddress = false;
9309
9310
    if (!empty($noReplyAddress)) {
9311
        $avoidReplyToAddress = api_get_configuration_value('mail_no_reply_avoid_reply_to');
9312
    }
9313
9314
    $notification = new Notification();
9315
9316
    // If the parameter is set don't use the admin.
9317
    $senderName = !empty($sender['name']) ? $sender['name'] : $notification->getDefaultPlatformSenderName();
9318
    $senderEmail = !empty($sender['email']) ? $sender['email'] : $notification->getDefaultPlatformSenderEmail();
9319
9320
    // Reply to first
9321
    if (!$avoidReplyToAddress) {
9322
        $mailer->AddCustomHeader('Errors-To: '.$notification->getDefaultPlatformSenderEmail());
9323
9324
        if (
9325
            !empty($replyToAddress) &&
9326
            $platformEmail['SMTP_UNIQUE_REPLY_TO'] &&
9327
            PHPMailer::ValidateAddress($replyToAddress['mail'])
9328
        ) {
9329
            $mailer->AddReplyTo($replyToAddress['email'], $replyToAddress['name']);
9330
            // Errors to sender
9331
            $mailer->AddCustomHeader('Errors-To: '.$replyToAddress['mail']);
9332
            $mailer->Sender = $replyToAddress['mail'];
9333
        }
9334
    }
9335
9336
    //If the SMTP configuration only accept one sender
9337
    if (
9338
        isset($platformEmail['SMTP_UNIQUE_SENDER']) &&
9339
        $platformEmail['SMTP_UNIQUE_SENDER']
9340
    ) {
9341
        $senderName = $platformEmail['SMTP_FROM_NAME'];
9342
        $senderEmail = $platformEmail['SMTP_FROM_EMAIL'];
9343
9344
        if (PHPMailer::ValidateAddress($senderEmail)) {
9345
            //force-set Sender to $senderEmail, otherwise SetFrom only does it if it is currently empty
9346
            $mailer->Sender = $senderEmail;
9347
        }
9348
    }
9349
9350
    $mailer->SetFrom($senderEmail, $senderName, !$avoidReplyToAddress);
9351
}
9352
9353
/**
9354
 * @param string $template
9355
 *
9356
 * @return string
9357
 */
9358
function api_find_template($template)
9359
{
9360
    return Template::findTemplateFilePath($template);
9361
}
9362
9363
/**
9364
 * @return array
9365
 */
9366
function api_get_language_list_for_flag()
9367
{
9368
    $table = Database::get_main_table(TABLE_MAIN_LANGUAGE);
9369
    $sql = "SELECT english_name, isocode FROM $table 
9370
            ORDER BY original_name ASC";
9371
    static $languages = [];
9372
    if (empty($languages)) {
9373
        $result = Database::query($sql);
9374
        while ($row = Database::fetch_array($result)) {
9375
            $languages[$row['english_name']] = $row['isocode'];
9376
        }
9377
        $languages['english'] = 'gb';
9378
    }
9379
9380
    return $languages;
9381
}
9382
9383
/**
9384
 * @return string
9385
 */
9386
function api_get_language_translate_html()
9387
{
9388
    $translate = api_get_configuration_value('translate_html');
9389
9390
    if (!$translate) {
9391
        return '';
9392
    }
9393
9394
    $languageList = api_get_languages();
9395
    $hideAll = '';
9396
    foreach ($languageList['all'] as $language) {
9397
        $hideAll .=
9398
            '$("span:lang('.$language['isocode'].')").filter(
9399
                function() {
9400
                    // Ignore ckeditor classes
9401
                    return !this.className.match(/cke(.*)/);
9402
            }).hide();';
9403
    }
9404
9405
    $userInfo = api_get_user_info();
9406
    $languageId = api_get_language_id($userInfo['language']);
9407
    $languageInfo = api_get_language_info($languageId);
9408
9409
    return '
9410
            $(function() {
9411
                '.$hideAll.'                 
9412
                var defaultLanguageFromUser = "'.$languageInfo['isocode'].'";   
9413
                                             
9414
                $("span:lang('.$languageInfo['isocode'].')").filter(
9415
                    function() {
9416
                        // Ignore ckeditor classes
9417
                        return !this.className.match(/cke(.*)/);
9418
                }).show();
9419
                
9420
                var defaultLanguage = "";
9421
                var langFromUserFound = false;
9422
                
9423
                $(this).find("span").filter(
9424
                    function() {
9425
                        // Ignore ckeditor classes
9426
                        return !this.className.match(/cke(.*)/);
9427
                }).each(function() {
9428
                    defaultLanguage = $(this).attr("lang");                            
9429
                    if (defaultLanguage) {
9430
                        $(this).before().next("br").remove();                
9431
                        if (defaultLanguageFromUser == defaultLanguage) {
9432
                            langFromUserFound = true;
9433
                        }
9434
                    }
9435
                });
9436
                
9437
                // Show default language
9438
                if (langFromUserFound == false && defaultLanguage) {
9439
                    $("span:lang("+defaultLanguage+")").filter(
9440
                    function() {
9441
                            // Ignore ckeditor classes
9442
                            return !this.className.match(/cke(.*)/);
9443
                    }).show();
9444
                }
9445
            });
9446
    ';
9447
}
9448