Completed
Push — master ( 9dadb1...edd250 )
by Julito
12:09 queued 19s
created

api_get_visual_theme()   C

Complexity

Conditions 12
Paths 65

Size

Total Lines 72
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 12
eloc 22
c 0
b 0
f 0
nc 65
nop 0
dl 0
loc 72
rs 6.9666

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
use Chamilo\CoreBundle\Entity\AccessUrl;
6
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...
7
use Chamilo\CoreBundle\Entity\Language;
8
use Chamilo\CoreBundle\Entity\Session as SessionEntity;
9
use Chamilo\CoreBundle\Entity\SettingsCurrent;
10
use Chamilo\CoreBundle\Entity\User;
11
use Chamilo\CoreBundle\Framework\Container;
12
use Chamilo\CourseBundle\Entity\CGroup;
13
use ChamiloSession as Session;
14
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
15
use Symfony\Component\Finder\Finder;
16
use Symfony\Component\Mime\Address;
17
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
18
use Symfony\Component\Security\Core\User\UserInterface;
19
20
/**
21
 * This is a code library for Chamilo.
22
 * It is included by default in every Chamilo file (through including the global.inc.php)
23
 * This library is in process of being transferred to src/Chamilo/CoreBundle/Component/Utils/ChamiloApi.
24
 * Whenever a function is transferred to the ChamiloApi class, the places where it is used should include
25
 * the "use Chamilo\CoreBundle\Component\Utils\ChamiloApi;" statement.
26
 */
27
28
// PHP version requirement.
29
define('REQUIRED_PHP_VERSION', '7.2');
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
// COURSE VISIBILITY CONSTANTS
60
/** only visible for course admin */
61
define('COURSE_VISIBILITY_CLOSED', 0);
62
/** only visible for users registered in the course */
63
define('COURSE_VISIBILITY_REGISTERED', 1);
64
/** Open for all registered users on the platform */
65
define('COURSE_VISIBILITY_OPEN_PLATFORM', 2);
66
/** Open for the whole world */
67
define('COURSE_VISIBILITY_OPEN_WORLD', 3);
68
/** Invisible to all except admin */
69
define('COURSE_VISIBILITY_HIDDEN', 4);
70
71
define('COURSE_REQUEST_PENDING', 0);
72
define('COURSE_REQUEST_ACCEPTED', 1);
73
define('COURSE_REQUEST_REJECTED', 2);
74
define('DELETE_ACTION_ENABLED', false);
75
76
// EMAIL SENDING RECIPIENT CONSTANTS
77
define('SEND_EMAIL_EVERYONE', 1);
78
define('SEND_EMAIL_STUDENTS', 2);
79
define('SEND_EMAIL_TEACHERS', 3);
80
81
// SESSION VISIBILITY CONSTANTS
82
define('SESSION_VISIBLE_READ_ONLY', 1);
83
define('SESSION_VISIBLE', 2);
84
define('SESSION_INVISIBLE', 3); // not available
85
define('SESSION_AVAILABLE', 4);
86
87
define('SESSION_LINK_TARGET', '_self');
88
89
define('SUBSCRIBE_ALLOWED', 1);
90
define('SUBSCRIBE_NOT_ALLOWED', 0);
91
define('UNSUBSCRIBE_ALLOWED', 1);
92
define('UNSUBSCRIBE_NOT_ALLOWED', 0);
93
94
// SURVEY VISIBILITY CONSTANTS
95
define('SURVEY_VISIBLE_TUTOR', 0);
96
define('SURVEY_VISIBLE_TUTOR_STUDENT', 1);
97
define('SURVEY_VISIBLE_PUBLIC', 2);
98
99
// CONSTANTS defining all tools, using the english version
100
/* When you add a new tool you must add it into function api_get_tools_lists() too */
101
define('TOOL_DOCUMENT', 'document');
102
define('TOOL_LP_FINAL_ITEM', 'final_item');
103
define('TOOL_READOUT_TEXT', 'readout_text');
104
define('TOOL_THUMBNAIL', 'thumbnail');
105
define('TOOL_HOTPOTATOES', 'hotpotatoes');
106
define('TOOL_CALENDAR_EVENT', 'calendar_event');
107
define('TOOL_LINK', 'link');
108
define('TOOL_LINK_CATEGORY', 'link_category');
109
define('TOOL_COURSE_DESCRIPTION', 'course_description');
110
define('TOOL_SEARCH', 'search');
111
define('TOOL_LEARNPATH', 'learnpath');
112
define('TOOL_LEARNPATH_CATEGORY', 'learnpath_category');
113
define('TOOL_AGENDA', 'agenda');
114
define('TOOL_ANNOUNCEMENT', 'announcement');
115
define('TOOL_FORUM', 'forum');
116
define('TOOL_FORUM_CATEGORY', 'forum_category');
117
define('TOOL_FORUM_THREAD', 'forum_thread');
118
define('TOOL_FORUM_POST', 'forum_post');
119
define('TOOL_FORUM_ATTACH', 'forum_attachment');
120
define('TOOL_FORUM_THREAD_QUALIFY', 'forum_thread_qualify');
121
define('TOOL_THREAD', 'thread');
122
define('TOOL_POST', 'post');
123
define('TOOL_DROPBOX', 'dropbox');
124
define('TOOL_QUIZ', 'quiz');
125
define('TOOL_TEST_CATEGORY', 'test_category');
126
define('TOOL_USER', 'user');
127
define('TOOL_GROUP', 'group');
128
define('TOOL_BLOGS', 'blog_management');
129
define('TOOL_CHAT', 'chat');
130
define('TOOL_STUDENTPUBLICATION', 'student_publication');
131
define('TOOL_TRACKING', 'tracking');
132
define('TOOL_HOMEPAGE_LINK', 'homepage_link');
133
define('TOOL_COURSE_SETTING', 'course_setting');
134
define('TOOL_BACKUP', 'backup');
135
define('TOOL_COPY_COURSE_CONTENT', 'copy_course_content');
136
define('TOOL_RECYCLE_COURSE', 'recycle_course');
137
define('TOOL_COURSE_HOMEPAGE', 'course_homepage');
138
define('TOOL_COURSE_RIGHTS_OVERVIEW', 'course_rights');
139
define('TOOL_UPLOAD', 'file_upload');
140
define('TOOL_COURSE_MAINTENANCE', 'course_maintenance');
141
define('TOOL_SURVEY', 'survey');
142
define('TOOL_WIKI', 'wiki');
143
define('TOOL_GLOSSARY', 'glossary');
144
define('TOOL_GRADEBOOK', 'gradebook');
145
define('TOOL_NOTEBOOK', 'notebook');
146
define('TOOL_ATTENDANCE', 'attendance');
147
define('TOOL_COURSE_PROGRESS', 'course_progress');
148
define('TOOL_PORTFOLIO', 'portfolio');
149
define('TOOL_PLAGIARISM', 'compilatio');
150
151
// CONSTANTS defining Chamilo interface sections
152
define('SECTION_CAMPUS', 'mycampus');
153
define('SECTION_COURSES', 'mycourses');
154
define('SECTION_CATALOG', 'catalog');
155
define('SECTION_MYPROFILE', 'myprofile');
156
define('SECTION_MYAGENDA', 'myagenda');
157
define('SECTION_COURSE_ADMIN', 'course_admin');
158
define('SECTION_PLATFORM_ADMIN', 'platform_admin');
159
define('SECTION_MYGRADEBOOK', 'mygradebook');
160
define('SECTION_TRACKING', 'session_my_space');
161
define('SECTION_SOCIAL', 'social-network');
162
define('SECTION_DASHBOARD', 'dashboard');
163
define('SECTION_REPORTS', 'reports');
164
define('SECTION_GLOBAL', 'global');
165
define('SECTION_INCLUDE', 'include');
166
167
// CONSTANT name for local authentication source
168
define('PLATFORM_AUTH_SOURCE', 'platform');
169
define('CAS_AUTH_SOURCE', 'cas');
170
define('LDAP_AUTH_SOURCE', 'extldap');
171
172
// CONSTANT defining the default HotPotatoes files directory
173
define('DIR_HOTPOTATOES', '/HotPotatoes_files');
174
175
// event logs types
176
define('LOG_COURSE_DELETE', 'course_deleted');
177
define('LOG_COURSE_CREATE', 'course_created');
178
define('LOG_COURSE_SETTINGS_CHANGED', 'course_settings_changed');
179
180
// @todo replace 'soc_gr' with social_group
181
define('LOG_GROUP_PORTAL_CREATED', 'soc_gr_created');
182
define('LOG_GROUP_PORTAL_UPDATED', 'soc_gr_updated');
183
define('LOG_GROUP_PORTAL_DELETED', 'soc_gr_deleted');
184
define('LOG_GROUP_PORTAL_USER_DELETE_ALL', 'soc_gr_delete_users');
185
186
define('LOG_GROUP_PORTAL_ID', 'soc_gr_portal_id');
187
define('LOG_GROUP_PORTAL_REL_USER_ARRAY', 'soc_gr_user_array');
188
189
define('LOG_GROUP_PORTAL_USER_SUBSCRIBED', 'soc_gr_u_subs');
190
define('LOG_GROUP_PORTAL_USER_UNSUBSCRIBED', 'soc_gr_u_unsubs');
191
define('LOG_GROUP_PORTAL_USER_UPDATE_ROLE', 'soc_gr_update_role');
192
193
define('LOG_USER_DELETE', 'user_deleted');
194
define('LOG_USER_CREATE', 'user_created');
195
define('LOG_USER_UPDATE', 'user_updated');
196
define('LOG_USER_PASSWORD_UPDATE', 'user_password_updated');
197
define('LOG_USER_ENABLE', 'user_enable');
198
define('LOG_USER_DISABLE', 'user_disable');
199
define('LOG_USER_ANONYMIZE', 'user_anonymized');
200
define('LOG_USER_FIELD_CREATE', 'user_field_created');
201
define('LOG_USER_FIELD_DELETE', 'user_field_deleted');
202
define('LOG_SESSION_CREATE', 'session_created');
203
define('LOG_SESSION_DELETE', 'session_deleted');
204
define('LOG_SESSION_ADD_USER_COURSE', 'session_add_user_course');
205
define('LOG_SESSION_DELETE_USER_COURSE', 'session_delete_user_course');
206
define('LOG_SESSION_ADD_USER', 'session_add_user');
207
define('LOG_SESSION_DELETE_USER', 'session_delete_user');
208
define('LOG_SESSION_ADD_COURSE', 'session_add_course');
209
define('LOG_SESSION_DELETE_COURSE', 'session_delete_course');
210
define('LOG_SESSION_CATEGORY_CREATE', 'session_cat_created'); //changed in 1.9.8
211
define('LOG_SESSION_CATEGORY_DELETE', 'session_cat_deleted'); //changed in 1.9.8
212
define('LOG_CONFIGURATION_SETTINGS_CHANGE', 'settings_changed');
213
define('LOG_PLATFORM_LANGUAGE_CHANGE', 'platform_lng_changed'); //changed in 1.9.8
214
define('LOG_SUBSCRIBE_USER_TO_COURSE', 'user_subscribed');
215
define('LOG_UNSUBSCRIBE_USER_FROM_COURSE', 'user_unsubscribed');
216
define('LOG_ATTEMPTED_FORCED_LOGIN', 'attempted_forced_login');
217
define('LOG_PLUGIN_CHANGE', 'plugin_changed');
218
define('LOG_HOMEPAGE_CHANGED', 'homepage_changed');
219
define('LOG_PROMOTION_CREATE', 'promotion_created');
220
define('LOG_PROMOTION_DELETE', 'promotion_deleted');
221
define('LOG_CAREER_CREATE', 'career_created');
222
define('LOG_CAREER_DELETE', 'career_deleted');
223
define('LOG_USER_PERSONAL_DOC_DELETED', 'user_doc_deleted');
224
define('LOG_WIKI_ACCESS', 'wiki_page_view');
225
// All results from an exercise
226
define('LOG_EXERCISE_RESULT_DELETE', 'exe_result_deleted');
227
// Logs only the one attempt
228
define('LOG_EXERCISE_ATTEMPT_DELETE', 'exe_attempt_deleted');
229
define('LOG_LP_ATTEMPT_DELETE', 'lp_attempt_deleted');
230
define('LOG_QUESTION_RESULT_DELETE', 'qst_attempt_deleted');
231
232
define('LOG_MY_FOLDER_CREATE', 'my_folder_created');
233
define('LOG_MY_FOLDER_CHANGE', 'my_folder_changed');
234
define('LOG_MY_FOLDER_DELETE', 'my_folder_deleted');
235
define('LOG_MY_FOLDER_COPY', 'my_folder_copied');
236
define('LOG_MY_FOLDER_CUT', 'my_folder_cut');
237
define('LOG_MY_FOLDER_PASTE', 'my_folder_pasted');
238
define('LOG_MY_FOLDER_UPLOAD', 'my_folder_uploaded');
239
240
// Event logs data types (max 20 chars)
241
define('LOG_COURSE_CODE', 'course_code');
242
define('LOG_COURSE_ID', 'course_id');
243
define('LOG_USER_ID', 'user_id');
244
define('LOG_USER_OBJECT', 'user_object');
245
define('LOG_USER_FIELD_VARIABLE', 'user_field_variable');
246
define('LOG_SESSION_ID', 'session_id');
247
248
define('LOG_QUESTION_ID', 'question_id');
249
define('LOG_SESSION_CATEGORY_ID', 'session_category_id');
250
define('LOG_CONFIGURATION_SETTINGS_CATEGORY', 'settings_category');
251
define('LOG_CONFIGURATION_SETTINGS_VARIABLE', 'settings_variable');
252
define('LOG_PLATFORM_LANGUAGE', 'default_platform_language');
253
define('LOG_PLUGIN_UPLOAD', 'plugin_upload');
254
define('LOG_PLUGIN_ENABLE', 'plugin_enable');
255
define('LOG_PLUGIN_SETTINGS_CHANGE', 'plugin_settings_change');
256
define('LOG_CAREER_ID', 'career_id');
257
define('LOG_PROMOTION_ID', 'promotion_id');
258
define('LOG_GRADEBOOK_LOCKED', 'gradebook_locked');
259
define('LOG_GRADEBOOK_UNLOCKED', 'gradebook_unlocked');
260
define('LOG_GRADEBOOK_ID', 'gradebook_id');
261
define('LOG_WIKI_PAGE_ID', 'wiki_page_id');
262
define('LOG_EXERCISE_ID', 'exercise_id');
263
define('LOG_EXERCISE_AND_USER_ID', 'exercise_and_user_id');
264
define('LOG_LP_ID', 'lp_id');
265
define('LOG_EXERCISE_ATTEMPT_QUESTION_ID', 'exercise_a_q_id');
266
define('LOG_EXERCISE_ATTEMPT', 'exe_id');
267
268
define('LOG_WORK_DIR_DELETE', 'work_dir_delete');
269
define('LOG_WORK_FILE_DELETE', 'work_file_delete');
270
define('LOG_WORK_DATA', 'work_data_array');
271
272
define('LOG_MY_FOLDER_PATH', 'path');
273
define('LOG_MY_FOLDER_NEW_PATH', 'new_path');
274
275
define('LOG_TERM_CONDITION_ACCEPTED', 'term_condition_accepted');
276
define('LOG_USER_CONFIRMED_EMAIL', 'user_confirmed_email');
277
define('LOG_USER_REMOVED_LEGAL_ACCEPT', 'user_removed_legal_accept');
278
279
define('LOG_USER_DELETE_ACCOUNT_REQUEST', 'user_delete_account_request');
280
281
define('LOG_QUESTION_CREATED', 'question_created');
282
define('LOG_QUESTION_UPDATED', 'question_updated');
283
define('LOG_QUESTION_DELETED', 'question_deleted');
284
define('LOG_QUESTION_REMOVED_FROM_QUIZ', 'question_removed_from_quiz');
285
286
define('USERNAME_PURIFIER', '/[^0-9A-Za-z_\.-]/');
287
288
//used when login_is_email setting is true
289
define('USERNAME_PURIFIER_MAIL', '/[^0-9A-Za-z_\.@]/');
290
define('USERNAME_PURIFIER_SHALLOW', '/\s/');
291
292
// This constant is a result of Windows OS detection, it has a boolean value:
293
// true whether the server runs on Windows OS, false otherwise.
294
define('IS_WINDOWS_OS', api_is_windows_os());
295
296
// iconv extension, for PHP5 on Windows it is installed by default.
297
define('ICONV_INSTALLED', function_exists('iconv'));
298
define('MBSTRING_INSTALLED', function_exists('mb_strlen')); // mbstring extension.
299
300
// Patterns for processing paths. Examples.
301
define('REPEATED_SLASHES_PURIFIER', '/\/{2,}/'); // $path = preg_replace(REPEATED_SLASHES_PURIFIER, '/', $path);
302
define('VALID_WEB_PATH', '/https?:\/\/[^\/]*(\/.*)?/i'); // $is_valid_path = preg_match(VALID_WEB_PATH, $path);
303
// $new_path = preg_replace(VALID_WEB_SERVER_BASE, $new_base, $path);
304
define('VALID_WEB_SERVER_BASE', '/https?:\/\/[^\/]*/i');
305
// Constants for api_get_path() and api_get_path_type(), etc. - registered path types.
306
// basic (leaf elements)
307
define('REL_CODE_PATH', 'REL_CODE_PATH');
308
define('REL_COURSE_PATH', 'REL_COURSE_PATH');
309
define('REL_HOME_PATH', 'REL_HOME_PATH');
310
311
// Constants for api_get_path() and api_get_path_type(), etc. - registered path types.
312
define('WEB_PATH', 'WEB_PATH');
313
define('SYS_PATH', 'SYS_PATH');
314
define('SYMFONY_SYS_PATH', 'SYMFONY_SYS_PATH');
315
define('SYS_UPLOAD_PATH', 'SYS_UPLOAD_PATH');
316
define('WEB_UPLOAD_PATH', 'WEB_UPLOAD_PATH');
317
318
define('REL_PATH', 'REL_PATH');
319
define('WEB_COURSE_PATH', 'WEB_COURSE_PATH');
320
define('WEB_CODE_PATH', 'WEB_CODE_PATH');
321
define('SYS_CODE_PATH', 'SYS_CODE_PATH');
322
define('SYS_LANG_PATH', 'SYS_LANG_PATH');
323
define('WEB_IMG_PATH', 'WEB_IMG_PATH');
324
define('WEB_CSS_PATH', 'WEB_CSS_PATH');
325
define('WEB_PUBLIC_PATH', 'WEB_PUBLIC_PATH');
326
define('SYS_CSS_PATH', 'SYS_CSS_PATH');
327
define('SYS_PLUGIN_PATH', 'SYS_PLUGIN_PATH');
328
define('WEB_PLUGIN_PATH', 'WEB_PLUGIN_PATH');
329
define('WEB_PLUGIN_ASSET_PATH', 'WEB_PLUGIN_ASSET_PATH');
330
define('SYS_ARCHIVE_PATH', 'SYS_ARCHIVE_PATH');
331
define('WEB_ARCHIVE_PATH', 'WEB_ARCHIVE_PATH');
332
define('LIBRARY_PATH', 'LIBRARY_PATH');
333
define('CONFIGURATION_PATH', 'CONFIGURATION_PATH');
334
define('WEB_LIBRARY_PATH', 'WEB_LIBRARY_PATH');
335
define('WEB_LIBRARY_JS_PATH', 'WEB_LIBRARY_JS_PATH');
336
define('WEB_AJAX_PATH', 'WEB_AJAX_PATH');
337
define('SYS_TEST_PATH', 'SYS_TEST_PATH');
338
define('SYS_TEMPLATE_PATH', 'SYS_TEMPLATE_PATH');
339
define('SYS_PUBLIC_PATH', 'SYS_PUBLIC_PATH');
340
define('SYS_FONTS_PATH', 'SYS_FONTS_PATH');
341
342
// Relations type with Course manager
343
define('COURSE_RELATION_TYPE_COURSE_MANAGER', 1);
344
define('SESSION_RELATION_TYPE_COURSE_MANAGER', 1);
345
346
// Relations type with Human resources manager
347
define('COURSE_RELATION_TYPE_RRHH', 1);
348
define('SESSION_RELATION_TYPE_RRHH', 1);
349
350
//User image sizes
351
define('USER_IMAGE_SIZE_ORIGINAL', 1);
352
define('USER_IMAGE_SIZE_BIG', 2);
353
define('USER_IMAGE_SIZE_MEDIUM', 3);
354
define('USER_IMAGE_SIZE_SMALL', 4);
355
356
// Relation type between users
357
define('USER_UNKNOWN', 0);
358
define('USER_RELATION_TYPE_UNKNOWN', 1);
359
define('USER_RELATION_TYPE_PARENT', 2); // should be deprecated is useless
360
define('USER_RELATION_TYPE_FRIEND', 3);
361
define('USER_RELATION_TYPE_GOODFRIEND', 4); // should be deprecated is useless
362
define('USER_RELATION_TYPE_ENEMY', 5); // should be deprecated is useless
363
define('USER_RELATION_TYPE_DELETED', 6);
364
define('USER_RELATION_TYPE_RRHH', 7);
365
define('USER_RELATION_TYPE_BOSS', 8);
366
define('USER_RELATION_TYPE_HRM_REQUEST', 9);
367
368
// Gradebook link constants
369
// Please do not change existing values, they are used in the database !
370
define('GRADEBOOK_ITEM_LIMIT', 1000);
371
372
define('LINK_EXERCISE', 1);
373
define('LINK_DROPBOX', 2);
374
define('LINK_STUDENTPUBLICATION', 3);
375
define('LINK_LEARNPATH', 4);
376
define('LINK_FORUM_THREAD', 5);
377
//define('LINK_WORK',6);
378
define('LINK_ATTENDANCE', 7);
379
define('LINK_SURVEY', 8);
380
define('LINK_HOTPOTATOES', 9);
381
382
// Score display types constants
383
define('SCORE_DIV', 1); // X / Y
384
define('SCORE_PERCENT', 2); // XX %
385
define('SCORE_DIV_PERCENT', 3); // X / Y (XX %)
386
define('SCORE_AVERAGE', 4); // XX %
387
define('SCORE_DECIMAL', 5); // 0.50  (X/Y)
388
define('SCORE_BAR', 6); // Uses the Display::bar_progress function
389
define('SCORE_SIMPLE', 7); // X
390
define('SCORE_IGNORE_SPLIT', 8); //  ??
391
define('SCORE_DIV_PERCENT_WITH_CUSTOM', 9); // X / Y (XX %) - Good!
392
define('SCORE_CUSTOM', 10); // Good!
393
define('SCORE_DIV_SIMPLE_WITH_CUSTOM', 11); // X - Good!
394
define('SCORE_DIV_SIMPLE_WITH_CUSTOM_LETTERS', 12); // X - Good!
395
define('SCORE_ONLY_SCORE', 13); // X - Good!
396
define('SCORE_NUMERIC', 14);
397
398
define('SCORE_BOTH', 1);
399
define('SCORE_ONLY_DEFAULT', 2);
400
define('SCORE_ONLY_CUSTOM', 3);
401
402
// From display.lib.php
403
404
define('MAX_LENGTH_BREADCRUMB', 100);
405
define('ICON_SIZE_ATOM', 8);
406
define('ICON_SIZE_TINY', 16);
407
define('ICON_SIZE_SMALL', 22);
408
define('ICON_SIZE_MEDIUM', 32);
409
define('ICON_SIZE_LARGE', 48);
410
define('ICON_SIZE_BIG', 64);
411
define('ICON_SIZE_HUGE', 128);
412
define('SHOW_TEXT_NEAR_ICONS', false);
413
414
// Session catalog
415
define('CATALOG_COURSES', 0);
416
define('CATALOG_SESSIONS', 1);
417
define('CATALOG_COURSES_SESSIONS', 2);
418
419
// Hook type events, pre-process and post-process.
420
// All means to be executed for both hook event types
421
define('HOOK_EVENT_TYPE_PRE', 0);
422
define('HOOK_EVENT_TYPE_POST', 1);
423
define('HOOK_EVENT_TYPE_ALL', 10);
424
425
define('CAREER_STATUS_ACTIVE', 1);
426
define('CAREER_STATUS_INACTIVE', 0);
427
428
define('PROMOTION_STATUS_ACTIVE', 1);
429
define('PROMOTION_STATUS_INACTIVE', 0);
430
431
// Group permissions
432
define('GROUP_PERMISSION_OPEN', '1');
433
define('GROUP_PERMISSION_CLOSED', '2');
434
435
// Group user permissions
436
define('GROUP_USER_PERMISSION_ADMIN', 1); // the admin of a group
437
define('GROUP_USER_PERMISSION_READER', 2); // a normal user
438
define('GROUP_USER_PERMISSION_PENDING_INVITATION', 3); // When an admin/moderator invites a user
439
define('GROUP_USER_PERMISSION_PENDING_INVITATION_SENT_BY_USER', 4); // an user joins a group
440
define('GROUP_USER_PERMISSION_MODERATOR', 5); // a moderator
441
define('GROUP_USER_PERMISSION_ANONYMOUS', 6); // an anonymous user
442
define('GROUP_USER_PERMISSION_HRM', 7); // a human resources manager
443
444
define('GROUP_IMAGE_SIZE_ORIGINAL', 1);
445
define('GROUP_IMAGE_SIZE_BIG', 2);
446
define('GROUP_IMAGE_SIZE_MEDIUM', 3);
447
define('GROUP_IMAGE_SIZE_SMALL', 4);
448
define('GROUP_TITLE_LENGTH', 50);
449
450
// Exercise
451
// @todo move into a class
452
define('ALL_ON_ONE_PAGE', 1);
453
define('ONE_PER_PAGE', 2);
454
455
define('EXERCISE_FEEDBACK_TYPE_END', 0); //Feedback 		 - show score and expected answers
456
define('EXERCISE_FEEDBACK_TYPE_DIRECT', 1); //DirectFeedback - Do not show score nor answers
457
define('EXERCISE_FEEDBACK_TYPE_EXAM', 2); // NoFeedback 	 - Show score only
458
define('EXERCISE_FEEDBACK_TYPE_POPUP', 3); // Popup BT#15827
459
460
define('RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS', 0); //show score and expected answers
461
define('RESULT_DISABLE_NO_SCORE_AND_EXPECTED_ANSWERS', 1); //Do not show score nor answers
462
define('RESULT_DISABLE_SHOW_SCORE_ONLY', 2); //Show score only
463
define('RESULT_DISABLE_SHOW_FINAL_SCORE_ONLY_WITH_CATEGORIES', 3); //Show final score only with categories
464
define('RESULT_DISABLE_SHOW_SCORE_ATTEMPT_SHOW_ANSWERS_LAST_ATTEMPT', 4);
465
define('RESULT_DISABLE_DONT_SHOW_SCORE_ONLY_IF_USER_FINISHES_ATTEMPTS_SHOW_ALWAYS_FEEDBACK', 5);
466
define('RESULT_DISABLE_RANKING', 6);
467
define('RESULT_DISABLE_SHOW_ONLY_IN_CORRECT_ANSWER', 7);
468
define('RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS_AND_RANKING', 8);
469
470
define('EXERCISE_MAX_NAME_SIZE', 80);
471
472
// Question types (edit next array as well when adding values)
473
// @todo move into a class
474
define('UNIQUE_ANSWER', 1);
475
define('MULTIPLE_ANSWER', 2);
476
define('FILL_IN_BLANKS', 3);
477
define('MATCHING', 4);
478
define('FREE_ANSWER', 5);
479
define('HOT_SPOT', 6);
480
define('HOT_SPOT_ORDER', 7);
481
define('HOT_SPOT_DELINEATION', 8);
482
define('MULTIPLE_ANSWER_COMBINATION', 9);
483
define('UNIQUE_ANSWER_NO_OPTION', 10);
484
define('MULTIPLE_ANSWER_TRUE_FALSE', 11);
485
define('MULTIPLE_ANSWER_COMBINATION_TRUE_FALSE', 12);
486
define('ORAL_EXPRESSION', 13);
487
define('GLOBAL_MULTIPLE_ANSWER', 14);
488
define('MEDIA_QUESTION', 15);
489
define('CALCULATED_ANSWER', 16);
490
define('UNIQUE_ANSWER_IMAGE', 17);
491
define('DRAGGABLE', 18);
492
define('MATCHING_DRAGGABLE', 19);
493
define('ANNOTATION', 20);
494
define('READING_COMPREHENSION', 21);
495
define('MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY', 22);
496
497
define('EXERCISE_CATEGORY_RANDOM_SHUFFLED', 1);
498
define('EXERCISE_CATEGORY_RANDOM_ORDERED', 2);
499
define('EXERCISE_CATEGORY_RANDOM_DISABLED', 0);
500
501
// Question selection type
502
define('EX_Q_SELECTION_ORDERED', 1);
503
define('EX_Q_SELECTION_RANDOM', 2);
504
define('EX_Q_SELECTION_CATEGORIES_ORDERED_QUESTIONS_ORDERED', 3);
505
define('EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_ORDERED', 4);
506
define('EX_Q_SELECTION_CATEGORIES_ORDERED_QUESTIONS_RANDOM', 5);
507
define('EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_RANDOM', 6);
508
define('EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_ORDERED_NO_GROUPED', 7);
509
define('EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_RANDOM_NO_GROUPED', 8);
510
define('EX_Q_SELECTION_CATEGORIES_ORDERED_BY_PARENT_QUESTIONS_ORDERED', 9);
511
define('EX_Q_SELECTION_CATEGORIES_ORDERED_BY_PARENT_QUESTIONS_RANDOM', 10);
512
513
// Used to save the skill_rel_item table
514
define('ITEM_TYPE_EXERCISE', 1);
515
define('ITEM_TYPE_HOTPOTATOES', 2);
516
define('ITEM_TYPE_LINK', 3);
517
define('ITEM_TYPE_LEARNPATH', 4);
518
define('ITEM_TYPE_GRADEBOOK', 5);
519
define('ITEM_TYPE_STUDENT_PUBLICATION', 6);
520
//define('ITEM_TYPE_FORUM', 7);
521
define('ITEM_TYPE_ATTENDANCE', 8);
522
define('ITEM_TYPE_SURVEY', 9);
523
define('ITEM_TYPE_FORUM_THREAD', 10);
524
525
// one big string with all question types, for the validator in pear/HTML/QuickForm/Rule/QuestionType
526
define(
527
    'QUESTION_TYPES',
528
    UNIQUE_ANSWER.':'.
529
    MULTIPLE_ANSWER.':'.
530
    FILL_IN_BLANKS.':'.
531
    MATCHING.':'.
532
    FREE_ANSWER.':'.
533
    HOT_SPOT.':'.
534
    HOT_SPOT_ORDER.':'.
535
    HOT_SPOT_DELINEATION.':'.
536
    MULTIPLE_ANSWER_COMBINATION.':'.
537
    UNIQUE_ANSWER_NO_OPTION.':'.
538
    MULTIPLE_ANSWER_TRUE_FALSE.':'.
539
    MULTIPLE_ANSWER_COMBINATION_TRUE_FALSE.':'.
540
    ORAL_EXPRESSION.':'.
541
    GLOBAL_MULTIPLE_ANSWER.':'.
542
    MEDIA_QUESTION.':'.
543
    CALCULATED_ANSWER.':'.
544
    UNIQUE_ANSWER_IMAGE.':'.
545
    DRAGGABLE.':'.
546
    MATCHING_DRAGGABLE.':'.
547
    MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY.':'.
548
    ANNOTATION
549
);
550
551
//Some alias used in the QTI exports
552
define('MCUA', 1);
553
define('TF', 1);
554
define('MCMA', 2);
555
define('FIB', 3);
556
557
// Skills
558
define('SKILL_TYPE_REQUIREMENT', 'required');
559
define('SKILL_TYPE_ACQUIRED', 'acquired');
560
define('SKILL_TYPE_BOTH', 'both');
561
562
// Message
563
define('MESSAGE_STATUS_NEW', '0');
564
define('MESSAGE_STATUS_UNREAD', '1');
565
//2 ??
566
define('MESSAGE_STATUS_DELETED', '3');
567
define('MESSAGE_STATUS_OUTBOX', '4');
568
define('MESSAGE_STATUS_INVITATION_PENDING', '5');
569
define('MESSAGE_STATUS_INVITATION_ACCEPTED', '6');
570
define('MESSAGE_STATUS_INVITATION_DENIED', '7');
571
define('MESSAGE_STATUS_WALL', '8');
572
define('MESSAGE_STATUS_WALL_DELETE', '9');
573
define('MESSAGE_STATUS_WALL_POST', '10');
574
define('MESSAGE_STATUS_CONVERSATION', '11');
575
define('MESSAGE_STATUS_FORUM', '12');
576
define('MESSAGE_STATUS_PROMOTED', '13');
577
578
// Images
579
define('IMAGE_WALL_SMALL_SIZE', 200);
580
define('IMAGE_WALL_MEDIUM_SIZE', 500);
581
define('IMAGE_WALL_BIG_SIZE', 2000);
582
define('IMAGE_WALL_SMALL', 'small');
583
define('IMAGE_WALL_MEDIUM', 'medium');
584
define('IMAGE_WALL_BIG', 'big');
585
586
// Social PLUGIN PLACES
587
define('SOCIAL_LEFT_PLUGIN', 1);
588
define('SOCIAL_CENTER_PLUGIN', 2);
589
define('SOCIAL_RIGHT_PLUGIN', 3);
590
define('CUT_GROUP_NAME', 50);
591
592
/**
593
 * FormValidator Filter.
594
 */
595
define('NO_HTML', 1);
596
define('STUDENT_HTML', 2);
597
define('TEACHER_HTML', 3);
598
define('STUDENT_HTML_FULLPAGE', 4);
599
define('TEACHER_HTML_FULLPAGE', 5);
600
601
// Timeline
602
define('TIMELINE_STATUS_ACTIVE', '1');
603
define('TIMELINE_STATUS_INACTIVE', '2');
604
605
// Event email template class
606
define('EVENT_EMAIL_TEMPLATE_ACTIVE', 1);
607
define('EVENT_EMAIL_TEMPLATE_INACTIVE', 0);
608
609
// Course home
610
define('SHORTCUTS_HORIZONTAL', 0);
611
define('SHORTCUTS_VERTICAL', 1);
612
613
// Image class
614
define('IMAGE_PROCESSOR', 'gd'); // 'imagick' or 'gd' strings
615
616
// Course copy
617
define('FILE_SKIP', 1);
618
define('FILE_RENAME', 2);
619
define('FILE_OVERWRITE', 3);
620
define('UTF8_CONVERT', false); //false by default
621
622
define('DOCUMENT', 'file');
623
define('FOLDER', 'folder');
624
625
define('RESOURCE_ASSET', 'asset');
626
define('RESOURCE_DOCUMENT', 'document');
627
define('RESOURCE_GLOSSARY', 'glossary');
628
define('RESOURCE_EVENT', 'calendar_event');
629
define('RESOURCE_LINK', 'link');
630
define('RESOURCE_COURSEDESCRIPTION', 'course_description');
631
define('RESOURCE_LEARNPATH', 'learnpath');
632
define('RESOURCE_LEARNPATH_CATEGORY', 'learnpath_category');
633
define('RESOURCE_ANNOUNCEMENT', 'announcement');
634
define('RESOURCE_FORUM', 'forum');
635
define('RESOURCE_FORUMTOPIC', 'thread');
636
define('RESOURCE_FORUMPOST', 'post');
637
define('RESOURCE_QUIZ', 'quiz');
638
define('RESOURCE_TEST_CATEGORY', 'test_category');
639
define('RESOURCE_QUIZQUESTION', 'Exercise_Question');
640
define('RESOURCE_TOOL_INTRO', 'Tool introduction');
641
define('RESOURCE_LINKCATEGORY', 'Link_Category');
642
define('RESOURCE_FORUMCATEGORY', 'Forum_Category');
643
define('RESOURCE_SCORM', 'Scorm');
644
define('RESOURCE_SURVEY', 'survey');
645
define('RESOURCE_SURVEYQUESTION', 'survey_question');
646
define('RESOURCE_SURVEYINVITATION', 'survey_invitation');
647
define('RESOURCE_WIKI', 'wiki');
648
define('RESOURCE_THEMATIC', 'thematic');
649
define('RESOURCE_ATTENDANCE', 'attendance');
650
define('RESOURCE_WORK', 'work');
651
define('RESOURCE_SESSION_COURSE', 'session_course');
652
define('RESOURCE_GRADEBOOK', 'gradebook');
653
define('ADD_THEMATIC_PLAN', 6);
654
655
// Max online users to show per page (whoisonline)
656
define('MAX_ONLINE_USERS', 12);
657
658
// Number of characters maximum to show in preview of course blog posts
659
define('BLOG_MAX_PREVIEW_CHARS', 800);
660
// HTML string to replace with a 'Read more...' link
661
define('BLOG_PAGE_BREAK', '<div style="page-break-after: always"><span style="display: none;">&nbsp;</span></div>');
662
663
// Make sure the CHAMILO_LOAD_WYSIWYG constant is defined
664
// To remove CKeditor libs from HTML, set this constant to true before loading
665
if (!defined('CHAMILO_LOAD_WYSIWYG')) {
666
    define('CHAMILO_LOAD_WYSIWYG', true);
667
}
668
669
/* Constants for course home */
670
define('TOOL_PUBLIC', 'Public');
671
define('TOOL_PUBLIC_BUT_HIDDEN', 'PublicButHide');
672
define('TOOL_COURSE_ADMIN', 'courseAdmin');
673
define('TOOL_PLATFORM_ADMIN', 'platformAdmin');
674
define('TOOL_AUTHORING', 'toolauthoring');
675
define('TOOL_INTERACTION', 'toolinteraction');
676
define('TOOL_COURSE_PLUGIN', 'toolcourseplugin'); //all plugins that can be enabled in courses
677
define('TOOL_ADMIN', 'tooladmin');
678
define('TOOL_ADMIN_PLATFORM', 'tooladminplatform');
679
define('TOOL_DRH', 'tool_drh');
680
define('TOOL_STUDENT_VIEW', 'toolstudentview');
681
define('TOOL_ADMIN_VISIBLE', 'tooladminvisible');
682
683
// Search settings (from main/inc/lib/search/IndexableChunk.class.php )
684
// some constants to avoid serialize string keys on serialized data array
685
define('SE_COURSE_ID', 0);
686
define('SE_TOOL_ID', 1);
687
define('SE_DATA', 2);
688
define('SE_USER', 3);
689
690
// in some cases we need top differenciate xapian documents of the same tool
691
define('SE_DOCTYPE_EXERCISE_EXERCISE', 0);
692
define('SE_DOCTYPE_EXERCISE_QUESTION', 1);
693
694
// xapian prefixes
695
define('XAPIAN_PREFIX_COURSEID', 'C');
696
define('XAPIAN_PREFIX_TOOLID', 'O');
697
698
/**
699
 * Returns a path to a certain resource within the Chamilo area, specifyed through a parameter.
700
 * Also, this function provides conversion between path types, in this case the input path points inside the Chamilo area too.
701
 *
702
 * See $_configuration['course_folder'] in the configuration.php to alter the WEB_COURSE_PATH and SYS_COURSE_PATH parameters.
703
704
 *
705
 * @param string $path (optional)   A path which type is to be converted. Also, it may be a defined constant for a path.
706
 *                     This parameter has meaning when $type parameter has one of the following values: TO_WEB, TO_SYS, TO_REL. Otherwise it is ignored.
707
 *
708
 * @return string the requested path or the converted path
709
 *
710
 * Notes about the current behaviour model:
711
 * 1. Windows back-slashes are converted to slashes in the result.
712
 * 2. A semi-absolute web-path is detected by its leading slash. On Linux systems, absolute system paths start with
713
 * a slash too, so an additional check about presence of leading system server base is implemented. For example, the function is
714
 * able to distinguish type difference between /var/www/chamilo/courses/ (SYS) and /chamilo/courses/ (REL).
715
 * 3. The function api_get_path() returns only these three types of paths, which in some sense are absolute. The function has
716
 * no a mechanism for processing relative web/system paths, such as: lesson01.html, ./lesson01.html, ../css/my_styles.css.
717
 * It has not been identified as needed yet.
718
 * 4. Also, resolving the meta-symbols "." and ".." within paths has not been implemented, it is to be identified as needed.
719
 *
720
 * For examples go to: *
721
 * See main/admin/system_status.php?section=paths
722
 *
723
 * Vchamilo changes : allow using an alternate configuration
724
 * to get vchamilo  instance paths
725
 */
726
function api_get_path($path = '', $configuration = [])
727
{
728
    global $paths;
729
730
    // get proper configuration data if exists
731
    global $_configuration;
732
733
    $emptyConfigurationParam = false;
734
    if (empty($configuration)) {
735
        $configuration = (array) $_configuration;
736
        $emptyConfigurationParam = true;
737
    }
738
739
    $root_sys = Container::getProjectDir();
740
741
    $root_web = '';
742
    // If no $root_web has been set so far *and* no custom config has been passed to the function
743
    // then re-use the previously-calculated (run-specific) $root_web and skip this complex calculation
744
    /*
745
    if (empty($root_web) || $emptyConfigurationParam === false || empty($configuration)) {
746
        // Resolve master hostname.
747
        if (!empty($configuration) && array_key_exists('root_web', $configuration)) {
748
            $root_web = $configuration['root_web'];
749
        } else {
750
            $root_web = '';
751
            // Try guess it from server.
752
            if (defined('SYSTEM_INSTALLATION') && SYSTEM_INSTALLATION) {
753
                if (($pos = strpos(($requested_page_rel = api_get_self()), 'main/install')) !== false) {
754
                    $root_rel = substr($requested_page_rel, 0, $pos);
755
                    // See http://www.mediawiki.org/wiki/Manual:$wgServer
756
                    $server_protocol = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https' : 'http';
757
                    $server_name =
758
                        isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME']
759
                            : (isset($_SERVER['HOSTNAME']) ? $_SERVER['HOSTNAME']
760
                            : (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST']
761
                                : (isset($_SERVER['SERVER_ADDR']) ? $_SERVER['SERVER_ADDR']
762
                                    : 'localhost')));
763
                    if (isset($_SERVER['SERVER_PORT']) && !strpos($server_name, ':')
764
                        && (($server_protocol == 'http'
765
                                && $_SERVER['SERVER_PORT'] != 80) || ($server_protocol == 'https' && $_SERVER['SERVER_PORT'] != 443))
766
                    ) {
767
                        $server_name .= ":".$_SERVER['SERVER_PORT'];
768
                    }
769
                    $root_web = $server_protocol.'://'.$server_name.$root_rel;
770
                    $root_sys = str_replace('\\', '/', realpath(__DIR__.'/../../../')).'/';
771
                }
772
                // Here we give up, so we don't touch anything.
773
            }
774
        }
775
    }*/
776
    if (isset(Container::$container)) {
777
        $root_web = Container::$container->get('router')->generate(
778
            'home',
779
            [],
780
            UrlGeneratorInterface::ABSOLUTE_URL
781
        );
782
    }
783
784
    if (isset($configuration['multiple_access_urls']) &&
785
        $configuration['multiple_access_urls']
786
    ) {
787
        // To avoid that the api_get_access_url() function fails since global.inc.php also calls the main_api.lib.php
788
        if (isset($configuration['access_url']) && !empty($configuration['access_url'])) {
789
            // We look into the DB the function api_get_access_url
790
            $urlInfo = api_get_access_url($configuration['access_url']);
791
            // Avoid default value
792
            $defaultValues = ['http://localhost/', 'https://localhost/'];
793
            if (!empty($urlInfo['url']) && !in_array($urlInfo['url'], $defaultValues)) {
794
                $root_web = 1 == $urlInfo['active'] ? $urlInfo['url'] : $configuration['root_web'];
795
            }
796
        }
797
    }
798
799
    $paths = [
800
        WEB_PATH => $root_web,
801
        SYMFONY_SYS_PATH => $root_sys,
802
        SYS_PATH => $root_sys.'public/',
803
        REL_PATH => '',
804
        CONFIGURATION_PATH => 'app/config/',
805
        LIBRARY_PATH => $root_sys.'public/main/inc/lib/',
806
807
        REL_COURSE_PATH => '',
808
        REL_CODE_PATH => '/main/',
809
810
        SYS_CODE_PATH => $root_sys.'public/main/',
811
        SYS_CSS_PATH => $root_sys.'public/build/css/',
812
        SYS_PLUGIN_PATH => $root_sys.'public/plugin/',
813
        SYS_ARCHIVE_PATH => $root_sys.'var/cache/',
814
       // SYS_UPLOAD_PATH => 'var/upload/',
815
        SYS_TEST_PATH => $root_sys.'tests/',
816
        SYS_TEMPLATE_PATH => $root_sys.'public/main/template/',
817
        SYS_PUBLIC_PATH => $root_sys.'public/',
818
        SYS_FONTS_PATH => $root_sys.'public/fonts/',
819
820
        WEB_CODE_PATH => $root_web.'main/',
821
        WEB_PLUGIN_ASSET_PATH => $root_web.'plugins/',
822
        WEB_COURSE_PATH => $root_web.'course/',
823
        WEB_IMG_PATH => $root_web.'img/',
824
        WEB_CSS_PATH => $root_web.'build/css/',
825
        WEB_AJAX_PATH => $root_web.'main/inc/ajax/',
826
        WEB_LIBRARY_PATH => $root_web.'main/inc/lib/',
827
        WEB_LIBRARY_JS_PATH => $root_web.'main/inc/lib/javascript/',
828
        WEB_PLUGIN_PATH => $root_web.'plugin/',
829
       // WEB_ARCHIVE_PATH => 'var/cache/',
830
        //WEB_UPLOAD_PATH => 'var/upload/',
831
        WEB_PUBLIC_PATH => $root_web,
832
    ];
833
834
    $root_rel = '';
835
836
    // Dealing with trailing slashes.
837
    $rootWebWithSlash = api_add_trailing_slash($root_web);
838
    $root_sys = api_add_trailing_slash($root_sys);
839
    $root_rel = api_add_trailing_slash($root_rel);
840
841
    // Initialization of a table that contains common-purpose paths.
842
    /*$paths[$root_web][REL_PATH] = $root_rel;
843
    $paths[$root_web][REL_CODE_PATH] = $root_rel.$code_folder;
844
    $paths[$root_web][WEB_PATH] = $rootWebWithSlash;
845
    $paths[$root_web][WEB_CODE_PATH] = $rootWebWithSlash.'main/';
846
    $paths[$root_web][WEB_COURSE_PATH] = $rootWebWithSlash.$course_folder;
847
    $paths[$root_web][WEB_PLUGIN_PATH] = $rootWebWithSlash.$paths[$root_web][WEB_PLUGIN_PATH];
848
    $paths[$root_web][WEB_PLUGIN_ASSET_PATH] = $rootWebWithSlash.$paths[$root_web][WEB_PLUGIN_ASSET_PATH];
849
    $paths[$root_web][WEB_ARCHIVE_PATH] = $rootWebWithSlash.$paths[$root_web][WEB_ARCHIVE_PATH];
850
    $paths[$root_web][WEB_CSS_PATH] = $rootWebWithSlash.$paths[$root_web][WEB_CSS_PATH];
851
    //$paths[$root_web][WEB_UPLOAD_PATH] = $rootWebWithSlash.$paths[$root_web][WEB_UPLOAD_PATH];
852
    $paths[$root_web][WEB_PUBLIC_PATH] = $rootWebWithSlash;
853
854
    $paths[$root_web][WEB_IMG_PATH] = $rootWebWithSlash.$paths[$root_web][WEB_IMG_PATH];
855
    $paths[$root_web][WEB_LIBRARY_PATH] = $paths[$root_web][WEB_CODE_PATH].$paths[$root_web][WEB_LIBRARY_PATH];
856
    $paths[$root_web][WEB_LIBRARY_JS_PATH] = $paths[$root_web][WEB_CODE_PATH].$paths[$root_web][WEB_LIBRARY_JS_PATH];
857
    $paths[$root_web][WEB_AJAX_PATH] = $paths[$root_web][WEB_CODE_PATH].$paths[$root_web][WEB_AJAX_PATH];
858
859
    $paths[$root_web][SYS_PATH] = $root_sys;
860
    $paths[$root_web][SYS_CODE_PATH] = $root_sys.$code_folder;
861
    $paths[$root_web][SYS_TEST_PATH] = $paths[$root_web][SYS_PATH].$paths[$root_web][SYS_TEST_PATH];
862
    $paths[$root_web][SYS_TEMPLATE_PATH] = $paths[$root_web][SYS_CODE_PATH].$paths[$root_web][SYS_TEMPLATE_PATH];
863
    $paths[$root_web][SYS_PUBLIC_PATH] = $paths[$root_web][SYS_PATH].$paths[$root_web][SYS_PUBLIC_PATH];
864
    $paths[$root_web][SYS_CSS_PATH] = $paths[$root_web][SYS_PATH].$paths[$root_web][SYS_CSS_PATH];
865
    $paths[$root_web][SYS_FONTS_PATH] = $paths[$root_web][SYS_CODE_PATH].$paths[$root_web][SYS_FONTS_PATH];
866
    $paths[$root_web][SYS_ARCHIVE_PATH] = $paths[$root_web][SYS_PATH].$paths[$root_web][SYS_ARCHIVE_PATH];
867
    $paths[$root_web][SYS_APP_PATH] = $paths[$root_web][SYS_PATH].$paths[$root_web][SYS_APP_PATH];
868
    $paths[$root_web][SYS_UPLOAD_PATH] = $paths[$root_web][SYS_PATH].$paths[$root_web][SYS_UPLOAD_PATH];
869
    $paths[$root_web][SYS_PLUGIN_PATH] = $paths[$root_web][SYS_PATH].$paths[$root_web][SYS_PLUGIN_PATH];
870
    $paths[$root_web][LIBRARY_PATH] = $paths[$root_web][SYS_CODE_PATH].$paths[$root_web][LIBRARY_PATH];
871
    $paths[$root_web][CONFIGURATION_PATH] = $paths[$root_web][SYS_PATH].$paths[$root_web][CONFIGURATION_PATH];*/
872
873
    global $virtualChamilo;
874
    if (!empty($virtualChamilo)) {
875
        $paths[SYS_ARCHIVE_PATH] = api_add_trailing_slash($virtualChamilo[SYS_ARCHIVE_PATH]);
876
        $paths[SYS_UPLOAD_PATH] = api_add_trailing_slash($virtualChamilo[SYS_UPLOAD_PATH]);
877
        //$paths[$root_web][WEB_UPLOAD_PATH] = api_add_trailing_slash($virtualChamilo[WEB_UPLOAD_PATH]);
878
        $paths[WEB_ARCHIVE_PATH] = api_add_trailing_slash($virtualChamilo[WEB_ARCHIVE_PATH]);
879
        //$paths[$root_web][WEB_COURSE_PATH] = api_add_trailing_slash($virtualChamilo[WEB_COURSE_PATH]);
880
881
        // WEB_UPLOAD_PATH should be handle by apache htaccess in the vhost
882
883
        // RewriteEngine On
884
        // RewriteRule /app/upload/(.*)$ http://localhost/other/upload/my-chamilo111-net/$1 [QSA,L]
885
886
        //$paths[$root_web][WEB_UPLOAD_PATH] = api_add_trailing_slash($virtualChamilo[WEB_UPLOAD_PATH]);
887
        //$paths[$root_web][REL_PATH] = $virtualChamilo[REL_PATH];
888
        //$paths[$root_web][REL_COURSE_PATH] = $virtualChamilo[REL_COURSE_PATH];
889
    }
890
891
    $path = trim($path);
892
893
    // Retrieving a common-purpose path.
894
    if (isset($paths[$path])) {
895
        return $paths[$path];
896
    }
897
898
    return false;
899
}
900
901
/**
902
 * Adds to a given path a trailing slash if it is necessary (adds "/" character at the end of the string).
903
 *
904
 * @param string $path the input path
905
 *
906
 * @return string returns the modified path
907
 */
908
function api_add_trailing_slash($path)
909
{
910
    return '/' == substr($path, -1) ? $path : $path.'/';
911
}
912
913
/**
914
 * Removes from a given path the trailing slash if it is necessary (removes "/" character from the end of the string).
915
 *
916
 * @param string $path the input path
917
 *
918
 * @return string returns the modified path
919
 */
920
function api_remove_trailing_slash($path)
921
{
922
    return '/' == substr($path, -1) ? substr($path, 0, -1) : $path;
923
}
924
925
/**
926
 * Checks the RFC 3986 syntax of a given URL.
927
 *
928
 * @param string $url      the URL to be checked
929
 * @param bool   $absolute whether the URL is absolute (beginning with a scheme such as "http:")
930
 *
931
 * @return string|false Returns the URL if it is valid, FALSE otherwise.
932
 *                      This function is an adaptation from the function valid_url(), Drupal CMS.
933
 *
934
 * @see http://drupal.org
935
 * Note: The built-in function filter_var($urs, FILTER_VALIDATE_URL) has a bug for some versions of PHP.
936
 * @see http://bugs.php.net/51192
937
 */
938
function api_valid_url($url, $absolute = false)
939
{
940
    if ($absolute) {
941
        if (preg_match("
942
            /^                                                      # Start at the beginning of the text
943
            (?:ftp|https?|feed):\/\/                                # Look for ftp, http, https or feed schemes
944
            (?:                                                     # Userinfo (optional) which is typically
945
                (?:(?:[\w\.\-\+!$&'\(\)*\+,;=]|%[0-9a-f]{2})+:)*    # a username or a username and password
946
                (?:[\w\.\-\+%!$&'\(\)*\+,;=]|%[0-9a-f]{2})+@        # combination
947
            )?
948
            (?:
949
                (?:[a-z0-9\-\.]|%[0-9a-f]{2})+                      # A domain name or a IPv4 address
950
                |(?:\[(?:[0-9a-f]{0,4}:)*(?:[0-9a-f]{0,4})\])       # or a well formed IPv6 address
951
            )
952
            (?::[0-9]+)?                                            # Server port number (optional)
953
            (?:[\/|\?]
954
                (?:[\w#!:\.\?\+=&@$'~*,;\/\(\)\[\]\-]|%[0-9a-f]{2}) # The path and query (optional)
955
            *)?
956
            $/xi", $url)) {
957
            return $url;
958
        }
959
960
        return false;
961
    } else {
962
        return preg_match("/^(?:[\w#!:\.\?\+=&@$'~*,;\/\(\)\[\]\-]|%[0-9a-f]{2})+$/i", $url) ? $url : false;
963
    }
964
}
965
966
/**
967
 * Checks whether a given string looks roughly like an email address.
968
 *
969
 * @param string $address the e-mail address to be checked
970
 *
971
 * @return mixed returns the e-mail if it is valid, FALSE otherwise
972
 */
973
function api_valid_email($address)
974
{
975
    return filter_var($address, FILTER_VALIDATE_EMAIL);
976
}
977
978
/* PROTECTION FUNCTIONS
979
   Use these functions to protect your scripts. */
980
981
/**
982
 * Function used to protect a course script.
983
 * The function blocks access when
984
 * - there is no $_SESSION["_course"] defined; or
985
 * - $is_allowed_in_course is set to false (this depends on the course
986
 * visibility and user status).
987
 *
988
 * This is only the first proposal, test and improve!
989
 *
990
 * @param bool Option to print headers when displaying error message. Default: false
991
 * @param bool whether session admins should be allowed or not
992
 * @param string $checkTool check if tool is available for users (user, group)
993
 *
994
 * @return bool True if the user has access to the current course or is out of a course context, false otherwise
995
 *
996
 * @todo replace global variable
997
 *
998
 * @author Roan Embrechts
999
 */
1000
function api_protect_course_script($print_headers = false, $allow_session_admins = false, $checkTool = '')
1001
{
1002
    $course_info = api_get_course_info();
1003
    if (empty($course_info)) {
1004
        api_not_allowed($print_headers);
1005
1006
        return false;
1007
    }
1008
1009
    if (api_is_drh()) {
1010
        return true;
1011
    }
1012
1013
    // Session admin has access to course
1014
    $sessionAccess = api_get_configuration_value('session_admins_access_all_content');
1015
    if ($sessionAccess) {
1016
        $allow_session_admins = true;
1017
    }
1018
1019
    if (api_is_platform_admin($allow_session_admins)) {
1020
        return true;
1021
    }
1022
1023
    $isAllowedInCourse = api_is_allowed_in_course();
1024
    $is_visible = false;
1025
    if (isset($course_info) && isset($course_info['visibility'])) {
1026
        switch ($course_info['visibility']) {
1027
            default:
1028
            case COURSE_VISIBILITY_CLOSED:
1029
                // Completely closed: the course is only accessible to the teachers. - 0
1030
                if ($isAllowedInCourse && api_get_user_id() && !api_is_anonymous()) {
1031
                    $is_visible = true;
1032
                }
1033
                break;
1034
            case COURSE_VISIBILITY_REGISTERED:
1035
                // Private - access authorized to course members only - 1
1036
                if ($isAllowedInCourse && api_get_user_id() && !api_is_anonymous()) {
1037
                    $is_visible = true;
1038
                }
1039
                break;
1040
            case COURSE_VISIBILITY_OPEN_PLATFORM:
1041
                // Open - access allowed for users registered on the platform - 2
1042
                if ($isAllowedInCourse && api_get_user_id() && !api_is_anonymous()) {
1043
                    $is_visible = true;
1044
                }
1045
                break;
1046
            case COURSE_VISIBILITY_OPEN_WORLD:
1047
                //Open - access allowed for the whole world - 3
1048
                $is_visible = true;
1049
                break;
1050
            case COURSE_VISIBILITY_HIDDEN:
1051
                //Completely closed: the course is only accessible to the teachers. - 0
1052
                if (api_is_platform_admin()) {
1053
                    $is_visible = true;
1054
                }
1055
                break;
1056
        }
1057
1058
        //If password is set and user is not registered to the course then the course is not visible
1059
        if (false == $isAllowedInCourse &&
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...
1060
            isset($course_info['registration_code']) &&
1061
            !empty($course_info['registration_code'])
1062
        ) {
1063
            $is_visible = false;
1064
        }
1065
    }
1066
1067
    if (!empty($checkTool)) {
1068
        if (!api_is_allowed_to_edit(true, true, true)) {
1069
            $toolInfo = api_get_tool_information_by_name($checkTool);
1070
            if (!empty($toolInfo) && isset($toolInfo['visibility']) && 0 == $toolInfo['visibility']) {
1071
                api_not_allowed(true);
1072
1073
                return false;
1074
            }
1075
        }
1076
    }
1077
1078
    // Check session visibility
1079
    $session_id = api_get_session_id();
1080
1081
    if (!empty($session_id)) {
1082
        // $isAllowedInCourse was set in local.inc.php
1083
        if (!$isAllowedInCourse) {
1084
            $is_visible = false;
1085
        }
1086
    }
1087
1088
    if (!$is_visible) {
1089
        api_not_allowed($print_headers);
1090
1091
        return false;
1092
    }
1093
1094
    return true;
1095
}
1096
1097
/**
1098
 * Function used to protect an admin script.
1099
 *
1100
 * The function blocks access when the user has no platform admin rights
1101
 * with an error message printed on default output
1102
 *
1103
 * @param bool Whether to allow session admins as well
1104
 * @param bool Whether to allow HR directors as well
1105
 * @param string An optional message (already passed through get_lang)
1106
 *
1107
 * @return bool True if user is allowed, false otherwise.
1108
 *              The function also outputs an error message in case not allowed
1109
 *
1110
 * @author Roan Embrechts (original author)
1111
 */
1112
function api_protect_admin_script($allow_sessions_admins = false, $allow_drh = false, $message = null)
1113
{
1114
    if (!api_is_platform_admin($allow_sessions_admins, $allow_drh)) {
1115
        api_not_allowed(true, $message);
1116
1117
        return false;
1118
    }
1119
1120
    return true;
1121
}
1122
1123
/**
1124
 * Function used to protect a teacher script.
1125
 * The function blocks access when the user has no teacher rights.
1126
 *
1127
 * @return bool True if the current user can access the script, false otherwise
1128
 *
1129
 * @author Yoselyn Castillo
1130
 */
1131
function api_protect_teacher_script()
1132
{
1133
    if (!api_is_allowed_to_edit()) {
1134
        api_not_allowed(true);
1135
1136
        return false;
1137
    }
1138
1139
    return true;
1140
}
1141
1142
/**
1143
 * Function used to prevent anonymous users from accessing a script.
1144
 *
1145
 * @param bool|true $printHeaders
1146
 *
1147
 * @author Roan Embrechts
1148
 *
1149
 * @return bool
1150
 */
1151
function api_block_anonymous_users($printHeaders = true)
1152
{
1153
    $user = api_get_user_info();
1154
    if (!(isset($user['user_id']) && $user['user_id']) || api_is_anonymous($user['user_id'], true)) {
1155
        api_not_allowed($printHeaders);
1156
1157
        return false;
1158
    }
1159
1160
    return true;
1161
}
1162
1163
/**
1164
 * Returns a rough evaluation of the browser's name and version based on very
1165
 * simple regexp.
1166
 *
1167
 * @return array with the navigator name and version ['name' => '...', 'version' => '...']
1168
 */
1169
function api_get_navigator()
1170
{
1171
    $navigator = 'Unknown';
1172
    $version = 0;
1173
1174
    if (!isset($_SERVER['HTTP_USER_AGENT'])) {
1175
        return ['name' => 'Unknown', 'version' => '0.0.0'];
1176
    }
1177
1178
    if (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Opera')) {
1179
        $navigator = 'Opera';
1180
        [, $version] = explode('Opera', $_SERVER['HTTP_USER_AGENT']);
1181
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Edge')) {
1182
        $navigator = 'Edge';
1183
        [, $version] = explode('Edge', $_SERVER['HTTP_USER_AGENT']);
1184
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE')) {
1185
        $navigator = 'Internet Explorer';
1186
        [, $version] = explode('MSIE ', $_SERVER['HTTP_USER_AGENT']);
1187
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Chrome')) {
1188
        $navigator = 'Chrome';
1189
        [, $version] = explode('Chrome', $_SERVER['HTTP_USER_AGENT']);
1190
    } elseif (false !== stripos($_SERVER['HTTP_USER_AGENT'], 'Safari')) {
1191
        $navigator = 'Safari';
1192
        if (false !== stripos($_SERVER['HTTP_USER_AGENT'], 'Version/')) {
1193
            // If this Safari does have the "Version/" string in its user agent
1194
            // then use that as a version indicator rather than what's after
1195
            // "Safari/" which is rather a "build number" or something
1196
            [, $version] = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1197
        } else {
1198
            [, $version] = explode('Safari/', $_SERVER['HTTP_USER_AGENT']);
1199
        }
1200
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Firefox')) {
1201
        $navigator = 'Firefox';
1202
        [, $version] = explode('Firefox', $_SERVER['HTTP_USER_AGENT']);
1203
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Netscape')) {
1204
        $navigator = 'Netscape';
1205
        if (false !== stripos($_SERVER['HTTP_USER_AGENT'], 'Netscape/')) {
1206
            [, $version] = explode('Netscape', $_SERVER['HTTP_USER_AGENT']);
1207
        } else {
1208
            [, $version] = explode('Navigator', $_SERVER['HTTP_USER_AGENT']);
1209
        }
1210
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Konqueror')) {
1211
        $navigator = 'Konqueror';
1212
        [, $version] = explode('Konqueror', $_SERVER['HTTP_USER_AGENT']);
1213
    } elseif (false !== stripos($_SERVER['HTTP_USER_AGENT'], 'applewebkit')) {
1214
        $navigator = 'AppleWebKit';
1215
        [, $version] = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1216
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Gecko')) {
1217
        $navigator = 'Mozilla';
1218
        [, $version] = explode('; rv:', $_SERVER['HTTP_USER_AGENT']);
1219
    }
1220
1221
    // Now cut extra stuff around (mostly *after*) the version number
1222
    $version = preg_replace('/^([\/\s])?([\d\.]+)?.*/', '\2', $version);
1223
1224
    if (false === strpos($version, '.')) {
1225
        $version = number_format(doubleval($version), 1);
1226
    }
1227
1228
    return ['name' => $navigator, 'version' => $version];
1229
}
1230
1231
/**
1232
 * @return true if user self registration is allowed, false otherwise
1233
 */
1234
function api_is_self_registration_allowed()
1235
{
1236
    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...
1237
}
1238
1239
/**
1240
 * This function returns the id of the user which is stored in the $_user array.
1241
 *
1242
 * example: The function can be used to check if a user is logged in
1243
 *          if (api_get_user_id())
1244
 *
1245
 * @return int the id of the current user, 0 if is empty
1246
 */
1247
function api_get_user_id()
1248
{
1249
    $userInfo = Session::read('_user');
1250
    if ($userInfo && isset($userInfo['user_id'])) {
1251
        return (int) $userInfo['user_id'];
1252
    }
1253
1254
    return 0;
1255
}
1256
1257
/**
1258
 * Gets the list of courses a specific user is subscribed to.
1259
 *
1260
 * @param int       User ID
1261
 * @param bool $fetch_session Whether to get session courses or not - NOT YET IMPLEMENTED
1262
 *
1263
 * @return array Array of courses in the form [0]=>('code'=>xxx,'db'=>xxx,'dir'=>xxx,'status'=>d)
1264
 *
1265
 * @deprecated use CourseManager::get_courses_list_by_user_id()
1266
 */
1267
function api_get_user_courses($userId, $fetch_session = true)
1268
{
1269
    // Get out if not integer
1270
    if ($userId != strval(intval($userId))) {
1271
        return [];
1272
    }
1273
1274
    $t_course = Database::get_main_table(TABLE_MAIN_COURSE);
1275
    $t_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
1276
1277
    $sql = "SELECT cc.id as real_id, cc.code code, cc.directory dir, cu.status status
1278
            FROM $t_course cc, $t_course_user cu
1279
            WHERE
1280
                cc.id = cu.c_id AND
1281
                cu.user_id = $userId AND
1282
                cu.relation_type <> ".COURSE_RELATION_TYPE_RRHH;
1283
    $result = Database::query($sql);
1284
    if (false === $result) {
1285
        return [];
1286
    }
1287
1288
    $courses = [];
1289
    while ($row = Database::fetch_array($result)) {
1290
        // we only need the database name of the course
1291
        $courses[] = $row;
1292
    }
1293
1294
    return $courses;
1295
}
1296
1297
/**
1298
 * Formats user information into a standard array
1299
 * This function should be only used inside api_get_user_info().
1300
 *
1301
 * @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...
1302
 * @param bool $add_password
1303
 * @param bool $loadAvatars  turn off to improve performance
1304
 *
1305
 * @return array Standard user array
1306
 */
1307
function _api_format_user($user, $add_password = false, $loadAvatars = true)
1308
{
1309
    $result = [];
1310
1311
    if (!isset($user['id'])) {
1312
        return [];
1313
    }
1314
1315
    $result['firstname'] = null;
1316
    $result['lastname'] = null;
1317
1318
    if (isset($user['firstname']) && isset($user['lastname'])) {
1319
        // with only lowercase
1320
        $result['firstname'] = $user['firstname'];
1321
        $result['lastname'] = $user['lastname'];
1322
    } elseif (isset($user['firstName']) && isset($user['lastName'])) {
1323
        // with uppercase letters
1324
        $result['firstname'] = isset($user['firstName']) ? $user['firstName'] : null;
1325
        $result['lastname'] = isset($user['lastName']) ? $user['lastName'] : null;
1326
    }
1327
1328
    if (isset($user['email'])) {
1329
        $result['mail'] = isset($user['email']) ? $user['email'] : null;
1330
        $result['email'] = isset($user['email']) ? $user['email'] : null;
1331
    } else {
1332
        $result['mail'] = isset($user['mail']) ? $user['mail'] : null;
1333
        $result['email'] = isset($user['mail']) ? $user['mail'] : null;
1334
    }
1335
1336
    $result['complete_name'] = api_get_person_name($result['firstname'], $result['lastname']);
1337
    $result['complete_name_with_username'] = $result['complete_name'];
1338
1339
    if (!empty($user['username']) && 'false' === api_get_setting('profile.hide_username_with_complete_name')) {
1340
        $result['complete_name_with_username'] = $result['complete_name'].' ('.$user['username'].')';
1341
    }
1342
1343
    $showEmail = 'true' === api_get_setting('show_email_addresses');
1344
    if (!empty($user['email'])) {
1345
        $result['complete_name_with_email_forced'] = $result['complete_name'].' ('.$user['email'].')';
1346
        if ($showEmail) {
1347
            $result['complete_name_with_email'] = $result['complete_name'].' ('.$user['email'].')';
1348
        }
1349
    } else {
1350
        $result['complete_name_with_email'] = $result['complete_name'];
1351
        $result['complete_name_with_email_forced'] = $result['complete_name'];
1352
    }
1353
1354
    // Kept for historical reasons
1355
    $result['firstName'] = $result['firstname'];
1356
    $result['lastName'] = $result['lastname'];
1357
1358
    $attributes = [
1359
        'phone',
1360
        'address',
1361
        'picture_uri',
1362
        'official_code',
1363
        'status',
1364
        'active',
1365
        'auth_source',
1366
        'username',
1367
        'theme',
1368
        'language',
1369
        'creator_id',
1370
        'registration_date',
1371
        'hr_dept_id',
1372
        'expiration_date',
1373
        'last_login',
1374
        'user_is_online',
1375
    ];
1376
1377
    if ('true' === api_get_setting('extended_profile')) {
1378
        $attributes[] = 'competences';
1379
        $attributes[] = 'diplomas';
1380
        $attributes[] = 'teach';
1381
        $attributes[] = 'openarea';
1382
    }
1383
1384
    foreach ($attributes as $attribute) {
1385
        $result[$attribute] = isset($user[$attribute]) ? $user[$attribute] : null;
1386
    }
1387
1388
    $user_id = (int) $user['id'];
1389
    // Maintain the user_id index for backwards compatibility
1390
    $result['user_id'] = $result['id'] = $user_id;
1391
1392
    $hasCertificates = Certificate::getCertificateByUser($user_id);
1393
    $result['has_certificates'] = 0;
1394
    if (!empty($hasCertificates)) {
1395
        $result['has_certificates'] = 1;
1396
    }
1397
1398
    $result['icon_status'] = '';
1399
    $result['icon_status_medium'] = '';
1400
    $result['is_admin'] = UserManager::is_admin($user_id);
1401
1402
    // Getting user avatar.
1403
    if ($loadAvatars) {
1404
        $result['avatar'] = '';
1405
        $result['avatar_no_query'] = '';
1406
        $result['avatar_small'] = '';
1407
        $result['avatar_medium'] = '';
1408
1409
        /*if (!isset($user['avatar'])) {
1410
            $originalFile = UserManager::getUserPicture(
1411
                $user_id,
1412
                USER_IMAGE_SIZE_ORIGINAL,
1413
                null,
1414
                $result
1415
            );
1416
            $result['avatar'] = $originalFile;
1417
            $avatarString = explode('?', $result['avatar']);
1418
            $result['avatar_no_query'] = reset($avatarString);
1419
        } else {
1420
            $result['avatar'] = $user['avatar'];
1421
            $avatarString = explode('?', $user['avatar']);
1422
            $result['avatar_no_query'] = reset($avatarString);
1423
        }
1424
1425
        if (!isset($user['avatar_small'])) {
1426
            $smallFile = UserManager::getUserPicture(
1427
                $user_id,
1428
                USER_IMAGE_SIZE_SMALL,
1429
                null,
1430
                $result
1431
            );
1432
            $result['avatar_small'] = $smallFile;
1433
        } else {
1434
            $result['avatar_small'] = $user['avatar_small'];
1435
        }
1436
1437
        if (!isset($user['avatar_medium'])) {
1438
            $mediumFile = UserManager::getUserPicture(
1439
                $user_id,
1440
                USER_IMAGE_SIZE_MEDIUM,
1441
                null,
1442
                $result
1443
            );
1444
            $result['avatar_medium'] = $mediumFile;
1445
        } else {
1446
            $result['avatar_medium'] = $user['avatar_medium'];
1447
        }*/
1448
1449
        $urlImg = api_get_path(WEB_IMG_PATH);
1450
        $iconStatus = '';
1451
        $iconStatusMedium = '';
1452
        $label = '';
1453
        switch ($result['status']) {
1454
            case STUDENT:
1455
                if ($result['has_certificates']) {
1456
                    $iconStatus = $urlImg.'icons/svg/identifier_graduated.svg';
1457
                    $label = get_lang('Graduated');
1458
                } else {
1459
                    $iconStatus = $urlImg.'icons/svg/identifier_student.svg';
1460
                    $label = get_lang('Student');
1461
                }
1462
                break;
1463
            case COURSEMANAGER:
1464
                if ($result['is_admin']) {
1465
                    $iconStatus = $urlImg.'icons/svg/identifier_admin.svg';
1466
                    $label = get_lang('Admin');
1467
                } else {
1468
                    $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1469
                    $label = get_lang('Teacher');
1470
                }
1471
                break;
1472
            case STUDENT_BOSS:
1473
                $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1474
                $label = get_lang('StudentBoss');
1475
                break;
1476
        }
1477
1478
        if (!empty($iconStatus)) {
1479
            $iconStatusMedium = '<img src="'.$iconStatus.'" width="32px" height="32px">';
1480
            $iconStatus = '<img src="'.$iconStatus.'" width="22px" height="22px">';
1481
        }
1482
1483
        $result['icon_status'] = $iconStatus;
1484
        $result['icon_status_label'] = $label;
1485
        $result['icon_status_medium'] = $iconStatusMedium;
1486
    }
1487
1488
    if (isset($user['user_is_online'])) {
1489
        $result['user_is_online'] = true == $user['user_is_online'] ? 1 : 0;
1490
    }
1491
    if (isset($user['user_is_online_in_chat'])) {
1492
        $result['user_is_online_in_chat'] = (int) $user['user_is_online_in_chat'];
1493
    }
1494
1495
    if ($add_password) {
1496
        $result['password'] = $user['password'];
1497
    }
1498
1499
    if (isset($result['profile_completed'])) {
1500
        $result['profile_completed'] = $user['profile_completed'];
1501
    }
1502
1503
    $result['profile_url'] = api_get_path(WEB_CODE_PATH).'social/profile.php?u='.$user_id;
1504
1505
    // Send message link
1506
    $sendMessage = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&user_id='.$user_id;
1507
    $result['complete_name_with_message_link'] = Display::url(
1508
        $result['complete_name_with_username'],
1509
        $sendMessage,
1510
        ['class' => 'ajax']
1511
    );
1512
1513
    if (isset($user['extra'])) {
1514
        $result['extra'] = $user['extra'];
1515
    }
1516
1517
    return $result;
1518
}
1519
1520
/**
1521
 * Finds all the information about a user.
1522
 * If no parameter is passed you find all the information about the current user.
1523
 *
1524
 * @param int  $user_id
1525
 * @param bool $checkIfUserOnline
1526
 * @param bool $showPassword
1527
 * @param bool $loadExtraData
1528
 * @param bool $loadOnlyVisibleExtraData Get the user extra fields that are visible
1529
 * @param bool $loadAvatars              turn off to improve performance and if avatars are not needed
1530
 * @param bool $updateCache              update apc cache if exists
1531
 *
1532
 * @return mixed $user_info user_id, lastname, firstname, username, email, etc or false on error
1533
 *
1534
 * @author Patrick Cool <[email protected]>
1535
 * @author Julio Montoya
1536
 *
1537
 * @version 21 September 2004
1538
 */
1539
function api_get_user_info(
1540
    $user_id = 0,
1541
    $checkIfUserOnline = false,
1542
    $showPassword = false,
1543
    $loadExtraData = false,
1544
    $loadOnlyVisibleExtraData = false,
1545
    $loadAvatars = true,
1546
    $updateCache = false
1547
) {
1548
    // Make sure user_id is safe
1549
    $user_id = (int) $user_id;
1550
    $user = false;
1551
    if (empty($user_id)) {
1552
        $userFromSession = Session::read('_user');
1553
        if (isset($userFromSession) && !empty($userFromSession)) {
1554
            return $userFromSession;
1555
            /*
1556
            return _api_format_user(
1557
                $userFromSession,
1558
                $showPassword,
1559
                $loadAvatars
1560
            );*/
1561
        }
1562
1563
        return false;
1564
    }
1565
1566
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1567
            WHERE id = $user_id";
1568
    $result = Database::query($sql);
1569
    if (Database::num_rows($result) > 0) {
1570
        $result_array = Database::fetch_array($result);
1571
        $result_array['user_is_online_in_chat'] = 0;
1572
        if ($checkIfUserOnline) {
1573
            $use_status_in_platform = user_is_online($user_id);
1574
            $result_array['user_is_online'] = $use_status_in_platform;
1575
            $user_online_in_chat = 0;
1576
            if ($use_status_in_platform) {
1577
                $user_status = UserManager::get_extra_user_data_by_field(
1578
                    $user_id,
1579
                    'user_chat_status',
1580
                    false,
1581
                    true
1582
                );
1583
                if (1 == (int) $user_status['user_chat_status']) {
1584
                    $user_online_in_chat = 1;
1585
                }
1586
            }
1587
            $result_array['user_is_online_in_chat'] = $user_online_in_chat;
1588
        }
1589
1590
        if ($loadExtraData) {
1591
            $fieldValue = new ExtraFieldValue('user');
1592
            $result_array['extra'] = $fieldValue->getAllValuesForAnItem(
1593
                $user_id,
1594
                $loadOnlyVisibleExtraData
1595
            );
1596
        }
1597
        $user = _api_format_user($result_array, $showPassword, $loadAvatars);
1598
    }
1599
1600
    return $user;
1601
}
1602
1603
function api_get_user_info_from_entity(
1604
    User $user,
1605
    $checkIfUserOnline = false,
1606
    $showPassword = false,
1607
    $loadExtraData = false,
1608
    $loadOnlyVisibleExtraData = false,
1609
    $loadAvatars = true,
1610
    $loadCertificate = false
1611
) {
1612
    if (!$user instanceof UserInterface) {
1613
        return false;
1614
    }
1615
1616
    // Make sure user_id is safe
1617
    $user_id = (int) $user->getId();
1618
1619
    if (empty($user_id)) {
1620
        $userFromSession = Session::read('_user');
1621
1622
        if (isset($userFromSession) && !empty($userFromSession)) {
1623
            return $userFromSession;
1624
        }
1625
1626
        return false;
1627
    }
1628
1629
    $result = [];
1630
    $result['user_is_online_in_chat'] = 0;
1631
    if ($checkIfUserOnline) {
1632
        $use_status_in_platform = user_is_online($user_id);
1633
        $result['user_is_online'] = $use_status_in_platform;
1634
        $user_online_in_chat = 0;
1635
        if ($use_status_in_platform) {
1636
            $user_status = UserManager::get_extra_user_data_by_field(
1637
                $user_id,
1638
                'user_chat_status',
1639
                false,
1640
                true
1641
            );
1642
            if (1 == (int) $user_status['user_chat_status']) {
1643
                $user_online_in_chat = 1;
1644
            }
1645
        }
1646
        $result['user_is_online_in_chat'] = $user_online_in_chat;
1647
    }
1648
1649
    if ($loadExtraData) {
1650
        $fieldValue = new ExtraFieldValue('user');
1651
        $result['extra'] = $fieldValue->getAllValuesForAnItem(
1652
            $user_id,
1653
            $loadOnlyVisibleExtraData
1654
        );
1655
    }
1656
1657
    $result['username'] = $user->getUsername();
1658
    $result['status'] = $user->getStatus();
1659
    $result['firstname'] = $user->getFirstname();
1660
    $result['lastname'] = $user->getLastname();
1661
    $result['email'] = $result['mail'] = $user->getEmail();
1662
    $result['complete_name'] = api_get_person_name($result['firstname'], $result['lastname']);
1663
    $result['complete_name_with_username'] = $result['complete_name'];
1664
1665
    if (!empty($result['username']) && 'false' === api_get_setting('profile.hide_username_with_complete_name')) {
1666
        $result['complete_name_with_username'] = $result['complete_name'].' ('.$result['username'].')';
1667
    }
1668
1669
    $showEmail = 'true' === api_get_setting('show_email_addresses');
1670
    if (!empty($result['email'])) {
1671
        $result['complete_name_with_email_forced'] = $result['complete_name'].' ('.$result['email'].')';
1672
        if ($showEmail) {
1673
            $result['complete_name_with_email'] = $result['complete_name'].' ('.$result['email'].')';
1674
        }
1675
    } else {
1676
        $result['complete_name_with_email'] = $result['complete_name'];
1677
        $result['complete_name_with_email_forced'] = $result['complete_name'];
1678
    }
1679
1680
    // Kept for historical reasons
1681
    $result['firstName'] = $result['firstname'];
1682
    $result['lastName'] = $result['lastname'];
1683
1684
    $attributes = [
1685
        'picture_uri',
1686
        'last_login',
1687
        'user_is_online',
1688
    ];
1689
1690
    $result['phone'] = $user->getPhone();
1691
    $result['address'] = $user->getAddress();
1692
    $result['official_code'] = $user->getOfficialCode();
1693
    $result['active'] = $user->getActive();
1694
    $result['auth_source'] = $user->getAuthSource();
1695
    $result['language'] = $user->getLanguage();
1696
    $result['creator_id'] = $user->getCreatorId();
1697
    $result['registration_date'] = $user->getRegistrationDate()->format('Y-m-d H:i:s');
1698
    $result['hr_dept_id'] = $user->getHrDeptId();
1699
    $result['expiration_date'] = '';
1700
    if ($user->getExpirationDate()) {
1701
        $result['expiration_date'] = $user->getExpirationDate()->format('Y-m-d H:i:s');
1702
    }
1703
1704
    $result['last_login'] = null;
1705
    if ($user->getLastLogin()) {
1706
        $result['last_login'] = $user->getLastLogin()->format('Y-m-d H:i:s');
1707
    }
1708
1709
    $result['competences'] = $user->getCompetences();
1710
    $result['diplomas'] = $user->getDiplomas();
1711
    $result['teach'] = $user->getTeach();
1712
    $result['openarea'] = $user->getOpenarea();
1713
    $user_id = (int) $user->getId();
1714
1715
    // Maintain the user_id index for backwards compatibility
1716
    $result['user_id'] = $result['id'] = $user_id;
1717
1718
    if ($loadCertificate) {
1719
        $hasCertificates = Certificate::getCertificateByUser($user_id);
1720
        $result['has_certificates'] = 0;
1721
        if (!empty($hasCertificates)) {
1722
            $result['has_certificates'] = 1;
1723
        }
1724
    }
1725
1726
    $result['icon_status'] = '';
1727
    $result['icon_status_medium'] = '';
1728
    $result['is_admin'] = UserManager::is_admin($user_id);
1729
1730
    // Getting user avatar.
1731
    if ($loadAvatars) {
1732
        $result['avatar'] = '';
1733
        $result['avatar_no_query'] = '';
1734
        $result['avatar_small'] = '';
1735
        $result['avatar_medium'] = '';
1736
1737
        /*if (!isset($user['avatar'])) {
1738
            $originalFile = UserManager::getUserPicture(
1739
                $user_id,
1740
                USER_IMAGE_SIZE_ORIGINAL,
1741
                null,
1742
                $result
1743
            );
1744
            $result['avatar'] = $originalFile;
1745
            $avatarString = explode('?', $result['avatar']);
1746
            $result['avatar_no_query'] = reset($avatarString);
1747
        } else {
1748
            $result['avatar'] = $user['avatar'];
1749
            $avatarString = explode('?', $user['avatar']);
1750
            $result['avatar_no_query'] = reset($avatarString);
1751
        }
1752
1753
        if (!isset($user['avatar_small'])) {
1754
            $smallFile = UserManager::getUserPicture(
1755
                $user_id,
1756
                USER_IMAGE_SIZE_SMALL,
1757
                null,
1758
                $result
1759
            );
1760
            $result['avatar_small'] = $smallFile;
1761
        } else {
1762
            $result['avatar_small'] = $user['avatar_small'];
1763
        }
1764
1765
        if (!isset($user['avatar_medium'])) {
1766
            $mediumFile = UserManager::getUserPicture(
1767
                $user_id,
1768
                USER_IMAGE_SIZE_MEDIUM,
1769
                null,
1770
                $result
1771
            );
1772
            $result['avatar_medium'] = $mediumFile;
1773
        } else {
1774
            $result['avatar_medium'] = $user['avatar_medium'];
1775
        }*/
1776
1777
        //$urlImg = api_get_path(WEB_IMG_PATH);
1778
        $urlImg = '/';
1779
        $iconStatus = '';
1780
        $iconStatusMedium = '';
1781
1782
        switch ($user->getStatus()) {
1783
            case STUDENT:
1784
                if (isset($result['has_certificates']) && $result['has_certificates']) {
1785
                    $iconStatus = $urlImg.'icons/svg/identifier_graduated.svg';
1786
                } else {
1787
                    $iconStatus = $urlImg.'icons/svg/identifier_student.svg';
1788
                }
1789
                break;
1790
            case COURSEMANAGER:
1791
                if ($result['is_admin']) {
1792
                    $iconStatus = $urlImg.'icons/svg/identifier_admin.svg';
1793
                } else {
1794
                    $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1795
                }
1796
                break;
1797
            case STUDENT_BOSS:
1798
                $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1799
                break;
1800
        }
1801
1802
        if (!empty($iconStatus)) {
1803
            $iconStatusMedium = '<img src="'.$iconStatus.'" width="32px" height="32px">';
1804
            $iconStatus = '<img src="'.$iconStatus.'" width="22px" height="22px">';
1805
        }
1806
1807
        $result['icon_status'] = $iconStatus;
1808
        $result['icon_status_medium'] = $iconStatusMedium;
1809
    }
1810
1811
    if (isset($result['user_is_online'])) {
1812
        $result['user_is_online'] = true == $result['user_is_online'] ? 1 : 0;
1813
    }
1814
    if (isset($result['user_is_online_in_chat'])) {
1815
        $result['user_is_online_in_chat'] = (int) $result['user_is_online_in_chat'];
1816
    }
1817
1818
    $result['password'] = '';
1819
    if ($showPassword) {
1820
        $result['password'] = $user->getPassword();
1821
    }
1822
1823
    if (isset($result['profile_completed'])) {
1824
        $result['profile_completed'] = $result['profile_completed'];
1825
    }
1826
1827
    $result['profile_url'] = api_get_path(WEB_CODE_PATH).'social/profile.php?u='.$user_id;
1828
1829
    // Send message link
1830
    $sendMessage = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&user_id='.$user_id;
1831
    $result['complete_name_with_message_link'] = Display::url(
1832
        $result['complete_name_with_username'],
1833
        $sendMessage,
1834
        ['class' => 'ajax']
1835
    );
1836
1837
    if (isset($result['extra'])) {
1838
        $result['extra'] = $result['extra'];
1839
    }
1840
1841
    return $result;
1842
}
1843
1844
/**
1845
 * @param int $userId
1846
 *
1847
 * @return User
1848
 */
1849
function api_get_user_entity($userId)
1850
{
1851
    $userId = (int) $userId;
1852
    $repo = UserManager::getRepository();
1853
1854
    /** @var User $user */
1855
    $user = $repo->find($userId);
1856
1857
    return $user;
1858
}
1859
1860
/**
1861
 * @return User|null
1862
 */
1863
function api_get_current_user()
1864
{
1865
    $isLoggedIn = Container::$container->get('security.authorization_checker')->isGranted('IS_AUTHENTICATED_REMEMBERED');
1866
    if (false === $isLoggedIn) {
1867
        return null;
1868
    }
1869
1870
    $token = Container::$container->get('security.token_storage')->getToken();
1871
1872
    if (null !== $token) {
1873
        return $token->getUser();
1874
    }
1875
1876
    return null;
1877
}
1878
1879
/**
1880
 * Finds all the information about a user from username instead of user id.
1881
 *
1882
 * @param string $username
1883
 *
1884
 * @return mixed $user_info array user_id, lastname, firstname, username, email or false on error
1885
 *
1886
 * @author Yannick Warnier <[email protected]>
1887
 */
1888
function api_get_user_info_from_username($username)
1889
{
1890
    if (empty($username)) {
1891
        return false;
1892
    }
1893
    $username = trim($username);
1894
1895
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1896
            WHERE username='".Database::escape_string($username)."'";
1897
    $result = Database::query($sql);
1898
    if (Database::num_rows($result) > 0) {
1899
        $resultArray = Database::fetch_array($result);
1900
1901
        return _api_format_user($resultArray);
1902
    }
1903
1904
    return false;
1905
}
1906
1907
/**
1908
 * Get first user with an email.
1909
 *
1910
 * @param string $email
1911
 *
1912
 * @return array|bool
1913
 */
1914
function api_get_user_info_from_email($email = '')
1915
{
1916
    if (empty($email)) {
1917
        return false;
1918
    }
1919
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1920
            WHERE email ='".Database::escape_string($email)."' LIMIT 1";
1921
    $result = Database::query($sql);
1922
    if (Database::num_rows($result) > 0) {
1923
        $resultArray = Database::fetch_array($result);
1924
1925
        return _api_format_user($resultArray);
1926
    }
1927
1928
    return false;
1929
}
1930
1931
/**
1932
 * @return string
1933
 */
1934
function api_get_course_id()
1935
{
1936
    return Session::read('_cid', null);
1937
}
1938
1939
/**
1940
 * Returns the current course id (integer).
1941
 *
1942
 * @param string $code Optional course code
1943
 *
1944
 * @return int
1945
 */
1946
function api_get_course_int_id($code = null)
1947
{
1948
    if (!empty($code)) {
1949
        $code = Database::escape_string($code);
1950
        $row = Database::select(
1951
            'id',
1952
            Database::get_main_table(TABLE_MAIN_COURSE),
1953
            ['where' => ['code = ?' => [$code]]],
1954
            'first'
1955
        );
1956
1957
        if (is_array($row) && isset($row['id'])) {
1958
            return $row['id'];
1959
        } else {
1960
            return false;
1961
        }
1962
    }
1963
1964
    return Session::read('_real_cid', 0);
1965
}
1966
1967
/**
1968
 * Returns the current course directory.
1969
 *
1970
 * This function relies on api_get_course_info()
1971
 *
1972
 * @param string    The course code - optional (takes it from session if not given)
1973
 *
1974
 * @return string The directory where the course is located inside the Chamilo "courses" directory
1975
 *
1976
 * @author Yannick Warnier <[email protected]>
1977
 */
1978
function api_get_course_path($course_code = null)
1979
{
1980
    $info = !empty($course_code) ? api_get_course_info($course_code) : api_get_course_info();
1981
1982
    return $info['path'];
1983
}
1984
1985
/**
1986
 * Gets a course setting from the current course_setting table. Try always using integer values.
1987
 *
1988
 * @param string $settingName The name of the setting we want from the table
1989
 * @param array  $courseInfo
1990
 * @param bool   $force       force checking the value in the database
1991
 *
1992
 * @return mixed The value of that setting in that table. Return -1 if not found.
1993
 */
1994
function api_get_course_setting($settingName, $courseInfo = [], $force = false)
1995
{
1996
    if (empty($courseInfo)) {
1997
        $courseInfo = api_get_course_info();
1998
    }
1999
2000
    if (empty($courseInfo) || empty($settingName)) {
2001
        return -1;
2002
    }
2003
2004
    $courseId = isset($courseInfo['real_id']) && !empty($courseInfo['real_id']) ? $courseInfo['real_id'] : 0;
2005
2006
    if (empty($courseId)) {
2007
        return -1;
2008
    }
2009
2010
    static $courseSettingInfo = [];
2011
2012
    if ($force) {
2013
        $courseSettingInfo = [];
2014
    }
2015
2016
    if (!isset($courseSettingInfo[$courseId])) {
2017
        $table = Database::get_course_table(TABLE_COURSE_SETTING);
2018
        $settingName = Database::escape_string($settingName);
2019
2020
        $sql = "SELECT variable, value FROM $table
2021
                WHERE c_id = $courseId ";
2022
        $res = Database::query($sql);
2023
        if (Database::num_rows($res) > 0) {
2024
            $result = Database::store_result($res, 'ASSOC');
2025
            $courseSettingInfo[$courseId] = array_column($result, 'value', 'variable');
2026
2027
            if (isset($courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'])) {
2028
                $value = $courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'];
2029
                if (!is_null($value)) {
2030
                    $result = explode(',', $value);
2031
                    $courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'] = $result;
2032
                }
2033
            }
2034
        }
2035
    }
2036
2037
    if (isset($courseSettingInfo[$courseId]) && isset($courseSettingInfo[$courseId][$settingName])) {
2038
        return $courseSettingInfo[$courseId][$settingName];
2039
    }
2040
2041
    return -1;
2042
}
2043
2044
function api_get_course_plugin_setting($plugin, $settingName, $courseInfo = [])
2045
{
2046
    $value = api_get_course_setting($settingName, $courseInfo, true);
2047
2048
    if (-1 === $value) {
2049
        // Check global settings
2050
        $value = api_get_plugin_setting($plugin, $settingName);
2051
        if ($value === 'true') {
2052
            return 1;
2053
        }
2054
        if ($value === 'false') {
2055
            return 0;
2056
        }
2057
        if (null === $value) {
2058
            return -1;
2059
        }
2060
    }
2061
2062
    return $value;
2063
}
2064
2065
/**
2066
 * Gets an anonymous user ID.
2067
 *
2068
 * For some tools that need tracking, like the learnpath tool, it is necessary
2069
 * to have a usable user-id to enable some kind of tracking, even if not
2070
 * perfect. An anonymous ID is taken from the users table by looking for a
2071
 * status of "6" (anonymous).
2072
 *
2073
 * @return int User ID of the anonymous user, or O if no anonymous user found
2074
 */
2075
function api_get_anonymous_id()
2076
{
2077
    // Find if another anon is connected now
2078
    $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
2079
    $tableU = Database::get_main_table(TABLE_MAIN_USER);
2080
    $ip = Database::escape_string(api_get_real_ip());
2081
    $max = (int) api_get_configuration_value('max_anonymous_users');
2082
    if ($max >= 2) {
2083
        $sql = "SELECT * FROM $table as TEL
2084
                JOIN $tableU as U
2085
                ON U.user_id = TEL.login_user_id
2086
                WHERE TEL.user_ip = '$ip'
2087
                    AND U.status = ".ANONYMOUS."
2088
                    AND U.user_id != 2 ";
2089
2090
        $result = Database::query($sql);
2091
        if (empty(Database::num_rows($result))) {
2092
            $login = uniqid('anon_');
2093
            $anonList = UserManager::get_user_list(['status' => ANONYMOUS], ['registration_date ASC']);
2094
            if (count($anonList) >= $max) {
2095
                foreach ($anonList as $userToDelete) {
2096
                    UserManager::delete_user($userToDelete['user_id']);
2097
                    break;
2098
                }
2099
            }
2100
2101
            return UserManager::create_user(
0 ignored issues
show
Bug Best Practice introduced by
The expression return UserManager::crea...lhost', $login, $login) could also return false which is incompatible with the documented return type integer. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
2102
                $login,
2103
                'anon',
2104
                ANONYMOUS,
2105
                ' anonymous@localhost',
2106
                $login,
2107
                $login
2108
            );
2109
        } else {
2110
            $row = Database::fetch_array($result, 'ASSOC');
2111
2112
            return $row['user_id'];
2113
        }
2114
    }
2115
2116
    $table = Database::get_main_table(TABLE_MAIN_USER);
2117
    $sql = "SELECT user_id
2118
            FROM $table
2119
            WHERE status = ".ANONYMOUS." ";
2120
    $res = Database::query($sql);
2121
    if (Database::num_rows($res) > 0) {
2122
        $row = Database::fetch_array($res, 'ASSOC');
2123
2124
        return $row['user_id'];
2125
    }
2126
2127
    // No anonymous user was found.
2128
    return 0;
2129
}
2130
2131
/**
2132
 * @param int    $courseId
2133
 * @param int    $sessionId
2134
 * @param int    $groupId
2135
 *
2136
 * @return string
2137
 */
2138
function api_get_cidreq_params($courseId, $sessionId = 0, $groupId = 0)
2139
{
2140
    $courseId = !empty($courseId) ? (int) $courseId :0;
2141
    $sessionId = !empty($sessionId) ? (int) $sessionId : 0;
2142
    $groupId = !empty($groupId) ? (int) $groupId : 0;
2143
2144
    $url = 'cid='.$courseId;
2145
    $url .= '&sid='.$sessionId;
2146
    $url .= '&gid='.$groupId;
2147
2148
    return $url;
2149
}
2150
2151
/**
2152
 * Returns the current course url part including session, group, and gradebook params.
2153
 *
2154
 * @param bool   $addSessionId
2155
 * @param bool   $addGroupId
2156
 * @param string $origin
2157
 *
2158
 * @return string Course & session references to add to a URL
2159
 */
2160
function api_get_cidreq($addSessionId = true, $addGroupId = true, $origin = '')
2161
{
2162
    $courseId = api_get_course_int_id();
2163
    $url = empty($courseId) ? '' : 'cid='.$courseId;
2164
    $origin = empty($origin) ? api_get_origin() : Security::remove_XSS($origin);
2165
2166
    if ($addSessionId) {
2167
        if (!empty($url)) {
2168
            $url .= 0 == api_get_session_id() ? '&sid=0' : '&sid='.api_get_session_id();
2169
        }
2170
    }
2171
2172
    if ($addGroupId) {
2173
        if (!empty($url)) {
2174
            $url .= 0 == api_get_group_id() ? '&gid=0' : '&gid='.api_get_group_id();
2175
        }
2176
    }
2177
2178
    if (!empty($url)) {
2179
        $url .= '&gradebook='.(int) api_is_in_gradebook();
2180
        $url .= '&origin='.$origin;
2181
    }
2182
2183
    return $url;
2184
}
2185
2186
/**
2187
 * Get if we visited a gradebook page.
2188
 *
2189
 * @return bool
2190
 */
2191
function api_is_in_gradebook()
2192
{
2193
    return Session::read('in_gradebook', false);
2194
}
2195
2196
/**
2197
 * Set that we are in a page inside a gradebook.
2198
 */
2199
function api_set_in_gradebook()
2200
{
2201
    Session::write('in_gradebook', true);
2202
}
2203
2204
/**
2205
 * Remove gradebook session.
2206
 */
2207
function api_remove_in_gradebook()
2208
{
2209
    Session::erase('in_gradebook');
2210
}
2211
2212
/**
2213
 * Returns the current course info array see api_format_course_array()
2214
 * If the course_code is given, the returned array gives info about that
2215
 * particular course, if none given it gets the course info from the session.
2216
 *
2217
 * @param string $course_code
2218
 *
2219
 * @return array
2220
 */
2221
function api_get_course_info($course_code = null)
2222
{
2223
    if (!empty($course_code)) {
2224
        $course = Container::getCourseRepository()->findOneByCode($course_code);
2225
2226
        return api_format_course_array($course);
2227
    }
2228
2229
    /*$course_code = Database::escape_string($course_code);
2230
    $courseId = api_get_course_int_id($course_code);
2231
    if (empty($courseId)) {
2232
        return [];
2233
    }
2234
2235
    $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
2236
    $course_cat_table = Database::get_main_table(TABLE_MAIN_CATEGORY);
2237
    $sql = "SELECT
2238
                course.*,
2239
                course_category.code faCode,
2240
                course_category.name faName
2241
            FROM $course_table
2242
            LEFT JOIN $course_cat_table
2243
            ON course.category_code = course_category.code
2244
            WHERE course.id = $courseId";
2245
    $result = Database::query($sql);
2246
    $courseInfo = [];
2247
    if (Database::num_rows($result) > 0) {
2248
        $data = Database::fetch_array($result);
2249
        $courseInfo = api_format_course_array($data);
2250
    }
2251
2252
    return $courseInfo;*/
2253
2254
    $course = Session::read('_course');
2255
    if ('-1' == $course) {
2256
        $course = [];
2257
    }
2258
2259
    return $course;
2260
}
2261
2262
/**
2263
 * @param int $courseId
2264
 */
2265
function api_get_course_entity($courseId = 0): ?Course
2266
{
2267
    if (empty($courseId)) {
2268
        $courseId = api_get_course_int_id();
2269
    }
2270
2271
    return Container::getCourseRepository()->find($courseId);
0 ignored issues
show
Bug Best Practice introduced by
The expression return Chamilo\CoreBundl...tory()->find($courseId) returns the type Chamilo\CoreBundle\Entity\ResourceInterface which includes types incompatible with the type-hinted return Chamilo\CoreBundle\Entity\Course|null.
Loading history...
2272
}
2273
2274
/**
2275
 * @param int $id
2276
 */
2277
function api_get_session_entity($id = 0): ?SessionEntity
2278
{
2279
    if (empty($id)) {
2280
        $id = api_get_session_id();
2281
    }
2282
2283
    if (empty($id)) {
2284
        return null;
2285
    }
2286
2287
    return Container::getSessionRepository()->find($id);
2288
}
2289
2290
/**
2291
 * @param int $id
2292
 */
2293
function api_get_group_entity($id = 0): ?CGroup
2294
{
2295
    if (empty($id)) {
2296
        $id = api_get_group_id();
2297
    }
2298
2299
    return Container::getGroupRepository()->find($id);
0 ignored issues
show
Bug Best Practice introduced by
The expression return Chamilo\CoreBundl...Repository()->find($id) returns the type Chamilo\CoreBundle\Entity\ResourceInterface which includes types incompatible with the type-hinted return Chamilo\CourseBundle\Entity\CGroup|null.
Loading history...
2300
}
2301
2302
/**
2303
 * @param int $id
2304
 *
2305
 * @return AccessUrl
2306
 */
2307
function api_get_url_entity($id = 0)
2308
{
2309
    if (empty($id)) {
2310
        $id = api_get_current_access_url_id();
2311
    }
2312
2313
    return Container::getAccessUrlRepository()->find($id);
2314
}
2315
2316
/**
2317
 * Returns the current course info array.
2318
2319
 * Now if the course_code is given, the returned array gives info about that
2320
 * particular course, not specially the current one.
2321
 *
2322
 * @param int $id Numeric ID of the course
2323
 *
2324
 * @return array The course info as an array formatted by api_format_course_array, including category.name
2325
 */
2326
function api_get_course_info_by_id($id = 0)
2327
{
2328
    $id = (int) $id;
2329
    if (empty($id)) {
2330
        $course = Session::read('_course', []);
2331
2332
        return $course;
2333
    }
2334
2335
    $course = Container::getCourseRepository()->find($id);
2336
    if (empty($course)) {
2337
        return [];
2338
    }
2339
2340
    return api_format_course_array($course);
2341
}
2342
2343
/**
2344
 * Reformat the course array (output by api_get_course_info()) in order, mostly,
2345
 * to switch from 'code' to 'id' in the array.
2346
 *
2347
 * @return array
2348
 *
2349
 * @todo eradicate the false "id"=code field of the $_course array and use the int id
2350
 */
2351
function api_format_course_array(Course $course = null)
2352
{
2353
    if (empty($course)) {
2354
        return [];
2355
    }
2356
2357
    $category = $course->getCategory();
2358
2359
    $courseData = [];
2360
    $courseData['categoryCode'] = '';
2361
    $courseData['categoryName'] = '';
2362
    $courseData['category_id'] = 0;
2363
    if ($category) {
0 ignored issues
show
introduced by
$category is of type Chamilo\CoreBundle\Entity\CourseCategory, thus it always evaluated to true.
Loading history...
2364
        $courseData['categoryCode'] = $category->getCode();
2365
        $courseData['categoryName'] = $category->getName();
2366
        $courseData['category_id'] = $category->getId();
2367
    }
2368
2369
    $courseData['id'] = $courseData['real_id'] = $course->getId();
2370
2371
    // Added
2372
    $courseData['code'] = $courseData['sysCode'] = $course->getCode();
2373
    $courseData['name'] = $courseData['title'] = $course->getTitle();
2374
    $courseData['official_code'] = $courseData['visual_code'] = $course->getVisualCode();
2375
    $courseData['path'] = $courseData['directory'] = $course->getDirectory(); // Use as key in path.
2376
    $courseData['creation_date'] = $course->getCreationDate()->format('Y-m-d H:i:s');
2377
    $courseData['titular'] = $course->getTutorName();
2378
    $courseData['language'] = $courseData['course_language'] = $course->getCourseLanguage();
2379
    $courseData['extLink']['url'] = $courseData['department_url'] = $course->getDepartmentUrl();
2380
    $courseData['extLink']['name'] = $courseData['department_name'] = $course->getDepartmentName();
2381
2382
    $courseData['visibility'] = $course->getVisibility();
2383
    $courseData['subscribe_allowed'] = $courseData['subscribe'] = $course->getSubscribe();
2384
    $courseData['unsubscribe'] = $course->getUnsubscribe();
2385
    $courseData['activate_legal'] = $course->getActivateLegal();
2386
    $courseData['legal'] = $course->getLegal();
2387
    $courseData['show_score'] = $course->getShowScore(); //used in the work tool
2388
2389
    $coursePath = api_get_path(WEB_COURSE_PATH);
2390
    $webCourseHome = $coursePath.$courseData['real_id'].'/home';
2391
2392
    // Course password
2393
    $courseData['registration_code'] = $course->getRegistrationCode();
2394
    $courseData['disk_quota'] = $course->getDiskQuota();
2395
    $courseData['course_public_url'] = $webCourseHome;
2396
    $courseData['about_url'] = $coursePath.$courseData['real_id'].'/about';
2397
    $courseData['add_teachers_to_sessions_courses'] = $course->isAddTeachersToSessionsCourses();
2398
    $courseData['entity'] = $course;
2399
2400
    $image = Display::return_icon(
2401
        'course.png',
2402
        null,
2403
        null,
2404
        ICON_SIZE_BIG,
2405
        null,
2406
        true,
2407
        false
2408
    );
2409
2410
    $illustration = Container::getIllustrationRepository()->getIllustrationUrl($course);
2411
    if (!empty($illustration)) {
2412
        $image = $illustration;
2413
    }
2414
2415
    $courseData['course_image'] = $image.'?filter=course_picture_small';
2416
2417
    // Course large image
2418
    /*$courseData['course_image_large_source'] = '';
2419
    if (file_exists($courseSys.'/course-pic.png')) {
2420
        $url_image = $webCourseHome.'/course-pic.png';
2421
        $courseData['course_image_large_source'] = $courseSys.'/course-pic.png';
2422
    } else {
2423
        $url_image = Display::return_icon(
2424
            'session_default.png',
2425
            null,
2426
            null,
2427
            null,
2428
            null,
2429
            true,
2430
            true
2431
        );
2432
    }*/
2433
2434
    $courseData['course_image_large'] = $image.'?filter=course_picture_medium';
2435
2436
    return $courseData;
2437
}
2438
2439
/**
2440
 * Returns a difficult to guess password.
2441
 *
2442
 * @param int $length the length of the password
2443
 *
2444
 * @return string the generated password
2445
 */
2446
function api_generate_password($length = 8)
2447
{
2448
    if ($length < 2) {
2449
        $length = 2;
2450
    }
2451
2452
    $charactersLowerCase = 'abcdefghijkmnopqrstuvwxyz';
2453
    $charactersUpperCase = 'ABCDEFGHJKLMNPQRSTUVWXYZ';
2454
    $minNumbers = 2;
2455
    $length = $length - $minNumbers;
2456
    $minLowerCase = round($length / 2);
2457
    $minUpperCase = $length - $minLowerCase;
2458
2459
    $password = '';
2460
    $passwordRequirements = api_get_configuration_value('password_requirements');
2461
2462
    $factory = new RandomLib\Factory();
2463
    $generator = $factory->getGenerator(new SecurityLib\Strength(SecurityLib\Strength::MEDIUM));
2464
2465
    if (!empty($passwordRequirements)) {
2466
        $length = $passwordRequirements['min']['length'];
2467
        $minNumbers = $passwordRequirements['min']['numeric'];
2468
        $minLowerCase = $passwordRequirements['min']['lowercase'];
2469
        $minUpperCase = $passwordRequirements['min']['uppercase'];
2470
2471
        $rest = $length - $minNumbers - $minLowerCase - $minUpperCase;
2472
        // Add the rest to fill the length requirement
2473
        if ($rest > 0) {
2474
            $password .= $generator->generateString($rest, $charactersLowerCase.$charactersUpperCase);
2475
        }
2476
    }
2477
2478
    // Min digits default 2
2479
    for ($i = 0; $i < $minNumbers; $i++) {
2480
        $password .= $generator->generateInt(2, 9);
2481
    }
2482
2483
    // Min lowercase
2484
    $password .= $generator->generateString($minLowerCase, $charactersLowerCase);
2485
2486
    // Min uppercase
2487
    $password .= $generator->generateString($minUpperCase, $charactersUpperCase);
2488
    $password = str_shuffle($password);
2489
2490
    return $password;
2491
}
2492
2493
/**
2494
 * Checks a password to see wether it is OK to use.
2495
 *
2496
 * @param string $password
2497
 *
2498
 * @return bool if the password is acceptable, false otherwise
2499
 *              Notes about what a password "OK to use" is:
2500
 *              1. The password should be at least 5 characters long.
2501
 *              2. Only English letters (uppercase or lowercase, it doesn't matter) and digits are allowed.
2502
 *              3. The password should contain at least 3 letters.
2503
 *              4. It should contain at least 2 digits.
2504
 *              Settings will change if the configuration value is set: password_requirements
2505
 */
2506
function api_check_password($password)
2507
{
2508
    $passwordRequirements = Security::getPasswordRequirements();
2509
2510
    $minLength = $passwordRequirements['min']['length'];
2511
    $minNumbers = $passwordRequirements['min']['numeric'];
2512
    // Optional
2513
    $minLowerCase = $passwordRequirements['min']['lowercase'];
2514
    $minUpperCase = $passwordRequirements['min']['uppercase'];
2515
2516
    $minLetters = $minLowerCase + $minUpperCase;
2517
    $passwordLength = api_strlen($password);
2518
2519
    $conditions = [
2520
        'min_length' => $passwordLength >= $minLength,
2521
    ];
2522
2523
    $digits = 0;
2524
    $lowerCase = 0;
2525
    $upperCase = 0;
2526
2527
    for ($i = 0; $i < $passwordLength; $i++) {
2528
        $currentCharacterCode = api_ord(api_substr($password, $i, 1));
2529
        if ($currentCharacterCode >= 65 && $currentCharacterCode <= 90) {
2530
            $upperCase++;
2531
        }
2532
2533
        if ($currentCharacterCode >= 97 && $currentCharacterCode <= 122) {
2534
            $lowerCase++;
2535
        }
2536
        if ($currentCharacterCode >= 48 && $currentCharacterCode <= 57) {
2537
            $digits++;
2538
        }
2539
    }
2540
2541
    // Min number of digits
2542
    $conditions['min_numeric'] = $digits >= $minNumbers;
2543
2544
    if (!empty($minUpperCase)) {
2545
        // Uppercase
2546
        $conditions['min_uppercase'] = $upperCase >= $minUpperCase;
2547
    }
2548
2549
    if (!empty($minLowerCase)) {
2550
        // Lowercase
2551
        $conditions['min_lowercase'] = $upperCase >= $minLowerCase;
2552
    }
2553
2554
    // Min letters
2555
    $letters = $upperCase + $lowerCase;
2556
    $conditions['min_letters'] = $letters >= $minLetters;
2557
2558
    $isPasswordOk = true;
2559
    foreach ($conditions as $condition) {
2560
        if (false === $condition) {
2561
            $isPasswordOk = false;
2562
            break;
2563
        }
2564
    }
2565
2566
    if (false === $isPasswordOk) {
2567
        $output = get_lang('The new password does not match the minimum security requirements').'<br />';
2568
        $output .= Security::getPasswordRequirementsToString($conditions);
2569
2570
        Display::addFlash(Display::return_message($output, 'warning', false));
2571
    }
2572
2573
    return $isPasswordOk;
2574
}
2575
2576
/**
2577
 * Returns the status string corresponding to the status code.
2578
 *
2579
 * @author Noel Dieschburg
2580
 *
2581
 * @param the int status code
2582
 *
2583
 * @return string
2584
 */
2585
function get_status_from_code($status_code)
2586
{
2587
    switch ($status_code) {
2588
        case STUDENT:
2589
            return get_lang('Student', '');
2590
        case COURSEMANAGER:
2591
            return get_lang('Teacher', '');
2592
        case SESSIONADMIN:
2593
            return get_lang('SessionsAdmin', '');
2594
        case DRH:
2595
            return get_lang('Drh', '');
2596
    }
2597
}
2598
2599
/**
2600
 * Gets the current Chamilo (not PHP/cookie) session ID.
2601
 *
2602
 * @return int O if no active session, the session ID otherwise
2603
 */
2604
function api_get_session_id()
2605
{
2606
    return (int) Session::read('sid', 0);
2607
}
2608
2609
/**
2610
 * Gets the current Chamilo (not social network) group ID.
2611
 *
2612
 * @return int O if no active session, the session ID otherwise
2613
 */
2614
function api_get_group_id()
2615
{
2616
    return Session::read('gid', 0);
2617
}
2618
2619
/**
2620
 * Gets the current or given session name.
2621
 *
2622
 * @param   int     Session ID (optional)
2623
 *
2624
 * @return string The session name, or null if not found
2625
 */
2626
function api_get_session_name($session_id = 0)
2627
{
2628
    if (empty($session_id)) {
2629
        $session_id = api_get_session_id();
2630
        if (empty($session_id)) {
2631
            return null;
2632
        }
2633
    }
2634
    $t = Database::get_main_table(TABLE_MAIN_SESSION);
2635
    $s = "SELECT name FROM $t WHERE id = ".(int) $session_id;
2636
    $r = Database::query($s);
2637
    $c = Database::num_rows($r);
2638
    if ($c > 0) {
2639
        //technically, there can be only one, but anyway we take the first
2640
        $rec = Database::fetch_array($r);
2641
2642
        return $rec['name'];
2643
    }
2644
2645
    return null;
2646
}
2647
2648
/**
2649
 * Gets the session info by id.
2650
 *
2651
 * @param int $id Session ID
2652
 *
2653
 * @return array information of the session
2654
 */
2655
function api_get_session_info($id)
2656
{
2657
    return SessionManager::fetch($id);
2658
}
2659
2660
/**
2661
 * Gets the session visibility by session id.
2662
 *
2663
 * @param int  $session_id
2664
 * @param int  $courseId
2665
 * @param bool $ignore_visibility_for_admins
2666
 *
2667
 * @return int
2668
 *             0 = session still available,
2669
 *             SESSION_VISIBLE_READ_ONLY = 1,
2670
 *             SESSION_VISIBLE = 2,
2671
 *             SESSION_INVISIBLE = 3
2672
 */
2673
function api_get_session_visibility(
2674
    $session_id,
2675
    $courseId = null,
2676
    $ignore_visibility_for_admins = true
2677
) {
2678
    if (api_is_platform_admin()) {
2679
        if ($ignore_visibility_for_admins) {
2680
            return SESSION_AVAILABLE;
2681
        }
2682
    }
2683
2684
    $now = time();
2685
    if (empty($session_id)) {
2686
        return 0; // Means that the session is still available.
2687
    }
2688
2689
    $session_id = (int) $session_id;
2690
    $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
2691
2692
    $result = Database::query("SELECT * FROM $tbl_session WHERE id = $session_id");
2693
2694
    if (Database::num_rows($result) <= 0) {
2695
        return SESSION_INVISIBLE;
2696
    }
2697
2698
    $row = Database::fetch_array($result, 'ASSOC');
2699
    $visibility = $row['visibility'];
2700
2701
    // I don't care the session visibility.
2702
    if (empty($row['access_start_date']) && empty($row['access_end_date'])) {
2703
        // Session duration per student.
2704
        if (isset($row['duration']) && !empty($row['duration'])) {
2705
            $duration = $row['duration'] * 24 * 60 * 60;
2706
            $courseAccess = CourseManager::getFirstCourseAccessPerSessionAndUser($session_id, api_get_user_id());
2707
2708
            // If there is a session duration but there is no previous
2709
            // access by the user, then the session is still available
2710
            if (0 == count($courseAccess)) {
2711
                return SESSION_AVAILABLE;
2712
            }
2713
2714
            $currentTime = time();
2715
            $firstAccess = isset($courseAccess['login_course_date'])
2716
                ? api_strtotime($courseAccess['login_course_date'], 'UTC')
2717
                : 0;
2718
            $userDurationData = SessionManager::getUserSession(
2719
                api_get_user_id(),
2720
                $session_id
2721
            );
2722
            $userDuration = isset($userDurationData['duration'])
2723
                ? (intval($userDurationData['duration']) * 24 * 60 * 60)
2724
                : 0;
2725
2726
            $totalDuration = $firstAccess + $duration + $userDuration;
2727
2728
            return $totalDuration > $currentTime ? SESSION_AVAILABLE : SESSION_VISIBLE_READ_ONLY;
2729
        }
2730
2731
        return SESSION_AVAILABLE;
2732
    }
2733
2734
    // If start date was set.
2735
    if (!empty($row['access_start_date'])) {
2736
        $visibility = $now > api_strtotime($row['access_start_date'], 'UTC') ? SESSION_AVAILABLE : SESSION_INVISIBLE;
2737
    }
2738
2739
    // If the end date was set.
2740
    if (!empty($row['access_end_date'])) {
2741
        // Only if date_start said that it was ok
2742
        if (SESSION_AVAILABLE === $visibility) {
2743
            $visibility = $now < api_strtotime($row['access_end_date'], 'UTC')
2744
                ? SESSION_AVAILABLE // Date still available
2745
                : $row['visibility']; // Session ends
2746
        }
2747
    }
2748
2749
    // If I'm a coach the visibility can change in my favor depending in the coach dates.
2750
    $isCoach = api_is_coach($session_id, $courseId);
2751
2752
    if ($isCoach) {
2753
        // Test start date.
2754
        if (!empty($row['coach_access_start_date'])) {
2755
            $start = api_strtotime($row['coach_access_start_date'], 'UTC');
2756
            $visibility = $start < $now ? SESSION_AVAILABLE : SESSION_INVISIBLE;
2757
        }
2758
2759
        // Test end date.
2760
        if (!empty($row['coach_access_end_date'])) {
2761
            if (SESSION_AVAILABLE === $visibility) {
2762
                $endDateCoach = api_strtotime($row['coach_access_end_date'], 'UTC');
2763
                $visibility = $endDateCoach >= $now ? SESSION_AVAILABLE : $row['visibility'];
2764
            }
2765
        }
2766
    }
2767
2768
    return $visibility;
2769
}
2770
2771
/**
2772
 * This function returns a (star) session icon if the session is not null and
2773
 * the user is not a student.
2774
 *
2775
 * @param int $sessionId
2776
 * @param int $statusId  User status id - if 5 (student), will return empty
2777
 *
2778
 * @return string Session icon
2779
 */
2780
function api_get_session_image($sessionId, $statusId)
2781
{
2782
    $sessionId = (int) $sessionId;
2783
    $image = '';
2784
    if (STUDENT != $statusId) {
2785
        // Check whether is not a student
2786
        if ($sessionId > 0) {
2787
            $image = '&nbsp;&nbsp;'.Display::return_icon(
2788
                'star.png',
2789
                get_lang('Session-specific resource'),
2790
                ['align' => 'absmiddle'],
2791
                ICON_SIZE_SMALL
2792
            );
2793
        }
2794
    }
2795
2796
    return $image;
2797
}
2798
2799
/**
2800
 * This function add an additional condition according to the session of the course.
2801
 *
2802
 * @param int    $session_id        session id
2803
 * @param bool   $and               optional, true if more than one condition false if the only condition in the query
2804
 * @param bool   $with_base_content optional, true to accept content with session=0 as well,
2805
 *                                  false for strict session condition
2806
 * @param string $session_field
2807
 *
2808
 * @return string condition of the session
2809
 */
2810
function api_get_session_condition(
2811
    $session_id,
2812
    $and = true,
2813
    $with_base_content = false,
2814
    $session_field = 'session_id'
2815
) {
2816
    $session_id = (int) $session_id;
2817
2818
    if (empty($session_field)) {
2819
        $session_field = 'session_id';
2820
    }
2821
    // Condition to show resources by session
2822
    $condition_add = $and ? ' AND ' : ' WHERE ';
2823
2824
    if ($with_base_content) {
2825
        $condition_session = $condition_add." ( $session_field = $session_id OR $session_field = 0 OR $session_field IS NULL) ";
2826
    } else {
2827
        if (empty($session_id)) {
2828
            $condition_session = $condition_add." ($session_field = $session_id OR $session_field IS NULL)";
2829
        } else {
2830
            $condition_session = $condition_add." $session_field = $session_id ";
2831
        }
2832
    }
2833
2834
    return $condition_session;
2835
}
2836
2837
/**
2838
 * Returns the value of a setting from the web-adjustable admin config settings.
2839
 *
2840
 * WARNING true/false are stored as string, so when comparing you need to check e.g.
2841
 * if (api_get_setting('show_navigation_menu') == 'true') //CORRECT
2842
 * instead of
2843
 * if (api_get_setting('show_navigation_menu') == true) //INCORRECT
2844
 *
2845
 * @param string $variable The variable name
2846
 *
2847
 * @return string
2848
 */
2849
function api_get_setting($variable)
2850
{
2851
    $settingsManager = Container::getSettingsManager();
2852
    if (empty($settingsManager)) {
2853
        return '';
2854
    }
2855
    $variable = trim($variable);
2856
2857
    switch ($variable) {
2858
        /*case 'header_extra_content':
2859
            $filename = api_get_path(SYS_PATH).api_get_home_path().'header_extra_content.txt';
2860
            if (file_exists($filename)) {
2861
                $value = file_get_contents($filename);
2862
2863
                return $value;
2864
            } else {
2865
                return '';
2866
            }
2867
            break;
2868
        case 'footer_extra_content':
2869
            $filename = api_get_path(SYS_PATH).api_get_home_path().'footer_extra_content.txt';
2870
            if (file_exists($filename)) {
2871
                $value = file_get_contents($filename);
2872
2873
                return $value;
2874
            } else {
2875
                return '';
2876
            }
2877
            break;*/
2878
        case 'server_type':
2879
            $test = ['dev', 'test'];
2880
            $environment = Container::getEnvironment();
2881
            if (in_array($environment, $test)) {
2882
                return 'test';
2883
            }
2884
2885
            return 'prod';
2886
        case 'stylesheets':
2887
            $variable = 'platform.theme';
2888
        // deprecated settings
2889
        // no break
2890
        case 'openid_authentication':
2891
        case 'service_ppt2lp':
2892
        case 'formLogin_hide_unhide_label':
2893
            return false;
2894
            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...
2895
        case 'tool_visible_by_default_at_creation':
2896
            $values = $settingsManager->getSetting($variable);
2897
            $newResult = [];
2898
            foreach ($values as $parameter) {
2899
                $newResult[$parameter] = 'true';
2900
            }
2901
2902
            return $newResult;
2903
            break;
2904
        default:
2905
            return $settingsManager->getSetting($variable);
2906
            break;
2907
    }
2908
}
2909
2910
/**
2911
 * @param string $variable
2912
 * @param string $option
2913
 *
2914
 * @return bool
2915
 */
2916
function api_get_setting_in_list($variable, $option)
2917
{
2918
    $value = api_get_setting($variable);
2919
2920
    return in_array($option, $value);
2921
}
2922
2923
/**
2924
 * @param string $plugin
2925
 * @param string $variable
2926
 *
2927
 * @return string
2928
 */
2929
function api_get_plugin_setting($plugin, $variable)
2930
{
2931
    $variableName = $plugin.'_'.$variable;
2932
    //$result = api_get_setting($variableName);
2933
    $params = [
2934
        'category = ? AND subkey = ? AND variable = ?' => [
2935
            'Plugins',
2936
            $plugin,
2937
            $variableName,
2938
        ],
2939
    ];
2940
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2941
    $result = Database::select(
2942
        'selected_value',
2943
        $table,
2944
        ['where' => $params],
2945
        'one'
2946
    );
2947
    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...
2948
        $value = $result['selected_value'];
2949
        $serializedValue = @unserialize($result['selected_value'], []);
2950
        if (false !== $serializedValue) {
2951
            $value = $serializedValue;
2952
        }
2953
2954
        return $value;
2955
    }
2956
2957
    return null;
2958
    /// Old code
2959
2960
    $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...
2961
    $result = api_get_setting($variableName);
2962
2963
    if (isset($result[$plugin])) {
2964
        $value = $result[$plugin];
2965
2966
        $unserialized = UnserializeApi::unserialize('not_allowed_classes', $value, true);
2967
2968
        if (false !== $unserialized) {
2969
            $value = $unserialized;
2970
        }
2971
2972
        return $value;
2973
    }
2974
2975
    return null;
2976
}
2977
2978
/**
2979
 * Returns the value of a setting from the web-adjustable admin config settings.
2980
 */
2981
function api_get_settings_params($params)
2982
{
2983
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2984
    $result = Database::select('*', $table, ['where' => $params]);
2985
2986
    return $result;
2987
}
2988
2989
/**
2990
 * @param array $params example: [id = ? => '1']
2991
 *
2992
 * @return array
2993
 */
2994
function api_get_settings_params_simple($params)
2995
{
2996
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2997
    $result = Database::select('*', $table, ['where' => $params], 'one');
2998
2999
    return $result;
3000
}
3001
3002
/**
3003
 * Returns the value of a setting from the web-adjustable admin config settings.
3004
 */
3005
function api_delete_settings_params($params)
3006
{
3007
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
3008
    $result = Database::delete($table, $params);
3009
3010
    return $result;
3011
}
3012
3013
/**
3014
 * Returns an escaped version of $_SERVER['PHP_SELF'] to avoid XSS injection.
3015
 *
3016
 * @return string Escaped version of $_SERVER['PHP_SELF']
3017
 */
3018
function api_get_self()
3019
{
3020
    return htmlentities($_SERVER['PHP_SELF']);
3021
}
3022
3023
/* USER PERMISSIONS */
3024
3025
/**
3026
 * Checks whether current user is a platform administrator.
3027
 *
3028
 * @param bool $allowSessionAdmins Whether session admins should be considered admins or not
3029
 * @param bool $allowDrh           Whether HR directors should be considered admins or not
3030
 *
3031
 * @return bool true if the user has platform admin rights,
3032
 *              false otherwise
3033
 *
3034
 * @see usermanager::is_admin(user_id) for a user-id specific function
3035
 */
3036
function api_is_platform_admin($allowSessionAdmins = false, $allowDrh = false)
3037
{
3038
    $currentUser = api_get_current_user();
3039
3040
    if (null === $currentUser) {
3041
        return false;
3042
    }
3043
3044
    $isAdmin = Session::read('is_platformAdmin');
3045
    if ($isAdmin) {
3046
        return true;
3047
    }
3048
    $user = api_get_user_info();
3049
3050
    return
3051
        isset($user['status']) &&
3052
        (
3053
            ($allowSessionAdmins && SESSIONADMIN == $user['status']) ||
3054
            ($allowDrh && DRH == $user['status'])
3055
        );
3056
}
3057
3058
/**
3059
 * Checks whether the user given as user id is in the admin table.
3060
 *
3061
 * @param int $user_id If none provided, will use current user
3062
 * @param int $url     URL ID. If provided, also check if the user is active on given URL
3063
 *
3064
 * @return bool True if the user is admin, false otherwise
3065
 */
3066
function api_is_platform_admin_by_id($user_id = null, $url = null)
3067
{
3068
    $user_id = (int) $user_id;
3069
    if (empty($user_id)) {
3070
        $user_id = api_get_user_id();
3071
    }
3072
    $admin_table = Database::get_main_table(TABLE_MAIN_ADMIN);
3073
    $sql = "SELECT * FROM $admin_table WHERE user_id = $user_id";
3074
    $res = Database::query($sql);
3075
    $is_admin = 1 === Database::num_rows($res);
3076
    if (!$is_admin || !isset($url)) {
3077
        return $is_admin;
3078
    }
3079
    // We get here only if $url is set
3080
    $url = (int) $url;
3081
    $url_user_table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
3082
    $sql = "SELECT * FROM $url_user_table
3083
            WHERE access_url_id = $url AND user_id = $user_id";
3084
    $res = Database::query($sql);
3085
    $result = 1 === Database::num_rows($res);
3086
3087
    return $result;
3088
}
3089
3090
/**
3091
 * Returns the user's numeric status ID from the users table.
3092
 *
3093
 * @param int $user_id If none provided, will use current user
3094
 *
3095
 * @return int User's status (1 for teacher, 5 for student, etc)
3096
 */
3097
function api_get_user_status($user_id = null)
3098
{
3099
    $user_id = (int) $user_id;
3100
    if (empty($user_id)) {
3101
        $user_id = api_get_user_id();
3102
    }
3103
    $table = Database::get_main_table(TABLE_MAIN_USER);
3104
    $sql = "SELECT status FROM $table WHERE user_id = $user_id ";
3105
    $result = Database::query($sql);
3106
    $status = null;
3107
    if (Database::num_rows($result)) {
3108
        $row = Database::fetch_array($result);
3109
        $status = $row['status'];
3110
    }
3111
3112
    return $status;
3113
}
3114
3115
/**
3116
 * Checks whether current user is allowed to create courses.
3117
 *
3118
 * @return bool true if the user has course creation rights,
3119
 *              false otherwise
3120
 */
3121
function api_is_allowed_to_create_course()
3122
{
3123
    if (api_is_platform_admin()) {
3124
        return true;
3125
    }
3126
3127
    // Teachers can only create courses
3128
    if (api_is_teacher()) {
3129
        if ('true' === api_get_setting('allow_users_to_create_courses')) {
3130
            return true;
3131
        } else {
3132
            return false;
3133
        }
3134
    }
3135
3136
    return Session::read('is_allowedCreateCourse');
3137
}
3138
3139
/**
3140
 * Checks whether the current user is a course administrator.
3141
 *
3142
 * @return bool True if current user is a course administrator
3143
 */
3144
function api_is_course_admin()
3145
{
3146
    if (api_is_platform_admin()) {
3147
        return true;
3148
    }
3149
3150
    $user = api_get_current_user();
3151
    if ($user) {
3152
        if (
3153
            $user->hasRole('ROLE_CURRENT_SESSION_COURSE_TEACHER') ||
3154
            $user->hasRole('ROLE_CURRENT_COURSE_TEACHER')
3155
        ) {
3156
            return true;
3157
        }
3158
    }
3159
3160
    return false;
3161
    //return Session::read('is_courseAdmin');
3162
}
3163
3164
/**
3165
 * Checks whether the current user is a course coach
3166
 * Based on the presence of user in session.id_coach (session general coach).
3167
 *
3168
 * @return bool True if current user is a course coach
3169
 */
3170
function api_is_session_general_coach()
3171
{
3172
    return Session::read('is_session_general_coach');
3173
}
3174
3175
/**
3176
 * Checks whether the current user is a course tutor
3177
 * Based on the presence of user in session_rel_course_rel_user.user_id with status = 2.
3178
 *
3179
 * @return bool True if current user is a course tutor
3180
 */
3181
function api_is_course_tutor()
3182
{
3183
    return Session::read('is_courseTutor');
3184
}
3185
3186
/**
3187
 * @param int $user_id
3188
 * @param int $courseId
3189
 * @param int $session_id
3190
 *
3191
 * @return bool
3192
 */
3193
function api_is_course_session_coach($user_id, $courseId, $session_id)
3194
{
3195
    $session_table = Database::get_main_table(TABLE_MAIN_SESSION);
3196
    $session_rel_course_rel_user_table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3197
3198
    $user_id = (int) $user_id;
3199
    $session_id = (int) $session_id;
3200
    $courseId = (int) $courseId;
3201
3202
    $sql = "SELECT DISTINCT session.id
3203
            FROM $session_table
3204
            INNER JOIN $session_rel_course_rel_user_table session_rc_ru
3205
            ON session.id = session_rc_ru.session_id
3206
            WHERE
3207
                session_rc_ru.user_id = '".$user_id."'  AND
3208
                session_rc_ru.c_id = '$courseId' AND
3209
                session_rc_ru.status = 2 AND
3210
                session_rc_ru.session_id = '$session_id'";
3211
    $result = Database::query($sql);
3212
3213
    return Database::num_rows($result) > 0;
3214
}
3215
3216
/**
3217
 * Checks whether the current user is a course or session coach.
3218
 *
3219
 * @param int $session_id
3220
 * @param int $courseId
3221
 * @param bool  Check whether we are in student view and, if we are, return false
3222
 *
3223
 * @return bool True if current user is a course or session coach
3224
 */
3225
function api_is_coach($session_id = 0, $courseId = null, $check_student_view = true)
3226
{
3227
    $userId = api_get_user_id();
3228
3229
    if (!empty($session_id)) {
3230
        $session_id = (int) $session_id;
3231
    } else {
3232
        $session_id = api_get_session_id();
3233
    }
3234
3235
    // The student preview was on
3236
    if ($check_student_view && api_is_student_view_active()) {
3237
        return false;
3238
    }
3239
3240
    if (!empty($courseId)) {
3241
        $courseId = (int) $courseId;
3242
    } else {
3243
        $courseId = api_get_course_int_id();
3244
    }
3245
3246
    $session_table = Database::get_main_table(TABLE_MAIN_SESSION);
3247
    $session_rel_course_rel_user_table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3248
    $sessionIsCoach = [];
3249
3250
    if (!empty($courseId)) {
3251
        $sql = "SELECT DISTINCT s.id, name, access_start_date, access_end_date
3252
                FROM $session_table s
3253
                INNER JOIN $session_rel_course_rel_user_table session_rc_ru
3254
                ON session_rc_ru.session_id = s.id AND session_rc_ru.user_id = '".$userId."'
3255
                WHERE
3256
                    session_rc_ru.c_id = '$courseId' AND
3257
                    session_rc_ru.status = 2 AND
3258
                    session_rc_ru.session_id = '$session_id'";
3259
        $result = Database::query($sql);
3260
        $sessionIsCoach = Database::store_result($result);
3261
    }
3262
3263
    if (!empty($session_id)) {
3264
        $sql = "SELECT DISTINCT id, name, access_start_date, access_end_date
3265
                FROM $session_table
3266
                WHERE session.id_coach = $userId AND id = $session_id
3267
                ORDER BY access_start_date, access_end_date, name";
3268
        $result = Database::query($sql);
3269
        if (!empty($sessionIsCoach)) {
3270
            $sessionIsCoach = array_merge(
3271
                $sessionIsCoach,
3272
                Database::store_result($result)
3273
            );
3274
        } else {
3275
            $sessionIsCoach = Database::store_result($result);
3276
        }
3277
    }
3278
3279
    return count($sessionIsCoach) > 0;
3280
}
3281
3282
/**
3283
 * Checks whether the current user is a session administrator.
3284
 *
3285
 * @return bool True if current user is a course administrator
3286
 */
3287
function api_is_session_admin()
3288
{
3289
    $user = api_get_user_info();
3290
3291
    return isset($user['status']) && SESSIONADMIN == $user['status'];
3292
}
3293
3294
/**
3295
 * Checks whether the current user is a human resources manager.
3296
 *
3297
 * @return bool True if current user is a human resources manager
3298
 */
3299
function api_is_drh()
3300
{
3301
    $user = api_get_user_info();
3302
3303
    return isset($user['status']) && DRH == $user['status'];
3304
}
3305
3306
/**
3307
 * Checks whether the current user is a student.
3308
 *
3309
 * @return bool True if current user is a human resources manager
3310
 */
3311
function api_is_student()
3312
{
3313
    $user = api_get_user_info();
3314
3315
    return isset($user['status']) && STUDENT == $user['status'];
3316
}
3317
3318
/**
3319
 * Checks whether the current user has the status 'teacher'.
3320
 *
3321
 * @return bool True if current user is a human resources manager
3322
 */
3323
function api_is_teacher()
3324
{
3325
    $user = api_get_user_info();
3326
3327
    return isset($user['status']) && COURSEMANAGER == $user['status'];
3328
}
3329
3330
/**
3331
 * Checks whether the current user is a invited user.
3332
 *
3333
 * @return bool
3334
 */
3335
function api_is_invitee()
3336
{
3337
    $user = api_get_user_info();
3338
3339
    return isset($user['status']) && INVITEE == $user['status'];
3340
}
3341
3342
/**
3343
 * This function checks whether a session is assigned into a category.
3344
 *
3345
 * @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...
3346
 * @param string    - category name
3347
 *
3348
 * @return bool - true if is found, otherwise false
3349
 */
3350
function api_is_session_in_category($session_id, $category_name)
3351
{
3352
    $session_id = (int) $session_id;
3353
    $category_name = Database::escape_string($category_name);
3354
    $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
3355
    $tbl_session_category = Database::get_main_table(TABLE_MAIN_SESSION_CATEGORY);
3356
3357
    $sql = "SELECT 1
3358
            FROM $tbl_session
3359
            WHERE $session_id IN (
3360
                SELECT s.id FROM $tbl_session s, $tbl_session_category sc
3361
                WHERE
3362
                  s.session_category_id = sc.id AND
3363
                  sc.name LIKE '%$category_name'
3364
            )";
3365
    $rs = Database::query($sql);
3366
3367
    if (Database::num_rows($rs) > 0) {
3368
        return true;
3369
    } else {
3370
        return false;
3371
    }
3372
}
3373
3374
/**
3375
 * Displays the title of a tool.
3376
 * Normal use: parameter is a string:
3377
 * api_display_tool_title("My Tool").
3378
 *
3379
 * Optionally, there can be a subtitle below
3380
 * the normal title, and / or a supra title above the normal title.
3381
 *
3382
 * e.g. supra title:
3383
 * group
3384
 * GROUP PROPERTIES
3385
 *
3386
 * e.g. subtitle:
3387
 * AGENDA
3388
 * calender & events tool
3389
 *
3390
 * @author Hugues Peeters <[email protected]>
3391
 *
3392
 * @param mixed $title_element - it could either be a string or an array
3393
 *                             containing 'supraTitle', 'mainTitle',
3394
 *                             'subTitle'
3395
 */
3396
function api_display_tool_title($title_element)
3397
{
3398
    if (is_string($title_element)) {
3399
        $tit = $title_element;
3400
        unset($title_element);
3401
        $title_element = [];
3402
        $title_element['mainTitle'] = $tit;
3403
    }
3404
    echo '<h3>';
3405
    if (!empty($title_element['supraTitle'])) {
3406
        echo '<small>'.$title_element['supraTitle'].'</small><br />';
3407
    }
3408
    if (!empty($title_element['mainTitle'])) {
3409
        echo $title_element['mainTitle'];
3410
    }
3411
    if (!empty($title_element['subTitle'])) {
3412
        echo '<br /><small>'.$title_element['subTitle'].'</small>';
3413
    }
3414
    echo '</h3>';
3415
}
3416
3417
/**
3418
 * Displays options for switching between student view and course manager view.
3419
 *
3420
 * Changes in version 1.2 (Patrick Cool)
3421
 * Student view switch now behaves as a real switch. It maintains its current state until the state
3422
 * is changed explicitly
3423
 *
3424
 * Changes in version 1.1 (Patrick Cool)
3425
 * student view now works correctly in subfolders of the document tool
3426
 * student view works correctly in the new links tool
3427
 *
3428
 * Example code for using this in your tools:
3429
 * //if ($is_courseAdmin && api_get_setting('student_view_enabled') == 'true') {
3430
 * //   display_tool_view_option($isStudentView);
3431
 * //}
3432
 * //and in later sections, use api_is_allowed_to_edit()
3433
 *
3434
 * @author Roan Embrechts
3435
 * @author Patrick Cool
3436
 * @author Julio Montoya, changes added in Chamilo
3437
 *
3438
 * @version 1.2
3439
 *
3440
 * @todo rewrite code so it is easier to understand
3441
 */
3442
function api_display_tool_view_option()
3443
{
3444
    if ('true' != api_get_setting('student_view_enabled')) {
3445
        return '';
3446
    }
3447
3448
    $sourceurl = '';
3449
    $is_framed = false;
3450
    // Exceptions apply for all multi-frames pages
3451
    if (false !== strpos($_SERVER['REQUEST_URI'], 'chat/chat_banner.php')) {
3452
        // The chat is a multiframe bit that doesn't work too well with the student_view, so do not show the link
3453
        return '';
3454
    }
3455
3456
    // Uncomment to remove student view link from document view page
3457
    if (false !== strpos($_SERVER['REQUEST_URI'], 'lp/lp_header.php')) {
3458
        if (empty($_GET['lp_id'])) {
3459
            return '';
3460
        }
3461
        $sourceurl = substr($_SERVER['REQUEST_URI'], 0, strpos($_SERVER['REQUEST_URI'], '?'));
3462
        $sourceurl = str_replace(
3463
            'lp/lp_header.php',
3464
            'lp/lp_controller.php?'.api_get_cidreq().'&action=view&lp_id='.intval($_GET['lp_id']).'&isStudentView='.('studentview' == $_SESSION['studentview'] ? 'false' : 'true'),
3465
            $sourceurl
3466
        );
3467
        //showinframes doesn't handle student view anyway...
3468
        //return '';
3469
        $is_framed = true;
3470
    }
3471
3472
    // Check whether the $_SERVER['REQUEST_URI'] contains already url parameters (thus a questionmark)
3473
    if (!$is_framed) {
3474
        if (false === strpos($_SERVER['REQUEST_URI'], '?')) {
3475
            $sourceurl = api_get_self().'?'.api_get_cidreq();
3476
        } else {
3477
            $sourceurl = $_SERVER['REQUEST_URI'];
3478
        }
3479
    }
3480
3481
    $output_string = '';
3482
    if (!empty($_SESSION['studentview'])) {
3483
        if ('studentview' == $_SESSION['studentview']) {
3484
            // We have to remove the isStudentView=true from the $sourceurl
3485
            $sourceurl = str_replace('&isStudentView=true', '', $sourceurl);
3486
            $sourceurl = str_replace('&isStudentView=false', '', $sourceurl);
3487
            $output_string .= '<a class="btn btn-primary btn-sm" href="'.$sourceurl.'&isStudentView=false" target="_self">'.
3488
                Display::returnFontAwesomeIcon('eye').' '.get_lang('Switch to teacher view').'</a>';
3489
        } elseif ('teacherview' == $_SESSION['studentview']) {
3490
            // Switching to teacherview
3491
            $sourceurl = str_replace('&isStudentView=true', '', $sourceurl);
3492
            $sourceurl = str_replace('&isStudentView=false', '', $sourceurl);
3493
            $output_string .= '<a class="btn btn-default btn-sm" href="'.$sourceurl.'&isStudentView=true" target="_self">'.
3494
                Display::returnFontAwesomeIcon('eye').' '.get_lang('Switch to student view').'</a>';
3495
        }
3496
    } else {
3497
        $output_string .= '<a class="btn btn-default btn-sm" href="'.$sourceurl.'&isStudentView=true" target="_self">'.
3498
            Display::returnFontAwesomeIcon('eye').' '.get_lang('Switch to student view').'</a>';
3499
    }
3500
    $output_string = Security::remove_XSS($output_string);
3501
    $html = Display::tag('div', $output_string, ['class' => 'view-options']);
3502
3503
    return $html;
3504
}
3505
3506
// TODO: This is for the permission section.
3507
/**
3508
 * Function that removes the need to directly use is_courseAdmin global in
3509
 * tool scripts. It returns true or false depending on the user's rights in
3510
 * this particular course.
3511
 * Optionally checking for tutor and coach roles here allows us to use the
3512
 * student_view feature altogether with these roles as well.
3513
 *
3514
 * @param bool  Whether to check if the user has the tutor role
3515
 * @param bool  Whether to check if the user has the coach role
3516
 * @param bool  Whether to check if the user has the session coach role
3517
 * @param bool  check the student view or not
3518
 *
3519
 * @author Roan Embrechts
3520
 * @author Patrick Cool
3521
 * @author Julio Montoya
3522
 *
3523
 * @version 1.1, February 2004
3524
 *
3525
 * @return bool true: the user has the rights to edit, false: he does not
3526
 */
3527
function api_is_allowed_to_edit(
3528
    $tutor = false,
3529
    $coach = false,
3530
    $session_coach = false,
3531
    $check_student_view = true
3532
) {
3533
    $allowSessionAdminEdit = true === api_get_setting('session.session_admins_edit_courses_content');
3534
    // Admins can edit anything.
3535
    if (api_is_platform_admin($allowSessionAdminEdit)) {
3536
        //The student preview was on
3537
        if ($check_student_view && api_is_student_view_active()) {
3538
            return false;
3539
        }
3540
3541
        return true;
3542
    }
3543
3544
    $sessionId = api_get_session_id();
3545
3546
    if ($sessionId && api_get_configuration_value('session_courses_read_only_mode')) {
3547
        $efv = new ExtraFieldValue('course');
3548
        $lockExrafieldField = $efv->get_values_by_handler_and_field_variable(
3549
            api_get_course_int_id(),
3550
            'session_courses_read_only_mode'
3551
        );
3552
3553
        if (!empty($lockExrafieldField['value'])) {
3554
            return false;
3555
        }
3556
    }
3557
3558
    $is_allowed_coach_to_edit = api_is_coach(null, null, $check_student_view);
3559
    $session_visibility = api_get_session_visibility($sessionId);
3560
    $is_courseAdmin = api_is_course_admin();
3561
3562
    if (!$is_courseAdmin && $tutor) {
3563
        // If we also want to check if the user is a tutor...
3564
        $is_courseAdmin = $is_courseAdmin || api_is_course_tutor();
3565
    }
3566
3567
    if (!$is_courseAdmin && $coach) {
3568
        // If we also want to check if the user is a coach...';
3569
        // Check if session visibility is read only for coaches.
3570
        if (SESSION_VISIBLE_READ_ONLY == $session_visibility) {
3571
            $is_allowed_coach_to_edit = false;
3572
        }
3573
3574
        if ('true' === api_get_setting('allow_coach_to_edit_course_session')) {
3575
            // Check if coach is allowed to edit a course.
3576
            $is_courseAdmin = $is_courseAdmin || $is_allowed_coach_to_edit;
3577
        }
3578
    }
3579
3580
    if (!$is_courseAdmin && $session_coach) {
3581
        $is_courseAdmin = $is_courseAdmin || $is_allowed_coach_to_edit;
3582
    }
3583
3584
    // Check if the student_view is enabled, and if so, if it is activated.
3585
    if ('true' === api_get_setting('student_view_enabled')) {
3586
        $studentView = api_is_student_view_active();
3587
        if (!empty($sessionId)) {
3588
            // Check if session visibility is read only for coaches.
3589
            if (SESSION_VISIBLE_READ_ONLY == $session_visibility) {
3590
                $is_allowed_coach_to_edit = false;
3591
            }
3592
3593
            $is_allowed = false;
3594
            if ('true' === api_get_setting('allow_coach_to_edit_course_session')) {
3595
                // Check if coach is allowed to edit a course.
3596
                $is_allowed = $is_allowed_coach_to_edit;
3597
            }
3598
            if ($check_student_view) {
3599
                $is_allowed = $is_allowed && false === $studentView;
3600
            }
3601
        } else {
3602
            $is_allowed = $is_courseAdmin;
3603
            if ($check_student_view) {
3604
                $is_allowed = $is_courseAdmin && false === $studentView;
3605
            }
3606
        }
3607
3608
        return $is_allowed;
3609
    } else {
3610
        return $is_courseAdmin;
3611
    }
3612
}
3613
3614
/**
3615
 * Returns true if user is a course coach of at least one course in session.
3616
 *
3617
 * @param int $sessionId
3618
 *
3619
 * @return bool
3620
 */
3621
function api_is_coach_of_course_in_session($sessionId)
3622
{
3623
    if (api_is_platform_admin()) {
3624
        return true;
3625
    }
3626
3627
    $userId = api_get_user_id();
3628
    $courseList = UserManager::get_courses_list_by_session(
3629
        $userId,
3630
        $sessionId
3631
    );
3632
3633
    // Session visibility.
3634
    $visibility = api_get_session_visibility(
3635
        $sessionId,
3636
        null,
3637
        false
3638
    );
3639
3640
    if (SESSION_VISIBLE != $visibility && !empty($courseList)) {
3641
        // Course Coach session visibility.
3642
        $blockedCourseCount = 0;
3643
        $closedVisibilityList = [
3644
            COURSE_VISIBILITY_CLOSED,
3645
            COURSE_VISIBILITY_HIDDEN,
3646
        ];
3647
3648
        foreach ($courseList as $course) {
3649
            // Checking session visibility
3650
            $sessionCourseVisibility = api_get_session_visibility(
3651
                $sessionId,
3652
                $course['real_id']
3653
            );
3654
3655
            $courseIsVisible = !in_array(
3656
                $course['visibility'],
3657
                $closedVisibilityList
3658
            );
3659
            if (false === $courseIsVisible || SESSION_INVISIBLE == $sessionCourseVisibility) {
3660
                $blockedCourseCount++;
3661
            }
3662
        }
3663
3664
        // If all courses are blocked then no show in the list.
3665
        if ($blockedCourseCount === count($courseList)) {
3666
            $visibility = SESSION_INVISIBLE;
3667
        } else {
3668
            $visibility = SESSION_VISIBLE;
3669
        }
3670
    }
3671
3672
    switch ($visibility) {
3673
        case SESSION_VISIBLE_READ_ONLY:
3674
        case SESSION_VISIBLE:
3675
        case SESSION_AVAILABLE:
3676
            return true;
3677
            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...
3678
        case SESSION_INVISIBLE:
3679
            return false;
3680
    }
3681
3682
    return false;
3683
}
3684
3685
/**
3686
 * Checks if a student can edit contents in a session depending
3687
 * on the session visibility.
3688
 *
3689
 * @param bool $tutor Whether to check if the user has the tutor role
3690
 * @param bool $coach Whether to check if the user has the coach role
3691
 *
3692
 * @return bool true: the user has the rights to edit, false: he does not
3693
 */
3694
function api_is_allowed_to_session_edit($tutor = false, $coach = false)
3695
{
3696
    if (api_is_allowed_to_edit($tutor, $coach)) {
3697
        // If I'm a teacher, I will return true in order to not affect the normal behaviour of Chamilo tools.
3698
        return true;
3699
    } else {
3700
        $sessionId = api_get_session_id();
3701
3702
        if (0 == $sessionId) {
3703
            // I'm not in a session so i will return true to not affect the normal behaviour of Chamilo tools.
3704
            return true;
3705
        } else {
3706
            // I'm in a session and I'm a student
3707
            // Get the session visibility
3708
            $session_visibility = api_get_session_visibility($sessionId);
3709
            // if 5 the session is still available
3710
            switch ($session_visibility) {
3711
                case SESSION_VISIBLE_READ_ONLY: // 1
3712
                    return false;
3713
                case SESSION_VISIBLE:           // 2
3714
                    return true;
3715
                case SESSION_INVISIBLE:         // 3
3716
                    return false;
3717
                case SESSION_AVAILABLE:         //5
3718
                    return true;
3719
            }
3720
        }
3721
    }
3722
3723
    return false;
3724
}
3725
3726
/**
3727
 * Checks whether the user is allowed in a specific tool for a specific action.
3728
 *
3729
 * @param string $tool   the tool we are checking if the user has a certain permission
3730
 * @param string $action the action we are checking (add, edit, delete, move, visibility)
3731
 *
3732
 * @return bool
3733
 *
3734
 * @author Patrick Cool <[email protected]>, Ghent University
3735
 * @author Julio Montoya
3736
 *
3737
 * @version 1.0
3738
 */
3739
function api_is_allowed($tool, $action, $task_id = 0)
3740
{
3741
    $_user = api_get_user_info();
3742
    $_course = api_get_course_info();
3743
3744
    if (api_is_course_admin()) {
3745
        return true;
3746
    }
3747
3748
    if (is_array($_course) and count($_course) > 0) {
3749
        require_once api_get_path(SYS_CODE_PATH).'permissions/permissions_functions.inc.php';
3750
3751
        // Getting the permissions of this user.
3752
        if (0 == $task_id) {
3753
            $user_permissions = get_permissions('user', $_user['user_id']);
3754
            $_SESSION['total_permissions'][$_course['code']] = $user_permissions;
3755
        }
3756
3757
        // Getting the permissions of the task.
3758
        if (0 != $task_id) {
3759
            $task_permissions = get_permissions('task', $task_id);
3760
            /* !!! */$_SESSION['total_permissions'][$_course['code']] = $task_permissions;
3761
        }
3762
    }
3763
3764
    // If the permissions are limited, we have to map the extended ones to the limited ones.
3765
    if ('limited' == api_get_setting('permissions')) {
3766
        if ('Visibility' == $action) {
3767
            $action = 'Edit';
3768
        }
3769
        if ('Move' == $action) {
3770
            $action = 'Edit';
3771
        }
3772
    }
3773
3774
    // The session that contains all the permissions already exists for this course
3775
    // so there is no need to requery everything.
3776
    //my_print_r($_SESSION['total_permissions'][$_course['code']][$tool]);
3777
    if (is_array($_SESSION['total_permissions'][$_course['code']][$tool])) {
3778
        if (in_array($action, $_SESSION['total_permissions'][$_course['code']][$tool])) {
3779
            return true;
3780
        } else {
3781
            return false;
3782
        }
3783
    }
3784
3785
    return false;
3786
}
3787
3788
/**
3789
 * Tells whether this user is an anonymous user.
3790
 *
3791
 * @param int  $user_id  User ID (optional, will take session ID if not provided)
3792
 * @param bool $db_check Whether to check in the database (true) or simply in
3793
 *                       the session (false) to see if the current user is the anonymous user
3794
 *
3795
 * @return bool true if this user is anonymous, false otherwise
3796
 */
3797
function api_is_anonymous($user_id = null, $db_check = false)
3798
{
3799
    /*if ($db_check) {
3800
        if (!isset($user_id)) {
3801
            $user_id = api_get_user_id();
3802
        }
3803
3804
        $info = api_get_user_info($user_id);
3805
3806
        if (6 == $info['status'] || 0 == $user_id || empty($info)) {
3807
            return true;
3808
        }
3809
    }*/
3810
3811
    return !Container::getAuthorizationChecker()->isGranted('IS_AUTHENTICATED_FULLY');
3812
}
3813
3814
/**
3815
 * Displays message "You are not allowed here..." and exits the entire script.
3816
 *
3817
 * @param bool   $print_headers Whether or not to print headers (default = false -> does not print them)
3818
 * @param string $message
3819
 * @param int    $responseCode
3820
 */
3821
function api_not_allowed(
3822
    $print_headers = false,
3823
    $message = null,
3824
    $responseCode = 0
3825
) {
3826
    throw new Exception('You are not allowed');
3827
}
3828
3829
/**
3830
 * Gets a UNIX timestamp from a database (MySQL) datetime format string.
3831
 *
3832
 * @param $last_post_datetime standard output date in a sql query
3833
 *
3834
 * @return int timestamp
3835
 *
3836
 * @author Toon Van Hoecke <[email protected]>
3837
 *
3838
 * @version October 2003
3839
 * @desc convert sql date to unix timestamp
3840
 */
3841
function convert_sql_date($last_post_datetime)
3842
{
3843
    [$last_post_date, $last_post_time] = explode(' ', $last_post_datetime);
3844
    [$year, $month, $day] = explode('-', $last_post_date);
3845
    [$hour, $min, $sec] = explode(':', $last_post_time);
3846
3847
    return mktime((int) $hour, (int) $min, (int) $sec, (int) $month, (int) $day, (int) $year);
3848
}
3849
3850
/**
3851
 * Delete a row in the c_item_property table.
3852
 *
3853
 * @param array  $courseInfo
3854
 * @param string $tool
3855
 * @param int    $itemId
3856
 * @param int    $userId
3857
 * @param int    $groupId    group.iid
3858
 * @param int    $sessionId
3859
 *
3860
 * @return false|null
3861
 */
3862
function api_item_property_delete(
3863
    $courseInfo,
3864
    $tool,
3865
    $itemId,
3866
    $userId,
3867
    $groupId = 0,
3868
    $sessionId = 0
3869
) {
3870
    if (empty($courseInfo)) {
3871
        return false;
3872
    }
3873
3874
    $courseId = (int) $courseInfo['real_id'];
3875
3876
    if (empty($courseId) || empty($tool) || empty($itemId)) {
3877
        return false;
3878
    }
3879
3880
    $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
3881
    $tool = Database::escape_string($tool);
3882
    $itemId = intval($itemId);
3883
    $userId = intval($userId);
3884
    $groupId = intval($groupId);
3885
    $sessionId = intval($sessionId);
3886
3887
    $groupCondition = " AND to_group_id = $groupId ";
3888
    if (empty($groupId)) {
3889
        $groupCondition = " AND (to_group_id is NULL OR to_group_id = 0) ";
3890
    }
3891
3892
    $userCondition = " AND to_user_id = $userId ";
3893
    if (empty($userId)) {
3894
        $userCondition = " AND (to_user_id is NULL OR to_user_id = 0) ";
3895
    }
3896
    $sessionCondition = api_get_session_condition($sessionId, true, false, 'session_id');
3897
    $sql = "DELETE FROM $table
3898
            WHERE
3899
                c_id = $courseId AND
3900
                tool  = '$tool' AND
3901
                ref = $itemId
3902
                $sessionCondition
3903
                $userCondition
3904
                $groupCondition
3905
            ";
3906
3907
    Database::query($sql);
3908
}
3909
3910
/**
3911
 * Gets item property by tool.
3912
 *
3913
 * @param string    course code
3914
 * @param string    tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
3915
 * @param int       id of the item itself, linked to key of every tool ('id', ...), "*" = all items of the tool
3916
 * @param int    $session_id
3917
 * @param string $tool
3918
 * @param string $course_code
3919
 *
3920
 * @return array All fields from c_item_property (all rows found) or empty array
3921
 */
3922
function api_get_item_property_by_tool($tool, $course_code, $session_id = null)
3923
{
3924
    $course_info = api_get_course_info($course_code);
3925
    $tool = Database::escape_string($tool);
3926
3927
    // Definition of tables.
3928
    $item_property_table = Database::get_course_table(TABLE_ITEM_PROPERTY);
3929
    $session_id = (int) $session_id;
3930
    $session_condition = ' AND session_id = '.$session_id;
3931
    if (empty($session_id)) {
3932
        $session_condition = " AND (session_id = 0 OR session_id IS NULL) ";
3933
    }
3934
    $course_id = $course_info['real_id'];
3935
3936
    $sql = "SELECT * FROM $item_property_table
3937
            WHERE
3938
                c_id = $course_id AND
3939
                tool = '$tool'
3940
                $session_condition ";
3941
    $rs = Database::query($sql);
3942
    $list = [];
3943
    if (Database::num_rows($rs) > 0) {
3944
        while ($row = Database::fetch_array($rs, 'ASSOC')) {
3945
            $list[] = $row;
3946
        }
3947
    }
3948
3949
    return $list;
3950
}
3951
3952
/**
3953
 * Gets item property by tool and user.
3954
 *
3955
 * @param int $userId
3956
 * @param int $tool
3957
 * @param int $courseId
3958
 * @param int $session_id
3959
 *
3960
 * @return array
3961
 */
3962
function api_get_item_property_list_by_tool_by_user(
3963
    $userId,
3964
    $tool,
3965
    $courseId,
3966
    $session_id = 0
3967
) {
3968
    $userId = intval($userId);
3969
    $tool = Database::escape_string($tool);
3970
    $session_id = intval($session_id);
3971
    $courseId = intval($courseId);
3972
3973
    // Definition of tables.
3974
    $item_property_table = Database::get_course_table(TABLE_ITEM_PROPERTY);
3975
    $session_condition = ' AND session_id = '.$session_id;
3976
    if (empty($session_id)) {
3977
        $session_condition = " AND (session_id = 0 OR session_id IS NULL) ";
3978
    }
3979
    $sql = "SELECT * FROM $item_property_table
3980
            WHERE
3981
                insert_user_id = $userId AND
3982
                c_id = $courseId AND
3983
                tool = '$tool'
3984
                $session_condition ";
3985
3986
    $rs = Database::query($sql);
3987
    $list = [];
3988
    if (Database::num_rows($rs) > 0) {
3989
        while ($row = Database::fetch_array($rs, 'ASSOC')) {
3990
            $list[] = $row;
3991
        }
3992
    }
3993
3994
    return $list;
3995
}
3996
3997
/**
3998
 * Gets item property id from tool of a course.
3999
 *
4000
 * @param string $course_code course code
4001
 * @param string $tool        tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4002
 * @param int    $ref         id of the item itself, linked to key of every tool ('id', ...), "*" = all items of the tool
4003
 * @param int    $sessionId   Session ID (optional)
4004
 *
4005
 * @return int
4006
 */
4007
function api_get_item_property_id($course_code, $tool, $ref, $sessionId = 0)
4008
{
4009
    $course_info = api_get_course_info($course_code);
4010
    $tool = Database::escape_string($tool);
4011
    $ref = (int) $ref;
4012
4013
    // Definition of tables.
4014
    $tableItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
4015
    $course_id = $course_info['real_id'];
4016
    $sessionId = (int) $sessionId;
4017
    $sessionCondition = " AND session_id = $sessionId ";
4018
    if (empty($sessionId)) {
4019
        $sessionCondition = ' AND (session_id = 0 OR session_id IS NULL) ';
4020
    }
4021
    $sql = "SELECT id FROM $tableItemProperty
4022
            WHERE
4023
                c_id = $course_id AND
4024
                tool = '$tool' AND
4025
                ref = $ref
4026
                $sessionCondition";
4027
    $rs = Database::query($sql);
4028
    $item_property_id = '';
4029
    if (Database::num_rows($rs) > 0) {
4030
        $row = Database::fetch_array($rs);
4031
        $item_property_id = $row['id'];
4032
    }
4033
4034
    return $item_property_id;
4035
}
4036
4037
/**
4038
 * Inserts a record in the track_e_item_property table (No update).
4039
 *
4040
 * @param string $tool
4041
 * @param int    $ref
4042
 * @param string $title
4043
 * @param string $content
4044
 * @param int    $progress
4045
 *
4046
 * @return bool|int
4047
 */
4048
function api_track_item_property_update($tool, $ref, $title, $content, $progress)
4049
{
4050
    $tbl_stats_item_property = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ITEM_PROPERTY);
4051
    $course_id = api_get_course_int_id(); //numeric
4052
    $course_code = api_get_course_id(); //alphanumeric
4053
    $item_property_id = api_get_item_property_id($course_code, $tool, $ref);
4054
    if (!empty($item_property_id)) {
4055
        $sql = "INSERT IGNORE INTO $tbl_stats_item_property SET
4056
                course_id           = '$course_id',
4057
                item_property_id    = '$item_property_id',
4058
                title               = '".Database::escape_string($title)."',
4059
                content             = '".Database::escape_string($content)."',
4060
                progress            = '".intval($progress)."',
4061
                lastedit_date       = '".api_get_utc_datetime()."',
4062
                lastedit_user_id    = '".api_get_user_id()."',
4063
                session_id          = '".api_get_session_id()."'";
4064
        $result = Database::query($sql);
4065
        $affected_rows = Database::affected_rows($result);
4066
4067
        return $affected_rows;
4068
    }
4069
4070
    return false;
4071
}
4072
4073
/**
4074
 * @param string $tool
4075
 * @param int    $ref
4076
 *
4077
 * @return array|resource
4078
 */
4079
function api_get_track_item_property_history($tool, $ref)
4080
{
4081
    $tbl_stats_item_property = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ITEM_PROPERTY);
4082
    $course_id = api_get_course_int_id(); //numeric
4083
    $course_code = api_get_course_id(); //alphanumeric
4084
    $item_property_id = api_get_item_property_id($course_code, $tool, $ref);
4085
    $sql = "SELECT * FROM $tbl_stats_item_property
4086
            WHERE item_property_id = $item_property_id AND course_id = $course_id
4087
            ORDER BY lastedit_date DESC";
4088
    $result = Database::query($sql);
4089
    if (false === $result or null === $result) {
4090
        $result = [];
4091
    } else {
4092
        $result = Database::store_result($result, 'ASSOC');
4093
    }
4094
4095
    return $result;
4096
}
4097
4098
/**
4099
 * Gets item property data from tool of a course id.
4100
 *
4101
 * @deprecated
4102
 *
4103
 * @param int    $course_id
4104
 * @param string $tool       tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4105
 * @param int    $ref        id of the item itself, linked to key of every tool ('id', ...), "*" = all items of the tool
4106
 * @param int    $session_id
4107
 * @param int    $groupId
4108
 *
4109
 * @return array with all fields from c_item_property, empty array if not found or false if course could not be found
4110
 */
4111
function api_get_item_property_info($course_id, $tool, $ref, $session_id = 0, $groupId = 0)
4112
{
4113
    $courseInfo = api_get_course_info_by_id($course_id);
4114
4115
    if (empty($courseInfo)) {
4116
        return false;
4117
    }
4118
4119
    $tool = Database::escape_string($tool);
4120
    $course_id = $courseInfo['real_id'];
4121
    $ref = (int) $ref;
4122
    $session_id = (int) $session_id;
4123
4124
    $sessionCondition = " session_id = $session_id";
4125
    if (empty($session_id)) {
4126
        $sessionCondition = ' (session_id = 0 OR session_id IS NULL) ';
4127
    }
4128
4129
    // Definition of tables.
4130
    $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4131
4132
    $sql = "SELECT * FROM $table
4133
            WHERE
4134
                c_id = $course_id AND
4135
                tool = '$tool' AND
4136
                ref = $ref AND
4137
                $sessionCondition ";
4138
4139
    if (!empty($groupId)) {
4140
        $groupId = (int) $groupId;
4141
        $sql .= " AND to_group_id = $groupId ";
4142
    }
4143
4144
    $rs = Database::query($sql);
4145
    $row = [];
4146
    if (Database::num_rows($rs) > 0) {
4147
        $row = Database::fetch_array($rs, 'ASSOC');
4148
    }
4149
4150
    return $row;
4151
}
4152
4153
/**
4154
 * Displays a combo box so the user can select his/her preferred language.
4155
 *
4156
 * @param string The desired name= value for the select
4157
 * @param bool Whether we use the JQuery Chozen library or not
4158
 * (in some cases, like the indexing language picker, it can alter the presentation)
4159
 *
4160
 * @deprecated
4161
 *
4162
 * @return string
4163
 */
4164
function api_get_languages_combo($name = 'language')
4165
{
4166
    $ret = '';
4167
    $platformLanguage = api_get_setting('platformLanguage');
4168
4169
    // Retrieve a complete list of all the languages.
4170
    $language_list = api_get_languages();
4171
4172
    if (count($language_list) < 2) {
4173
        return $ret;
4174
    }
4175
4176
    // The the current language of the user so that his/her language occurs as selected in the dropdown menu.
4177
    if (isset($_SESSION['user_language_choice'])) {
4178
        $default = $_SESSION['user_language_choice'];
4179
    } else {
4180
        $default = $platformLanguage;
4181
    }
4182
4183
    $ret .= '<select name="'.$name.'" id="language_chosen" class="selectpicker show-tick form-control">';
4184
    foreach ($language_list as $key => $value) {
4185
        if ($key == $default) {
4186
            $selected = ' selected="selected"';
4187
        } else {
4188
            $selected = '';
4189
        }
4190
        $ret .= sprintf('<option value=%s" %s>%s</option>', $key, $selected, $value);
4191
    }
4192
    $ret .= '</select>';
4193
4194
    return $ret;
4195
}
4196
4197
/**
4198
 * Displays a form (drop down menu) so the user can select his/her preferred language.
4199
 * The form works with or without javascript.
4200
 *
4201
 * @param  bool Hide form if only one language available (defaults to false = show the box anyway)
4202
 * @param bool $showAsButton
4203
 *
4204
 * @return string|null Display the box directly
4205
 */
4206
function api_display_language_form($hide_if_no_choice = false, $showAsButton = false)
4207
{
4208
    // Retrieve a complete list of all the languages.
4209
    $language_list = api_get_languages();
4210
    if (count($language_list['name']) <= 1 && $hide_if_no_choice) {
4211
        return; //don't show any form
4212
    }
4213
4214
    // The the current language of the user so that his/her language occurs as selected in the dropdown menu.
4215
    if (isset($_SESSION['user_language_choice'])) {
4216
        $user_selected_language = $_SESSION['user_language_choice'];
4217
    }
4218
    if (empty($user_selected_language)) {
4219
        $user_selected_language = api_get_setting('platformLanguage');
4220
    }
4221
4222
    $currentLanguageId = api_get_language_id($user_selected_language);
4223
    $currentLanguageInfo = api_get_language_info($currentLanguageId);
4224
    $countryCode = languageToCountryIsoCode($currentLanguageInfo['isocode']);
4225
    $url = api_get_self();
4226
    if ($showAsButton) {
4227
        $html = '<div class="btn-group">
4228
              <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
4229
                <span class="flag-icon flag-icon-'.$countryCode.'"></span>
4230
                '.$currentLanguageInfo['original_name'].'
4231
                <span class="caret">
4232
                </span>
4233
              </button>';
4234
    } else {
4235
        $html = '
4236
            <a href="'.$url.'" class="dropdown-toggle" data-toggle="dropdown" role="button">
4237
                <span class="flag-icon flag-icon-'.$countryCode.'"></span>
4238
                '.$currentLanguageInfo['original_name'].'
4239
                <span class="caret"></span>
4240
            </a>
4241
            ';
4242
    }
4243
4244
    $html .= '<ul class="dropdown-menu" role="menu">';
4245
    foreach ($language_list['all'] as $key => $data) {
4246
        $urlLink = $url.'?language='.$data['english_name'];
4247
        $html .= '<li><a href="'.$urlLink.'"><span class="flag-icon flag-icon-'.languageToCountryIsoCode($data['isocode']).'"></span> '.$data['original_name'].'</a></li>';
4248
    }
4249
    $html .= '</ul>';
4250
4251
    if ($showAsButton) {
4252
        $html .= '</div>';
4253
    }
4254
4255
    return $html;
4256
}
4257
4258
/**
4259
 * @param string $languageIsoCode
4260
 *
4261
 * @return string
4262
 */
4263
function languageToCountryIsoCode($languageIsoCode)
4264
{
4265
    $allow = api_get_configuration_value('language_flags_by_country');
4266
4267
    // @todo save in DB
4268
    switch ($languageIsoCode) {
4269
        case 'ar':
4270
            $country = 'ae';
4271
            break;
4272
        case 'bs':
4273
            $country = 'ba';
4274
            break;
4275
        case 'ca':
4276
            $country = 'es';
4277
            if ($allow) {
4278
                $country = 'catalan';
4279
            }
4280
            break;
4281
        case 'cs':
4282
            $country = 'cz';
4283
            break;
4284
        case 'da':
4285
            $country = 'dk';
4286
            break;
4287
        case 'el':
4288
            $country = 'ae';
4289
            break;
4290
        case 'en':
4291
            $country = 'gb';
4292
            break;
4293
        case 'eu': // Euskera
4294
            $country = 'es';
4295
            if ($allow) {
4296
                $country = 'basque';
4297
            }
4298
            break;
4299
        case 'gl': // galego
4300
            $country = 'es';
4301
            if ($allow) {
4302
                $country = 'galician';
4303
            }
4304
            break;
4305
        case 'he':
4306
            $country = 'il';
4307
            break;
4308
        case 'ja':
4309
            $country = 'jp';
4310
            break;
4311
        case 'ka':
4312
            $country = 'ge';
4313
            break;
4314
        case 'ko':
4315
            $country = 'kr';
4316
            break;
4317
        case 'ms':
4318
            $country = 'my';
4319
            break;
4320
        case 'pt-BR':
4321
            $country = 'br';
4322
            break;
4323
        case 'qu':
4324
            $country = 'pe';
4325
            break;
4326
        case 'sl':
4327
            $country = 'si';
4328
            break;
4329
        case 'sv':
4330
            $country = 'se';
4331
            break;
4332
        case 'uk': // Ukraine
4333
            $country = 'ua';
4334
            break;
4335
        case 'zh-TW':
4336
        case 'zh':
4337
            $country = 'cn';
4338
            break;
4339
        default:
4340
            $country = $languageIsoCode;
4341
            break;
4342
    }
4343
    $country = strtolower($country);
4344
4345
    return $country;
4346
}
4347
4348
/**
4349
 * Returns a list of all the languages that are made available by the admin.
4350
 *
4351
 * @return array An array with all languages. Structure of the array is
4352
 *               array['name'] = An array with the name of every language
4353
 *               array['folder'] = An array with the corresponding names of the language-folders in the filesystem
4354
 */
4355
function api_get_languages()
4356
{
4357
    $table = Database::get_main_table(TABLE_MAIN_LANGUAGE);
4358
    $sql = "SELECT * FROM $table WHERE available='1'
4359
            ORDER BY original_name ASC";
4360
    $result = Database::query($sql);
4361
    $languages = [];
4362
    while ($row = Database::fetch_array($result, 'ASSOC')) {
4363
        $languages[$row['isocode']] = $row['original_name'];
4364
    }
4365
4366
    return $languages;
4367
}
4368
4369
/**
4370
 * Returns a list of all the languages that are made available by the admin.
4371
 *
4372
 * @return array
4373
 */
4374
function api_get_languages_to_array()
4375
{
4376
    $tbl_language = Database::get_main_table(TABLE_MAIN_LANGUAGE);
4377
    $sql = "SELECT * FROM $tbl_language WHERE available='1' ORDER BY original_name ASC";
4378
    $result = Database::query($sql);
4379
    $languages = [];
4380
    while ($row = Database::fetch_array($result)) {
4381
        $languages[$row['dokeos_folder']] = $row['original_name'];
4382
    }
4383
4384
    return $languages;
4385
}
4386
4387
/**
4388
 * Returns the id (the database id) of a language.
4389
 *
4390
 * @param   string  language name (the corresponding name of the language-folder in the filesystem)
4391
 *
4392
 * @return int id of the language
4393
 */
4394
function api_get_language_id($language)
4395
{
4396
    $tbl_language = Database::get_main_table(TABLE_MAIN_LANGUAGE);
4397
    if (empty($language)) {
4398
        return null;
4399
    }
4400
    $language = Database::escape_string($language);
4401
    $sql = "SELECT id FROM $tbl_language
4402
            WHERE dokeos_folder = '$language' LIMIT 1";
4403
    $result = Database::query($sql);
4404
    $row = Database::fetch_array($result);
4405
4406
    return $row['id'];
4407
}
4408
4409
/**
4410
 * Get the language information by its id.
4411
 *
4412
 * @param int $languageId
4413
 *
4414
 * @throws Exception
4415
 *
4416
 * @return array
4417
 */
4418
function api_get_language_info($languageId)
4419
{
4420
    if (empty($languageId)) {
4421
        return [];
4422
    }
4423
4424
    $language = Database::getManager()->find(Language::class, $languageId);
4425
4426
    if (!$language) {
4427
        return [];
4428
    }
4429
4430
    return [
4431
        'id' => $language->getId(),
4432
        'original_name' => $language->getOriginalName(),
4433
        'english_name' => $language->getEnglishName(),
4434
        'isocode' => $language->getIsocode(),
4435
        'dokeos_folder' => $language->getDokeosFolder(),
4436
        'available' => $language->getAvailable(),
4437
        'parent_id' => $language->getParent() ? $language->getParent()->getId() : null,
4438
    ];
4439
}
4440
4441
/**
4442
 * @param string $code
4443
 *
4444
 * @return Language
4445
 */
4446
function api_get_language_from_iso($code)
4447
{
4448
    $em = Database::getManager();
4449
4450
    return $em->getRepository(Language::class)->findOneBy(['isocode' => $code]);
4451
}
4452
4453
/**
4454
 * Returns the name of the visual (CSS) theme to be applied on the current page.
4455
 * The returned name depends on the platform, course or user -wide settings.
4456
 *
4457
 * @return string The visual theme's name, it is the name of a folder inside web/css/themes
4458
 */
4459
function api_get_visual_theme()
4460
{
4461
    static $visual_theme;
4462
    if (!isset($visual_theme)) {
4463
        // Get style directly from DB
4464
        /*$styleFromDatabase = api_get_settings_params_simple(
4465
            [
4466
                'variable = ? AND access_url = ?' => [
4467
                    'stylesheets',
4468
                    api_get_current_access_url_id(),
4469
                ],
4470
            ]
4471
        );
4472
4473
        if ($styleFromDatabase) {
4474
            $platform_theme = $styleFromDatabase['selected_value'];
4475
        } else {
4476
            $platform_theme = api_get_setting('stylesheets');
4477
        }*/
4478
        $platform_theme = api_get_setting('stylesheets');
4479
4480
        // Platform's theme.
4481
        $visual_theme = $platform_theme;
4482
        if ('true' == api_get_setting('user_selected_theme')) {
4483
            $user_info = api_get_user_info();
4484
            if (isset($user_info['theme'])) {
4485
                $user_theme = $user_info['theme'];
4486
4487
                if (!empty($user_theme)) {
4488
                    $visual_theme = $user_theme;
4489
                    // User's theme.
4490
                }
4491
            }
4492
        }
4493
4494
        $course_id = api_get_course_id();
4495
        if (!empty($course_id)) {
4496
            if ('true' == api_get_setting('allow_course_theme')) {
4497
                $course_theme = api_get_course_setting('course_theme', $course_id);
4498
4499
                if (!empty($course_theme) && -1 != $course_theme) {
4500
                    if (!empty($course_theme)) {
4501
                        // Course's theme.
4502
                        $visual_theme = $course_theme;
4503
                    }
4504
                }
4505
4506
                $allow_lp_theme = api_get_course_setting('allow_learning_path_theme');
4507
                if (1 == $allow_lp_theme) {
4508
                    /*global $lp_theme_css, $lp_theme_config;
4509
                    // These variables come from the file lp_controller.php.
4510
                    if (!$lp_theme_config) {
4511
                        if (!empty($lp_theme_css)) {
4512
                            // LP's theme.
4513
                            $visual_theme = $lp_theme_css;
4514
                        }
4515
                    }*/
4516
                }
4517
            }
4518
        }
4519
4520
        if (empty($visual_theme)) {
4521
            $visual_theme = 'chamilo';
4522
        }
4523
4524
        /*global $lp_theme_log;
4525
        if ($lp_theme_log) {
4526
            $visual_theme = $platform_theme;
4527
        }*/
4528
    }
4529
4530
    return $visual_theme;
4531
}
4532
4533
/**
4534
 * Returns a list of CSS themes currently available in the CSS folder
4535
 * The folder must have a default.css file.
4536
 *
4537
 * @param bool $getOnlyThemeFromVirtualInstance Used by the vchamilo plugin
4538
 *
4539
 * @return array list of themes directories from the css folder
4540
 *               Note: Directory names (names of themes) in the file system should contain ASCII-characters only
4541
 */
4542
function api_get_themes($getOnlyThemeFromVirtualInstance = false)
4543
{
4544
    // This configuration value is set by the vchamilo plugin
4545
    $virtualTheme = api_get_configuration_value('virtual_css_theme_folder');
4546
4547
    $readCssFolder = function ($dir) use ($virtualTheme) {
4548
        $finder = new Finder();
4549
        $themes = $finder->directories()->in($dir)->depth(0)->sortByName();
4550
        $list = [];
4551
        /** @var Symfony\Component\Finder\SplFileInfo $theme */
4552
        foreach ($themes as $theme) {
4553
            $folder = $theme->getFilename();
4554
            // A theme folder is consider if there's a default.css file
4555
            if (!file_exists($theme->getPathname().'/default.css')) {
4556
                continue;
4557
            }
4558
            $name = ucwords(str_replace('_', ' ', $folder));
4559
            if ($folder == $virtualTheme) {
4560
                continue;
4561
            }
4562
            $list[$folder] = $name;
4563
        }
4564
4565
        return $list;
4566
    };
4567
4568
    $dir = api_get_path(SYS_CSS_PATH).'themes/';
4569
    $list = $readCssFolder($dir);
4570
4571
    if (!empty($virtualTheme)) {
4572
        $newList = $readCssFolder($dir.'/'.$virtualTheme);
4573
        if ($getOnlyThemeFromVirtualInstance) {
4574
            return $newList;
4575
        }
4576
        $list = $list + $newList;
4577
        asort($list);
4578
    }
4579
4580
    return $list;
4581
}
4582
4583
/**
4584
 * Find the largest sort value in a given user_course_category
4585
 * This function is used when we are moving a course to a different category
4586
 * and also when a user subscribes to courses (the new course is added at the end of the main category.
4587
 *
4588
 * @author Patrick Cool <[email protected]>, Ghent University
4589
 *
4590
 * @param int $user_course_category the id of the user_course_category
4591
 * @param int $user_id
4592
 *
4593
 * @return int the value of the highest sort of the user_course_category
4594
 */
4595
function api_max_sort_value($user_course_category, $user_id)
4596
{
4597
    $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4598
    $sql = "SELECT max(sort) as max_sort FROM $tbl_course_user
4599
            WHERE
4600
                user_id='".intval($user_id)."' AND
4601
                relation_type<>".COURSE_RELATION_TYPE_RRHH." AND
4602
                user_course_cat='".intval($user_course_category)."'";
4603
    $result_max = Database::query($sql);
4604
    if (1 == Database::num_rows($result_max)) {
4605
        $row_max = Database::fetch_array($result_max);
4606
4607
        return $row_max['max_sort'];
4608
    }
4609
4610
    return 0;
4611
}
4612
4613
/**
4614
 * Transforms a number of seconds in hh:mm:ss format.
4615
 *
4616
 * @author Julian Prud'homme
4617
 *
4618
 * @param int    $seconds      number of seconds
4619
 * @param string $space
4620
 * @param bool   $showSeconds
4621
 * @param bool   $roundMinutes
4622
 *
4623
 * @return string the formatted time
4624
 */
4625
function api_time_to_hms($seconds, $space = ':', $showSeconds = true, $roundMinutes = false)
4626
{
4627
    // $seconds = -1 means that we have wrong data in the db.
4628
    if (-1 == $seconds) {
4629
        return
4630
            get_lang('Unknown').
4631
            Display::return_icon(
4632
                'info2.gif',
4633
                get_lang('The datas about this user were registered when the calculation of time spent on the platform wasn\'t possible.'),
4634
                ['align' => 'absmiddle', 'hspace' => '3px']
4635
            );
4636
    }
4637
4638
    // How many hours ?
4639
    $hours = floor($seconds / 3600);
4640
4641
    // How many minutes ?
4642
    $min = floor(($seconds - ($hours * 3600)) / 60);
4643
4644
    if ($roundMinutes) {
4645
        if ($min >= 45) {
4646
            $min = 45;
4647
        }
4648
4649
        if ($min >= 30 && $min <= 44) {
4650
            $min = 30;
4651
        }
4652
4653
        if ($min >= 15 && $min <= 29) {
4654
            $min = 15;
4655
        }
4656
4657
        if ($min >= 0 && $min <= 14) {
4658
            $min = 0;
4659
        }
4660
    }
4661
4662
    // How many seconds
4663
    $sec = floor($seconds - ($hours * 3600) - ($min * 60));
4664
4665
    if ($hours < 10) {
4666
        $hours = "0$hours";
4667
    }
4668
4669
    if ($sec < 10) {
4670
        $sec = "0$sec";
4671
    }
4672
4673
    if ($min < 10) {
4674
        $min = "0$min";
4675
    }
4676
4677
    $seconds = '';
4678
    if ($showSeconds) {
4679
        $seconds = $space.$sec;
4680
    }
4681
4682
    return $hours.$space.$min.$seconds;
4683
}
4684
4685
/* FILE SYSTEM RELATED FUNCTIONS */
4686
4687
/**
4688
 * Returns the permissions to be assigned to every newly created directory by the web-server.
4689
 * The return value is based on the platform administrator's setting
4690
 * "Administration > Configuration settings > Security > Permissions for new directories".
4691
 *
4692
 * @return int returns the permissions in the format "Owner-Group-Others, Read-Write-Execute", as an integer value
4693
 */
4694
function api_get_permissions_for_new_directories()
4695
{
4696
    static $permissions;
4697
    if (!isset($permissions)) {
4698
        $permissions = trim(api_get_setting('permissions_for_new_directories'));
4699
        // The default value 0777 is according to that in the platform administration panel after fresh system installation.
4700
        $permissions = octdec(!empty($permissions) ? $permissions : '0777');
4701
    }
4702
4703
    return $permissions;
4704
}
4705
4706
/**
4707
 * Returns the permissions to be assigned to every newly created directory by the web-server.
4708
 * The return value is based on the platform administrator's setting
4709
 * "Administration > Configuration settings > Security > Permissions for new files".
4710
 *
4711
 * @return int returns the permissions in the format
4712
 *             "Owner-Group-Others, Read-Write-Execute", as an integer value
4713
 */
4714
function api_get_permissions_for_new_files()
4715
{
4716
    static $permissions;
4717
    if (!isset($permissions)) {
4718
        $permissions = trim(api_get_setting('permissions_for_new_files'));
4719
        // The default value 0666 is according to that in the platform
4720
        // administration panel after fresh system installation.
4721
        $permissions = octdec(!empty($permissions) ? $permissions : '0666');
4722
    }
4723
4724
    return $permissions;
4725
}
4726
4727
/**
4728
 * Deletes a file, or a folder and its contents.
4729
 *
4730
 * @author      Aidan Lister <[email protected]>
4731
 *
4732
 * @version     1.0.3
4733
 *
4734
 * @param string $dirname Directory to delete
4735
 * @param       bool     Deletes only the content or not
4736
 * @param bool $strict if one folder/file fails stop the loop
4737
 *
4738
 * @return bool Returns TRUE on success, FALSE on failure
4739
 *
4740
 * @see http://aidanlister.com/2004/04/recursively-deleting-a-folder-in-php/
4741
 *
4742
 * @author      Yannick Warnier, adaptation for the Chamilo LMS, April, 2008
4743
 * @author      Ivan Tcholakov, a sanity check about Directory class creation has been added, September, 2009
4744
 */
4745
function rmdirr($dirname, $delete_only_content_in_folder = false, $strict = false)
4746
{
4747
    $res = true;
4748
    // A sanity check.
4749
    if (!file_exists($dirname)) {
4750
        return false;
4751
    }
4752
    $php_errormsg = '';
4753
    // Simple delete for a file.
4754
    if (is_file($dirname) || is_link($dirname)) {
4755
        $res = unlink($dirname);
4756
        if (false === $res) {
4757
            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);
4758
        }
4759
4760
        return $res;
4761
    }
4762
4763
    // Loop through the folder.
4764
    $dir = dir($dirname);
4765
    // A sanity check.
4766
    $is_object_dir = is_object($dir);
4767
    if ($is_object_dir) {
4768
        while (false !== $entry = $dir->read()) {
4769
            // Skip pointers.
4770
            if ('.' == $entry || '..' == $entry) {
4771
                continue;
4772
            }
4773
4774
            // Recurse.
4775
            if ($strict) {
4776
                $result = rmdirr("$dirname/$entry");
4777
                if (false == $result) {
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...
4778
                    $res = false;
4779
                    break;
4780
                }
4781
            } else {
4782
                rmdirr("$dirname/$entry");
4783
            }
4784
        }
4785
    }
4786
4787
    // Clean up.
4788
    if ($is_object_dir) {
4789
        $dir->close();
4790
    }
4791
4792
    if (false == $delete_only_content_in_folder) {
4793
        $res = rmdir($dirname);
4794
        if (false === $res) {
4795
            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);
4796
        }
4797
    }
4798
4799
    return $res;
4800
}
4801
4802
// TODO: This function is to be simplified. File access modes to be implemented.
4803
/**
4804
 * function adapted from a php.net comment
4805
 * copy recursively a folder.
4806
 *
4807
 * @param the source folder
4808
 * @param the dest folder
4809
 * @param an array of excluded file_name (without extension)
4810
 * @param copied_files the returned array of copied files
4811
 * @param string $source
4812
 * @param string $dest
4813
 */
4814
function copyr($source, $dest, $exclude = [], $copied_files = [])
4815
{
4816
    if (empty($dest)) {
4817
        return false;
4818
    }
4819
    // Simple copy for a file
4820
    if (is_file($source)) {
4821
        $path_info = pathinfo($source);
4822
        if (!in_array($path_info['filename'], $exclude)) {
4823
            copy($source, $dest);
4824
        }
4825
4826
        return true;
4827
    } elseif (!is_dir($source)) {
4828
        //then source is not a dir nor a file, return
4829
        return false;
4830
    }
4831
4832
    // Make destination directory.
4833
    if (!is_dir($dest)) {
4834
        mkdir($dest, api_get_permissions_for_new_directories());
4835
    }
4836
4837
    // Loop through the folder.
4838
    $dir = dir($source);
4839
    while (false !== $entry = $dir->read()) {
4840
        // Skip pointers
4841
        if ('.' == $entry || '..' == $entry) {
4842
            continue;
4843
        }
4844
4845
        // Deep copy directories.
4846
        if ($dest !== "$source/$entry") {
4847
            $files = copyr("$source/$entry", "$dest/$entry", $exclude, $copied_files);
4848
        }
4849
    }
4850
    // Clean up.
4851
    $dir->close();
4852
4853
    return true;
4854
}
4855
4856
/**
4857
 * @todo: Using DIRECTORY_SEPARATOR is not recommended, this is an obsolete approach.
4858
 * Documentation header to be added here.
4859
 *
4860
 * @param string $pathname
4861
 * @param string $base_path_document
4862
 * @param int    $session_id
4863
 *
4864
 * @return mixed True if directory already exists, false if a file already exists at
4865
 *               the destination and null if everything goes according to plan
4866
 */
4867
function copy_folder_course_session(
4868
    $pathname,
4869
    $base_path_document,
4870
    $session_id,
4871
    $course_info,
4872
    $document,
4873
    $source_course_id
4874
) {
4875
    $table = Database::get_course_table(TABLE_DOCUMENT);
4876
    $session_id = intval($session_id);
4877
    $source_course_id = intval($source_course_id);
4878
4879
    // Check whether directory already exists.
4880
    if (is_dir($pathname) || empty($pathname)) {
4881
        return true;
4882
    }
4883
4884
    // Ensure that a file with the same name does not already exist.
4885
    if (is_file($pathname)) {
4886
        trigger_error('copy_folder_course_session(): File exists', E_USER_WARNING);
4887
4888
        return false;
4889
    }
4890
4891
    $course_id = $course_info['real_id'];
4892
    $folders = explode(DIRECTORY_SEPARATOR, str_replace($base_path_document.DIRECTORY_SEPARATOR, '', $pathname));
4893
    $new_pathname = $base_path_document;
4894
    $path = '';
4895
4896
    foreach ($folders as $folder) {
4897
        $new_pathname .= DIRECTORY_SEPARATOR.$folder;
4898
        $path .= DIRECTORY_SEPARATOR.$folder;
4899
4900
        if (!file_exists($new_pathname)) {
4901
            $path = Database::escape_string($path);
4902
4903
            $sql = "SELECT * FROM $table
4904
                    WHERE
4905
                        c_id = $source_course_id AND
4906
                        path = '$path' AND
4907
                        filetype = 'folder' AND
4908
                        session_id = '$session_id'";
4909
            $rs1 = Database::query($sql);
4910
            $num_rows = Database::num_rows($rs1);
4911
4912
            if (0 == $num_rows) {
4913
                mkdir($new_pathname, api_get_permissions_for_new_directories());
4914
4915
                // Insert new folder with destination session_id.
4916
                $params = [
4917
                    'c_id' => $course_id,
4918
                    'path' => $path,
4919
                    'comment' => $document->comment,
4920
                    'title' => basename($new_pathname),
4921
                    'filetype' => 'folder',
4922
                    'size' => '0',
4923
                    'session_id' => $session_id,
4924
                ];
4925
                $document_id = Database::insert($table, $params);
4926
                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...
4927
4928
                    /*api_item_property_update(
4929
                        $course_info,
4930
                        TOOL_DOCUMENT,
4931
                        $document_id,
4932
                        'FolderCreated',
4933
                        api_get_user_id(),
4934
                        0,
4935
                        0,
4936
                        null,
4937
                        null,
4938
                        $session_id
4939
                    );*/
4940
                }
4941
            }
4942
        }
4943
    } // en foreach
4944
}
4945
4946
// TODO: chmodr() is a better name. Some corrections are needed. Documentation header to be added here.
4947
/**
4948
 * @param string $path
4949
 */
4950
function api_chmod_R($path, $filemode)
4951
{
4952
    if (!is_dir($path)) {
4953
        return chmod($path, $filemode);
4954
    }
4955
4956
    $handler = opendir($path);
4957
    while ($file = readdir($handler)) {
4958
        if ('.' != $file && '..' != $file) {
4959
            $fullpath = "$path/$file";
4960
            if (!is_dir($fullpath)) {
4961
                if (!chmod($fullpath, $filemode)) {
4962
                    return false;
4963
                }
4964
            } else {
4965
                if (!api_chmod_R($fullpath, $filemode)) {
4966
                    return false;
4967
                }
4968
            }
4969
        }
4970
    }
4971
4972
    closedir($handler);
4973
4974
    return chmod($path, $filemode);
4975
}
4976
4977
// TODO: Where the following function has been copy/pased from? There is no information about author and license. Style, coding conventions...
4978
/**
4979
 * Parse info file format. (e.g: file.info).
4980
 *
4981
 * Files should use an ini-like format to specify values.
4982
 * White-space generally doesn't matter, except inside values.
4983
 * e.g.
4984
 *
4985
 * @verbatim
4986
 *   key = value
4987
 *   key = "value"
4988
 *   key = 'value'
4989
 *   key = "multi-line
4990
 *
4991
 *   value"
4992
 *   key = 'multi-line
4993
 *
4994
 *   value'
4995
 *   key
4996
 *   =
4997
 *   'value'
4998
 * @endverbatim
4999
 *
5000
 * Arrays are created using a GET-like syntax:
5001
 *
5002
 * @verbatim
5003
 *   key[] = "numeric array"
5004
 *   key[index] = "associative array"
5005
 *   key[index][] = "nested numeric array"
5006
 *   key[index][index] = "nested associative array"
5007
 * @endverbatim
5008
 *
5009
 * PHP constants are substituted in, but only when used as the entire value:
5010
 *
5011
 * Comments should start with a semi-colon at the beginning of a line.
5012
 *
5013
 * This function is NOT for placing arbitrary module-specific settings. Use
5014
 * variable_get() and variable_set() for that.
5015
 *
5016
 * Information stored in the module.info file:
5017
 * - name: The real name of the module for display purposes.
5018
 * - description: A brief description of the module.
5019
 * - dependencies: An array of shortnames of other modules this module depends on.
5020
 * - package: The name of the package of modules this module belongs to.
5021
 *
5022
 * Example of .info file:
5023
 * <code>
5024
 * @verbatim
5025
 *   name = Forum
5026
 *   description = Enables threaded discussions about general topics.
5027
 *   dependencies[] = taxonomy
5028
 *   dependencies[] = comment
5029
 *   package = Core - optional
5030
 *   version = VERSION
5031
 * @endverbatim
5032
 * </code>
5033
 *
5034
 * @param string $filename
5035
 *                         The file we are parsing. Accepts file with relative or absolute path.
5036
 *
5037
 * @return
5038
 *   The info array
5039
 */
5040
function api_parse_info_file($filename)
5041
{
5042
    $info = [];
5043
5044
    if (!file_exists($filename)) {
5045
        return $info;
5046
    }
5047
5048
    $data = file_get_contents($filename);
5049
    if (preg_match_all('
5050
        @^\s*                           # Start at the beginning of a line, ignoring leading whitespace
5051
        ((?:
5052
          [^=;\[\]]|                    # Key names cannot contain equal signs, semi-colons or square brackets,
5053
          \[[^\[\]]*\]                  # unless they are balanced and not nested
5054
        )+?)
5055
        \s*=\s*                         # Key/value pairs are separated by equal signs (ignoring white-space)
5056
        (?:
5057
          ("(?:[^"]|(?<=\\\\)")*")|     # Double-quoted string, which may contain slash-escaped quotes/slashes
5058
          (\'(?:[^\']|(?<=\\\\)\')*\')| # Single-quoted string, which may contain slash-escaped quotes/slashes
5059
          ([^\r\n]*?)                   # Non-quoted string
5060
        )\s*$                           # Stop at the next end of a line, ignoring trailing whitespace
5061
        @msx', $data, $matches, PREG_SET_ORDER)) {
5062
        $key = $value1 = $value2 = $value3 = '';
5063
        foreach ($matches as $match) {
5064
            // Fetch the key and value string.
5065
            $i = 0;
5066
            foreach (['key', 'value1', 'value2', 'value3'] as $var) {
5067
                $$var = isset($match[++$i]) ? $match[$i] : '';
5068
            }
5069
            $value = stripslashes(substr($value1, 1, -1)).stripslashes(substr($value2, 1, -1)).$value3;
5070
5071
            // Parse array syntax.
5072
            $keys = preg_split('/\]?\[/', rtrim($key, ']'));
5073
            $last = array_pop($keys);
5074
            $parent = &$info;
5075
5076
            // Create nested arrays.
5077
            foreach ($keys as $key) {
5078
                if ('' == $key) {
5079
                    $key = count($parent);
5080
                }
5081
                if (!isset($parent[$key]) || !is_array($parent[$key])) {
5082
                    $parent[$key] = [];
5083
                }
5084
                $parent = &$parent[$key];
5085
            }
5086
5087
            // Handle PHP constants.
5088
            if (defined($value)) {
5089
                $value = constant($value);
5090
            }
5091
5092
            // Insert actual value.
5093
            if ('' == $last) {
5094
                $last = count($parent);
5095
            }
5096
            $parent[$last] = $value;
5097
        }
5098
    }
5099
5100
    return $info;
5101
}
5102
5103
/**
5104
 * Gets Chamilo version from the configuration files.
5105
 *
5106
 * @return string A string of type "1.8.4", or an empty string if the version could not be found
5107
 */
5108
function api_get_version()
5109
{
5110
    return (string) api_get_configuration_value('system_version');
5111
}
5112
5113
/**
5114
 * Gets the software name (the name/brand of the Chamilo-based customized system).
5115
 *
5116
 * @return string
5117
 */
5118
function api_get_software_name()
5119
{
5120
    $name = api_get_configuration_value('software_name');
5121
    if (!empty($name)) {
5122
        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...
5123
    } else {
5124
        return 'Chamilo';
5125
    }
5126
}
5127
5128
function api_get_status_list()
5129
{
5130
    $list = [];
5131
    // Table of status
5132
    $list[COURSEMANAGER] = 'teacher'; // 1
5133
    $list[SESSIONADMIN] = 'session_admin'; // 3
5134
    $list[DRH] = 'drh'; // 4
5135
    $list[STUDENT] = 'user'; // 5
5136
    $list[ANONYMOUS] = 'anonymous'; // 6
5137
    $list[INVITEE] = 'invited'; // 20
5138
5139
    return $list;
5140
}
5141
5142
/**
5143
 * Checks whether status given in parameter exists in the platform.
5144
 *
5145
 * @param mixed the status (can be either int either string)
5146
 *
5147
 * @return bool if the status exists, else returns false
5148
 */
5149
function api_status_exists($status_asked)
5150
{
5151
    $list = api_get_status_list();
5152
5153
    return in_array($status_asked, $list) ? true : isset($list[$status_asked]);
5154
}
5155
5156
/**
5157
 * Checks whether status given in parameter exists in the platform. The function
5158
 * returns the status ID or false if it does not exist, but given the fact there
5159
 * is no "0" status, the return value can be checked against
5160
 * if(api_status_key()) to know if it exists.
5161
 *
5162
 * @param   mixed   The status (can be either int or string)
5163
 *
5164
 * @return mixed Status ID if exists, false otherwise
5165
 */
5166
function api_status_key($status)
5167
{
5168
    $list = api_get_status_list();
5169
5170
    return isset($list[$status]) ? $status : array_search($status, $list);
5171
}
5172
5173
/**
5174
 * Gets the status langvars list.
5175
 *
5176
 * @return string[] the list of status with their translations
5177
 */
5178
function api_get_status_langvars()
5179
{
5180
    return [
5181
        COURSEMANAGER => get_lang('Teacher'),
5182
        SESSIONADMIN => get_lang('SessionsAdmin'),
5183
        DRH => get_lang('Human Resources Manager'),
5184
        STUDENT => get_lang('Learner'),
5185
        ANONYMOUS => get_lang('Anonymous'),
5186
        STUDENT_BOSS => get_lang('RoleStudentBoss'),
5187
        INVITEE => get_lang('Invited'),
5188
    ];
5189
}
5190
5191
/**
5192
 * The function that retrieves all the possible settings for a certain config setting.
5193
 *
5194
 * @author Patrick Cool <[email protected]>, Ghent University
5195
 */
5196
function api_get_settings_options($var)
5197
{
5198
    $table_settings_options = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
5199
    $var = Database::escape_string($var);
5200
    $sql = "SELECT * FROM $table_settings_options
5201
            WHERE variable = '$var'
5202
            ORDER BY id";
5203
    $result = Database::query($sql);
5204
    $settings_options_array = [];
5205
    while ($row = Database::fetch_array($result, 'ASSOC')) {
5206
        $settings_options_array[] = $row;
5207
    }
5208
5209
    return $settings_options_array;
5210
}
5211
5212
/**
5213
 * @param array $params
5214
 */
5215
function api_set_setting_option($params)
5216
{
5217
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
5218
    if (empty($params['id'])) {
5219
        Database::insert($table, $params);
5220
    } else {
5221
        Database::update($table, $params, ['id = ? ' => $params['id']]);
5222
    }
5223
}
5224
5225
/**
5226
 * @param array $params
5227
 */
5228
function api_set_setting_simple($params)
5229
{
5230
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5231
    $url_id = api_get_current_access_url_id();
5232
5233
    if (empty($params['id'])) {
5234
        $params['access_url'] = $url_id;
5235
        Database::insert($table, $params);
5236
    } else {
5237
        Database::update($table, $params, ['id = ? ' => [$params['id']]]);
5238
    }
5239
}
5240
5241
/**
5242
 * @param int $id
5243
 */
5244
function api_delete_setting_option($id)
5245
{
5246
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
5247
    if (!empty($id)) {
5248
        Database::delete($table, ['id = ? ' => $id]);
5249
    }
5250
}
5251
5252
/**
5253
 * Sets a platform configuration setting to a given value.
5254
 *
5255
 * @param string    The variable we want to update
5256
 * @param string    The value we want to record
5257
 * @param string    The sub-variable if any (in most cases, this will remain null)
5258
 * @param string    The category if any (in most cases, this will remain null)
5259
 * @param int       The access_url for which this parameter is valid
5260
 * @param string $cat
5261
 *
5262
 * @return bool|null
5263
 */
5264
function api_set_setting($var, $value, $subvar = null, $cat = null, $access_url = 1)
5265
{
5266
    if (empty($var)) {
5267
        return false;
5268
    }
5269
    $t_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5270
    $var = Database::escape_string($var);
5271
    $value = Database::escape_string($value);
5272
    $access_url = (int) $access_url;
5273
    if (empty($access_url)) {
5274
        $access_url = 1;
5275
    }
5276
    $select = "SELECT id FROM $t_settings WHERE variable = '$var' ";
5277
    if (!empty($subvar)) {
5278
        $subvar = Database::escape_string($subvar);
5279
        $select .= " AND subkey = '$subvar'";
5280
    }
5281
    if (!empty($cat)) {
5282
        $cat = Database::escape_string($cat);
5283
        $select .= " AND category = '$cat'";
5284
    }
5285
    if ($access_url > 1) {
5286
        $select .= " AND access_url = $access_url";
5287
    } else {
5288
        $select .= " AND access_url = 1 ";
5289
    }
5290
5291
    $res = Database::query($select);
5292
    if (Database::num_rows($res) > 0) {
5293
        // Found item for this access_url.
5294
        $row = Database::fetch_array($res);
5295
        $sql = "UPDATE $t_settings SET selected_value = '$value'
5296
                WHERE id = ".$row['id'];
5297
        Database::query($sql);
5298
    } else {
5299
        // Item not found for this access_url, we have to check if it exist with access_url = 1
5300
        $select = "SELECT * FROM $t_settings
5301
                   WHERE variable = '$var' AND access_url = 1 ";
5302
        // Just in case
5303
        if (1 == $access_url) {
5304
            if (!empty($subvar)) {
5305
                $select .= " AND subkey = '$subvar'";
5306
            }
5307
            if (!empty($cat)) {
5308
                $select .= " AND category = '$cat'";
5309
            }
5310
            $res = Database::query($select);
5311
            if (Database::num_rows($res) > 0) {
5312
                // We have a setting for access_url 1, but none for the current one, so create one.
5313
                $row = Database::fetch_array($res);
5314
                $insert = "INSERT INTO $t_settings (variable, subkey, type,category, selected_value, title, comment, scope, subkeytext, access_url)
5315
                        VALUES
5316
                        ('".$row['variable']."',".(!empty($row['subkey']) ? "'".$row['subkey']."'" : "NULL").",".
5317
                    "'".$row['type']."','".$row['category']."',".
5318
                    "'$value','".$row['title']."',".
5319
                    "".(!empty($row['comment']) ? "'".$row['comment']."'" : "NULL").",".(!empty($row['scope']) ? "'".$row['scope']."'" : "NULL").",".
5320
                    "".(!empty($row['subkeytext']) ? "'".$row['subkeytext']."'" : "NULL").",$access_url)";
5321
                Database::query($insert);
5322
            } else {
5323
                // Such a setting does not exist.
5324
                //error_log(__FILE__.':'.__LINE__.': Attempting to update setting '.$var.' ('.$subvar.') which does not exist at all', 0);
5325
            }
5326
        } else {
5327
            // Other access url.
5328
            if (!empty($subvar)) {
5329
                $select .= " AND subkey = '$subvar'";
5330
            }
5331
            if (!empty($cat)) {
5332
                $select .= " AND category = '$cat'";
5333
            }
5334
            $res = Database::query($select);
5335
5336
            if (Database::num_rows($res) > 0) {
5337
                // We have a setting for access_url 1, but none for the current one, so create one.
5338
                $row = Database::fetch_array($res);
5339
                if (1 == $row['access_url_changeable']) {
5340
                    $insert = "INSERT INTO $t_settings (variable,subkey, type,category, selected_value,title, comment,scope, subkeytext,access_url, access_url_changeable) VALUES
5341
                            ('".$row['variable']."',".
5342
                        (!empty($row['subkey']) ? "'".$row['subkey']."'" : "NULL").",".
5343
                        "'".$row['type']."','".$row['category']."',".
5344
                        "'$value','".$row['title']."',".
5345
                        "".(!empty($row['comment']) ? "'".$row['comment']."'" : "NULL").",".
5346
                        (!empty($row['scope']) ? "'".$row['scope']."'" : "NULL").",".
5347
                        "".(!empty($row['subkeytext']) ? "'".$row['subkeytext']."'" : "NULL").",$access_url,".$row['access_url_changeable'].")";
5348
                    Database::query($insert);
5349
                }
5350
            } else { // Such a setting does not exist.
5351
                //error_log(__FILE__.':'.__LINE__.': Attempting to update setting '.$var.' ('.$subvar.') which does not exist at all. The access_url is: '.$access_url.' ',0);
5352
            }
5353
        }
5354
    }
5355
}
5356
5357
/**
5358
 * Sets a whole category of settings to one specific value.
5359
 *
5360
 * @param string    Category
5361
 * @param string    Value
5362
 * @param int       Access URL. Optional. Defaults to 1
5363
 * @param array     Optional array of filters on field type
5364
 * @param string $category
5365
 * @param string $value
5366
 *
5367
 * @return bool
5368
 */
5369
function api_set_settings_category($category, $value = null, $access_url = 1, $fieldtype = [])
5370
{
5371
    if (empty($category)) {
5372
        return false;
5373
    }
5374
    $category = Database::escape_string($category);
5375
    $t_s = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5376
    $access_url = (int) $access_url;
5377
    if (empty($access_url)) {
5378
        $access_url = 1;
5379
    }
5380
    if (isset($value)) {
5381
        $value = Database::escape_string($value);
5382
        $sql = "UPDATE $t_s SET selected_value = '$value'
5383
                WHERE category = '$category' AND access_url = $access_url";
5384
        if (is_array($fieldtype) && count($fieldtype) > 0) {
5385
            $sql .= " AND ( ";
5386
            $i = 0;
5387
            foreach ($fieldtype as $type) {
5388
                if ($i > 0) {
5389
                    $sql .= ' OR ';
5390
                }
5391
                $type = Database::escape_string($type);
5392
                $sql .= " type='".$type."' ";
5393
                $i++;
5394
            }
5395
            $sql .= ")";
5396
        }
5397
        $res = Database::query($sql);
5398
5399
        return false !== $res;
5400
    } else {
5401
        $sql = "UPDATE $t_s SET selected_value = NULL
5402
                WHERE category = '$category' AND access_url = $access_url";
5403
        if (is_array($fieldtype) && count($fieldtype) > 0) {
5404
            $sql .= " AND ( ";
5405
            $i = 0;
5406
            foreach ($fieldtype as $type) {
5407
                if ($i > 0) {
5408
                    $sql .= ' OR ';
5409
                }
5410
                $type = Database::escape_string($type);
5411
                $sql .= " type='".$type."' ";
5412
                $i++;
5413
            }
5414
            $sql .= ")";
5415
        }
5416
        $res = Database::query($sql);
5417
5418
        return false !== $res;
5419
    }
5420
}
5421
5422
/**
5423
 * Gets all available access urls in an array (as in the database).
5424
 *
5425
 * @return array An array of database records
5426
 */
5427
function api_get_access_urls($from = 0, $to = 1000000, $order = 'url', $direction = 'ASC')
5428
{
5429
    $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5430
    $from = (int) $from;
5431
    $to = (int) $to;
5432
    $order = Database::escape_string($order, null, false);
5433
    $direction = Database::escape_string($direction, null, false);
5434
    $sql = "SELECT id, url, description, active, created_by, tms
5435
            FROM $table
5436
            ORDER BY $order $direction
5437
            LIMIT $to OFFSET $from";
5438
    $res = Database::query($sql);
5439
5440
    return Database::store_result($res);
5441
}
5442
5443
/**
5444
 * Gets the access url info in an array.
5445
 *
5446
 * @param int  $id            Id of the access url
5447
 * @param bool $returnDefault Set to false if you want the real URL if URL 1 is still 'http://localhost/'
5448
 *
5449
 * @return array All the info (url, description, active, created_by, tms)
5450
 *               from the access_url table
5451
 *
5452
 * @author Julio Montoya
5453
 */
5454
function api_get_access_url($id, $returnDefault = true)
5455
{
5456
    static $staticResult;
5457
    $id = (int) $id;
5458
5459
    if (isset($staticResult[$id])) {
5460
        $result = $staticResult[$id];
5461
    } else {
5462
        // Calling the Database:: library dont work this is handmade.
5463
        $table_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5464
        $sql = "SELECT url, description, active, created_by, tms
5465
                FROM $table_access_url WHERE id = '$id' ";
5466
        $res = Database::query($sql);
5467
        $result = @Database::fetch_array($res);
5468
        $staticResult[$id] = $result;
5469
    }
5470
5471
    // If the result url is 'http://localhost/' (the default) and the root_web
5472
    // (=current url) is different, and the $id is = 1 (which might mean
5473
    // api_get_current_access_url_id() returned 1 by default), then return the
5474
    // root_web setting instead of the current URL
5475
    // This is provided as an option to avoid breaking the storage of URL-specific
5476
    // homepages in home/localhost/
5477
    if (1 === $id && false === $returnDefault) {
5478
        $currentUrl = api_get_current_access_url_id();
5479
        // only do this if we are on the main URL (=1), otherwise we could get
5480
        // information on another URL instead of the one asked as parameter
5481
        if (1 === $currentUrl) {
5482
            $rootWeb = api_get_path(WEB_PATH);
5483
            $default = 'http://localhost/';
5484
            if ($result['url'] === $default && $rootWeb != $default) {
5485
                $result['url'] = $rootWeb;
5486
            }
5487
        }
5488
    }
5489
5490
    return $result;
5491
}
5492
5493
/**
5494
 * Gets all the current settings for a specific access url.
5495
 *
5496
 * @param string    The category, if any, that we want to get
5497
 * @param string    Whether we want a simple list (display a category) or
5498
 * a grouped list (group by variable as in settings.php default). Values: 'list' or 'group'
5499
 * @param int       Access URL's ID. Optional. Uses 1 by default, which is the unique URL
5500
 *
5501
 * @return array Array of database results for the current settings of the current access URL
5502
 */
5503
function &api_get_settings($cat = null, $ordering = 'list', $access_url = 1, $url_changeable = 0)
5504
{
5505
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5506
    $access_url = (int) $access_url;
5507
    $where_condition = '';
5508
    if (1 == $url_changeable) {
5509
        $where_condition = " AND access_url_changeable= '1' ";
5510
    }
5511
    if (empty($access_url) || -1 == $access_url) {
5512
        $access_url = 1;
5513
    }
5514
    $sql = "SELECT * FROM $table
5515
            WHERE access_url = $access_url  $where_condition ";
5516
5517
    if (!empty($cat)) {
5518
        $cat = Database::escape_string($cat);
5519
        $sql .= " AND category='$cat' ";
5520
    }
5521
    if ('group' == $ordering) {
5522
        $sql .= " ORDER BY id ASC";
5523
    } else {
5524
        $sql .= " ORDER BY 1,2 ASC";
5525
    }
5526
    $result = Database::query($sql);
5527
    if (null === $result) {
5528
        return [];
5529
    }
5530
    $result = Database::store_result($result, 'ASSOC');
5531
5532
    return $result;
5533
}
5534
5535
/**
5536
 * @param string $value       The value we want to record
5537
 * @param string $variable    The variable name we want to insert
5538
 * @param string $subKey      The subkey for the variable we want to insert
5539
 * @param string $type        The type for the variable we want to insert
5540
 * @param string $category    The category for the variable we want to insert
5541
 * @param string $title       The title
5542
 * @param string $comment     The comment
5543
 * @param string $scope       The scope
5544
 * @param string $subKeyText  The subkey text
5545
 * @param int    $accessUrlId The access_url for which this parameter is valid
5546
 * @param int    $visibility  The changeability of this setting for non-master urls
5547
 *
5548
 * @return int The setting ID
5549
 */
5550
function api_add_setting(
5551
    $value,
5552
    $variable,
5553
    $subKey = '',
5554
    $type = 'textfield',
5555
    $category = '',
5556
    $title = '',
5557
    $comment = '',
5558
    $scope = '',
5559
    $subKeyText = '',
5560
    $accessUrlId = 1,
5561
    $visibility = 0
5562
) {
5563
    $em = Database::getManager();
5564
5565
    $settingRepo = $em->getRepository(SettingsCurrent::class);
5566
    $accessUrlId = (int) $accessUrlId ?: 1;
5567
5568
    if (is_array($value)) {
5569
        $value = serialize($value);
5570
    } else {
5571
        $value = trim($value);
5572
    }
5573
5574
    $criteria = ['variable' => $variable, 'url' => $accessUrlId];
5575
5576
    if (!empty($subKey)) {
5577
        $criteria['subkey'] = $subKey;
5578
    }
5579
5580
    // Check if this variable doesn't exist already
5581
    /** @var SettingsCurrent $setting */
5582
    $setting = $settingRepo->findOneBy($criteria);
5583
5584
    if ($setting) {
0 ignored issues
show
introduced by
$setting is of type Chamilo\CoreBundle\Entity\SettingsCurrent, thus it always evaluated to true.
Loading history...
5585
        $setting->setSelectedValue($value);
5586
5587
        $em->persist($setting);
5588
        $em->flush();
5589
5590
        return $setting->getId();
5591
    }
5592
5593
    // Item not found for this access_url, we have to check if the whole thing is missing
5594
    // (in which case we ignore the insert) or if there *is* a record but just for access_url = 1
5595
    $setting = new SettingsCurrent();
5596
    $url = api_get_url_entity();
5597
5598
    $setting
5599
        ->setVariable($variable)
5600
        ->setSelectedValue($value)
5601
        ->setType($type)
5602
        ->setCategory($category)
5603
        ->setSubkey($subKey)
5604
        ->setTitle($title)
5605
        ->setComment($comment)
5606
        ->setScope($scope)
5607
        ->setSubkeytext($subKeyText)
5608
        ->setUrl(api_get_url_entity())
5609
        ->setAccessUrlChangeable($visibility);
5610
5611
    $em->persist($setting);
5612
    $em->flush();
5613
5614
    return $setting->getId();
5615
}
5616
5617
/**
5618
 * Checks wether a user can or can't view the contents of a course.
5619
 *
5620
 * @deprecated use CourseManager::is_user_subscribed_in_course
5621
 *
5622
 * @param int $userid User id or NULL to get it from $_SESSION
5623
 * @param int $cid    course id to check whether the user is allowed
5624
 *
5625
 * @return bool
5626
 */
5627
function api_is_course_visible_for_user($userid = null, $cid = null)
5628
{
5629
    if (null === $userid) {
5630
        $userid = api_get_user_id();
5631
    }
5632
    if (empty($userid) || strval(intval($userid)) != $userid) {
5633
        if (api_is_anonymous()) {
5634
            $userid = api_get_anonymous_id();
5635
        } else {
5636
            return false;
5637
        }
5638
    }
5639
    $cid = Database::escape_string($cid);
5640
5641
    $courseInfo = api_get_course_info($cid);
5642
    $courseId = $courseInfo['real_id'];
5643
    $is_platformAdmin = api_is_platform_admin();
5644
5645
    $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
5646
    $course_cat_table = Database::get_main_table(TABLE_MAIN_CATEGORY);
5647
5648
    $sql = "SELECT
5649
                $course_cat_table.code AS category_code,
5650
                $course_table.visibility,
5651
                $course_table.code,
5652
                $course_cat_table.code
5653
            FROM $course_table
5654
            LEFT JOIN $course_cat_table
5655
                ON $course_table.category_id = $course_cat_table.id
5656
            WHERE
5657
                $course_table.code = '$cid'
5658
            LIMIT 1";
5659
5660
    $result = Database::query($sql);
5661
5662
    if (Database::num_rows($result) > 0) {
5663
        $visibility = Database::fetch_array($result);
5664
        $visibility = $visibility['visibility'];
5665
    } else {
5666
        $visibility = 0;
5667
    }
5668
    // Shortcut permissions in case the visibility is "open to the world".
5669
    if (COURSE_VISIBILITY_OPEN_WORLD === $visibility) {
5670
        return true;
5671
    }
5672
5673
    $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
5674
5675
    $sql = "SELECT
5676
                is_tutor, status
5677
            FROM $tbl_course_user
5678
            WHERE
5679
                user_id  = '$userid' AND
5680
                relation_type <> '".COURSE_RELATION_TYPE_RRHH."' AND
5681
                c_id = $courseId
5682
            LIMIT 1";
5683
5684
    $result = Database::query($sql);
5685
5686
    if (Database::num_rows($result) > 0) {
5687
        // This user has got a recorded state for this course.
5688
        $cuData = Database::fetch_array($result);
5689
        $is_courseMember = true;
5690
        $is_courseAdmin = (1 == $cuData['status']);
5691
    }
5692
5693
    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...
5694
        // This user has no status related to this course.
5695
        // Is it the session coach or the session admin?
5696
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
5697
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
5698
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
5699
5700
        $sql = "SELECT
5701
                    session.id_coach, session_admin_id, session.id
5702
                FROM
5703
                    $tbl_session as session
5704
                INNER JOIN $tbl_session_course
5705
                    ON session_rel_course.session_id = session.id
5706
                    AND session_rel_course.c_id = '$courseId'
5707
                LIMIT 1";
5708
5709
        $result = Database::query($sql);
5710
        $row = Database::store_result($result);
5711
5712
        if ($row[0]['id_coach'] == $userid) {
5713
            $is_courseMember = true;
5714
            $is_courseAdmin = false;
5715
        } elseif ($row[0]['session_admin_id'] == $userid) {
5716
            $is_courseMember = false;
5717
            $is_courseAdmin = false;
5718
        } else {
5719
            // Check if the current user is the course coach.
5720
            $sql = "SELECT 1
5721
                    FROM $tbl_session_course
5722
                    WHERE session_rel_course.c_id = '$courseId'
5723
                    AND session_rel_course.id_coach = '$userid'
5724
                    LIMIT 1";
5725
5726
            $result = Database::query($sql);
5727
5728
            //if ($row = Database::fetch_array($result)) {
5729
            if (Database::num_rows($result) > 0) {
5730
                $is_courseMember = true;
5731
                $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
5732
5733
                $sql = "SELECT status FROM $tbl_user
5734
                        WHERE user_id = $userid
5735
                        LIMIT 1";
5736
5737
                $result = Database::query($sql);
5738
5739
                if (1 == Database::result($result, 0, 0)) {
5740
                    $is_courseAdmin = true;
5741
                } else {
5742
                    $is_courseAdmin = false;
5743
                }
5744
            } else {
5745
                // Check if the user is a student is this session.
5746
                $sql = "SELECT  id
5747
                        FROM $tbl_session_course_user
5748
                        WHERE
5749
                            user_id  = '$userid' AND
5750
                            c_id = '$courseId'
5751
                        LIMIT 1";
5752
5753
                if (Database::num_rows($result) > 0) {
5754
                    // This user haa got a recorded state for this course.
5755
                    while ($row = Database::fetch_array($result)) {
5756
                        $is_courseMember = true;
5757
                        $is_courseAdmin = false;
5758
                    }
5759
                }
5760
            }
5761
        }
5762
    }
5763
5764
    switch ($visibility) {
5765
        case COURSE_VISIBILITY_OPEN_WORLD:
5766
            return true;
5767
        case COURSE_VISIBILITY_OPEN_PLATFORM:
5768
            return isset($userid);
5769
        case COURSE_VISIBILITY_REGISTERED:
5770
        case COURSE_VISIBILITY_CLOSED:
5771
            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...
5772
        case COURSE_VISIBILITY_HIDDEN:
5773
            return $is_platformAdmin;
5774
    }
5775
5776
    return false;
5777
}
5778
5779
/**
5780
 * Returns whether an element (forum, message, survey ...) belongs to a session or not.
5781
 *
5782
 * @param string the tool of the element
5783
 * @param int the element id in database
5784
 * @param int the session_id to compare with element session id
5785
 *
5786
 * @return bool true if the element is in the session, false else
5787
 */
5788
function api_is_element_in_the_session($tool, $element_id, $session_id = null)
5789
{
5790
    if (is_null($session_id)) {
5791
        $session_id = api_get_session_id();
5792
    }
5793
5794
    $element_id = (int) $element_id;
5795
5796
    if (empty($element_id)) {
5797
        return false;
5798
    }
5799
5800
    // Get information to build query depending of the tool.
5801
    switch ($tool) {
5802
        case TOOL_SURVEY:
5803
            $table_tool = Database::get_course_table(TABLE_SURVEY);
5804
            $key_field = 'survey_id';
5805
            break;
5806
        case TOOL_ANNOUNCEMENT:
5807
            $table_tool = Database::get_course_table(TABLE_ANNOUNCEMENT);
5808
            $key_field = 'id';
5809
            break;
5810
        case TOOL_AGENDA:
5811
            $table_tool = Database::get_course_table(TABLE_AGENDA);
5812
            $key_field = 'id';
5813
            break;
5814
        case TOOL_GROUP:
5815
            $table_tool = Database::get_course_table(TABLE_GROUP);
5816
            $key_field = 'id';
5817
            break;
5818
        default:
5819
            return false;
5820
    }
5821
    $course_id = api_get_course_int_id();
5822
5823
    $sql = "SELECT session_id FROM $table_tool
5824
            WHERE c_id = $course_id AND $key_field =  ".$element_id;
5825
    $rs = Database::query($sql);
5826
    if ($element_session_id = Database::result($rs, 0, 0)) {
5827
        if ($element_session_id == intval($session_id)) {
5828
            // The element belongs to the session.
5829
            return true;
5830
        }
5831
    }
5832
5833
    return false;
5834
}
5835
5836
/**
5837
 * Replaces "forbidden" characters in a filename string.
5838
 *
5839
 * @param string $filename
5840
 * @param bool   $treat_spaces_as_hyphens
5841
 *
5842
 * @return string
5843
 */
5844
function api_replace_dangerous_char($filename, $treat_spaces_as_hyphens = true)
5845
{
5846
    // Some non-properly encoded file names can cause the whole file to be
5847
    // skipped when uploaded. Avoid this by detecting the encoding and
5848
    // converting to UTF-8, setting the source as ASCII (a reasonably
5849
    // limited characters set) if nothing could be found (BT#
5850
    $encoding = api_detect_encoding($filename);
5851
    if (empty($encoding)) {
5852
        $encoding = 'ASCII';
5853
        if (!api_is_valid_ascii($filename)) {
5854
            // try iconv and try non standard ASCII a.k.a CP437
5855
            // see BT#15022
5856
            if (function_exists('iconv')) {
5857
                $result = iconv('CP437', 'UTF-8', $filename);
5858
                if (api_is_valid_utf8($result)) {
5859
                    $filename = $result;
5860
                    $encoding = 'UTF-8';
5861
                }
5862
            }
5863
        }
5864
    }
5865
5866
    $filename = api_to_system_encoding($filename, $encoding);
5867
5868
    $url = URLify::filter(
5869
        $filename,
5870
        250,
5871
        '',
5872
        true,
5873
        false,
5874
        false,
5875
        false
5876
    );
5877
5878
    return $url;
5879
}
5880
5881
/**
5882
 * Fixes the $_SERVER['REQUEST_URI'] that is empty in IIS6.
5883
 *
5884
 * @author Ivan Tcholakov, 28-JUN-2006.
5885
 */
5886
function api_request_uri()
5887
{
5888
    if (!empty($_SERVER['REQUEST_URI'])) {
5889
        return $_SERVER['REQUEST_URI'];
5890
    }
5891
    $uri = $_SERVER['SCRIPT_NAME'];
5892
    if (!empty($_SERVER['QUERY_STRING'])) {
5893
        $uri .= '?'.$_SERVER['QUERY_STRING'];
5894
    }
5895
    $_SERVER['REQUEST_URI'] = $uri;
5896
5897
    return $uri;
5898
}
5899
5900
/** Gets the current access_url id of the Chamilo Platform.
5901
 * @author Julio Montoya <[email protected]>
5902
 *
5903
 * @return int access_url_id of the current Chamilo Installation
5904
 */
5905
function api_get_current_access_url_id()
5906
{
5907
    if (false === api_get_multiple_access_url()) {
5908
        return 1;
5909
    }
5910
5911
    static $id;
5912
    if (!empty($id)) {
5913
        return $id;
5914
    }
5915
5916
    $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5917
    $path = Database::escape_string(api_get_path(WEB_PATH));
5918
    $sql = "SELECT id FROM $table WHERE url = '".$path."'";
5919
    $result = Database::query($sql);
5920
    if (Database::num_rows($result) > 0) {
5921
        $id = Database::result($result, 0, 0);
5922
        if (false === $id) {
5923
            return -1;
5924
        }
5925
5926
        return (int) $id;
5927
    }
5928
5929
    $id = 1;
5930
5931
    //if the url in WEB_PATH was not found, it can only mean that there is
5932
    // either a configuration problem or the first URL has not been defined yet
5933
    // (by default it is http://localhost/). Thus the more sensible thing we can
5934
    // do is return 1 (the main URL) as the user cannot hack this value anyway
5935
    return 1;
5936
}
5937
5938
/**
5939
 * Gets the registered urls from a given user id.
5940
 *
5941
 * @author Julio Montoya <[email protected]>
5942
 *
5943
 * @param int $user_id
5944
 *
5945
 * @return array
5946
 */
5947
function api_get_access_url_from_user($user_id)
5948
{
5949
    $user_id = (int) $user_id;
5950
    $table_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
5951
    $table_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5952
    $sql = "SELECT access_url_id
5953
            FROM $table_url_rel_user url_rel_user
5954
            INNER JOIN $table_url u
5955
            ON (url_rel_user.access_url_id = u.id)
5956
            WHERE user_id = ".$user_id;
5957
    $result = Database::query($sql);
5958
    $list = [];
5959
    while ($row = Database::fetch_array($result, 'ASSOC')) {
5960
        $list[] = $row['access_url_id'];
5961
    }
5962
5963
    return $list;
5964
}
5965
5966
/**
5967
 * Checks whether the curent user is in a group or not.
5968
 *
5969
 * @param string        The group id - optional (takes it from session if not given)
5970
 * @param string        The course code - optional (no additional check by course if course code is not given)
5971
 *
5972
 * @return bool
5973
 *
5974
 * @author Ivan Tcholakov
5975
 */
5976
function api_is_in_group($groupIdParam = null, $courseCodeParam = null)
5977
{
5978
    if (!empty($courseCodeParam)) {
5979
        $courseCode = api_get_course_id();
5980
        if (!empty($courseCode)) {
5981
            if ($courseCodeParam != $courseCode) {
5982
                return false;
5983
            }
5984
        } else {
5985
            return false;
5986
        }
5987
    }
5988
5989
    $groupId = api_get_group_id();
5990
5991
    if (isset($groupId) && '' != $groupId) {
5992
        if (!empty($groupIdParam)) {
5993
            return $groupIdParam == $groupId;
5994
        } else {
5995
            return true;
5996
        }
5997
    }
5998
5999
    return false;
6000
}
6001
6002
/**
6003
 * Checks whether a secret key is valid.
6004
 *
6005
 * @param string $original_key_secret - secret key from (webservice) client
6006
 * @param string $security_key        - security key from Chamilo
6007
 *
6008
 * @return bool - true if secret key is valid, false otherwise
6009
 */
6010
function api_is_valid_secret_key($original_key_secret, $security_key)
6011
{
6012
    return $original_key_secret == sha1($security_key);
6013
}
6014
6015
/**
6016
 * Checks whether a user is into course.
6017
 *
6018
 * @param int $course_id - the course id
6019
 * @param int $user_id   - the user id
6020
 *
6021
 * @return bool
6022
 */
6023
function api_is_user_of_course($course_id, $user_id)
6024
{
6025
    $tbl_course_rel_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
6026
    $sql = 'SELECT user_id FROM '.$tbl_course_rel_user.'
6027
            WHERE
6028
                c_id ="'.intval($course_id).'" AND
6029
                user_id = "'.intval($user_id).'" AND
6030
                relation_type <> '.COURSE_RELATION_TYPE_RRHH.' ';
6031
    $result = Database::query($sql);
6032
6033
    return 1 == Database::num_rows($result);
6034
}
6035
6036
/**
6037
 * Checks whether the server's operating system is Windows (TM).
6038
 *
6039
 * @return bool - true if the operating system is Windows, false otherwise
6040
 */
6041
function api_is_windows_os()
6042
{
6043
    if (function_exists('php_uname')) {
6044
        // php_uname() exists as of PHP 4.0.2, according to the documentation.
6045
        // We expect that this function will always work for Chamilo 1.8.x.
6046
        $os = php_uname();
6047
    }
6048
    // The following methods are not needed, but let them stay, just in case.
6049
    elseif (isset($_ENV['OS'])) {
6050
        // Sometimes $_ENV['OS'] may not be present (bugs?)
6051
        $os = $_ENV['OS'];
6052
    } elseif (defined('PHP_OS')) {
6053
        // PHP_OS means on which OS PHP was compiled, this is why
6054
        // using PHP_OS is the last choice for detection.
6055
        $os = PHP_OS;
6056
    } else {
6057
        return false;
6058
    }
6059
6060
    return 'win' == strtolower(substr((string) $os, 0, 3));
6061
}
6062
6063
/**
6064
 * This function informs whether the sent request is XMLHttpRequest.
6065
 */
6066
function api_is_xml_http_request()
6067
{
6068
    return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && 'xmlhttprequest' == strtolower($_SERVER['HTTP_X_REQUESTED_WITH']);
6069
}
6070
6071
/**
6072
 * This wrapper function has been implemented for avoiding some known problems about the function getimagesize().
6073
 *
6074
 * @see http://php.net/manual/en/function.getimagesize.php
6075
 * @see http://www.dokeos.com/forum/viewtopic.php?t=12345
6076
 * @see http://www.dokeos.com/forum/viewtopic.php?t=16355
6077
 *
6078
 * @return int
6079
 */
6080
function api_getimagesize($path)
6081
{
6082
    $image = new Image($path);
0 ignored issues
show
Deprecated Code introduced by
The class Image has been deprecated. ( Ignorable by Annotation )

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

6082
    $image = /** @scrutinizer ignore-deprecated */ new Image($path);
Loading history...
6083
6084
    return $image->get_image_size();
6085
}
6086
6087
/**
6088
 * This function resizes an image, with preserving its proportions (or aspect ratio).
6089
 *
6090
 * @author Ivan Tcholakov, MAY-2009.
6091
 *
6092
 * @param int $image         System path or URL of the image
6093
 * @param int $target_width  Targeted width
6094
 * @param int $target_height Targeted height
6095
 *
6096
 * @return array Calculated new width and height
6097
 */
6098
function api_resize_image($image, $target_width, $target_height)
6099
{
6100
    $image_properties = api_getimagesize($image);
6101
6102
    return api_calculate_image_size(
6103
        $image_properties['width'],
6104
        $image_properties['height'],
6105
        $target_width,
6106
        $target_height
6107
    );
6108
}
6109
6110
/**
6111
 * This function calculates new image size, with preserving image's proportions (or aspect ratio).
6112
 *
6113
 * @author Ivan Tcholakov, MAY-2009.
6114
 * @author The initial idea has been taken from code by Patrick Cool, MAY-2004.
6115
 *
6116
 * @param int $image_width   Initial width
6117
 * @param int $image_height  Initial height
6118
 * @param int $target_width  Targeted width
6119
 * @param int $target_height Targeted height
6120
 *
6121
 * @return array Calculated new width and height
6122
 */
6123
function api_calculate_image_size(
6124
    $image_width,
6125
    $image_height,
6126
    $target_width,
6127
    $target_height
6128
) {
6129
    // Only maths is here.
6130
    $result = ['width' => $image_width, 'height' => $image_height];
6131
    if ($image_width <= 0 || $image_height <= 0) {
6132
        return $result;
6133
    }
6134
    $resize_factor_width = $target_width / $image_width;
6135
    $resize_factor_height = $target_height / $image_height;
6136
    $delta_width = $target_width - $image_width * $resize_factor_height;
6137
    $delta_height = $target_height - $image_height * $resize_factor_width;
6138
    if ($delta_width > $delta_height) {
6139
        $result['width'] = ceil($image_width * $resize_factor_height);
6140
        $result['height'] = ceil($image_height * $resize_factor_height);
6141
    } elseif ($delta_width < $delta_height) {
6142
        $result['width'] = ceil($image_width * $resize_factor_width);
6143
        $result['height'] = ceil($image_height * $resize_factor_width);
6144
    } else {
6145
        $result['width'] = ceil($target_width);
6146
        $result['height'] = ceil($target_height);
6147
    }
6148
6149
    return $result;
6150
}
6151
6152
/**
6153
 * Returns a list of Chamilo's tools or
6154
 * checks whether a given identificator is a valid Chamilo's tool.
6155
 *
6156
 * @author Isaac flores paz
6157
 *
6158
 * @param string The tool name to filter
6159
 *
6160
 * @return mixed Filtered string or array
6161
 */
6162
function api_get_tools_lists($my_tool = null)
6163
{
6164
    $tools_list = [
6165
        TOOL_DOCUMENT,
6166
        TOOL_THUMBNAIL,
6167
        TOOL_HOTPOTATOES,
6168
        TOOL_CALENDAR_EVENT,
6169
        TOOL_LINK,
6170
        TOOL_COURSE_DESCRIPTION,
6171
        TOOL_SEARCH,
6172
        TOOL_LEARNPATH,
6173
        TOOL_ANNOUNCEMENT,
6174
        TOOL_FORUM,
6175
        TOOL_THREAD,
6176
        TOOL_POST,
6177
        TOOL_DROPBOX,
6178
        TOOL_QUIZ,
6179
        TOOL_USER,
6180
        TOOL_GROUP,
6181
        TOOL_BLOGS,
6182
        TOOL_CHAT,
6183
        TOOL_STUDENTPUBLICATION,
6184
        TOOL_TRACKING,
6185
        TOOL_HOMEPAGE_LINK,
6186
        TOOL_COURSE_SETTING,
6187
        TOOL_BACKUP,
6188
        TOOL_COPY_COURSE_CONTENT,
6189
        TOOL_RECYCLE_COURSE,
6190
        TOOL_COURSE_HOMEPAGE,
6191
        TOOL_COURSE_RIGHTS_OVERVIEW,
6192
        TOOL_UPLOAD,
6193
        TOOL_COURSE_MAINTENANCE,
6194
        TOOL_SURVEY,
6195
        TOOL_WIKI,
6196
        TOOL_GLOSSARY,
6197
        TOOL_GRADEBOOK,
6198
        TOOL_NOTEBOOK,
6199
        TOOL_ATTENDANCE,
6200
        TOOL_COURSE_PROGRESS,
6201
    ];
6202
    if (empty($my_tool)) {
6203
        return $tools_list;
6204
    }
6205
6206
    return in_array($my_tool, $tools_list) ? $my_tool : '';
6207
}
6208
6209
/**
6210
 * Checks whether we already approved the last version term and condition.
6211
 *
6212
 * @param int user id
6213
 *
6214
 * @return bool true if we pass false otherwise
6215
 */
6216
function api_check_term_condition($userId)
6217
{
6218
    if ('true' === api_get_setting('allow_terms_conditions')) {
6219
        // Check if exists terms and conditions
6220
        if (0 == LegalManager::count()) {
6221
            return true;
6222
        }
6223
6224
        $extraFieldValue = new ExtraFieldValue('user');
6225
        $data = $extraFieldValue->get_values_by_handler_and_field_variable(
6226
            $userId,
6227
            'legal_accept'
6228
        );
6229
6230
        if (!empty($data) && isset($data['value']) && !empty($data['value'])) {
6231
            $result = $data['value'];
6232
            $user_conditions = explode(':', $result);
6233
            $version = $user_conditions[0];
6234
            $langId = $user_conditions[1];
6235
            $realVersion = LegalManager::get_last_version($langId);
6236
6237
            return $version >= $realVersion;
6238
        }
6239
6240
        return false;
6241
    }
6242
6243
    return false;
6244
}
6245
6246
/**
6247
 * Gets all information of a tool into course.
6248
 *
6249
 * @param int The tool id
6250
 *
6251
 * @return array
6252
 */
6253
function api_get_tool_information_by_name($name)
6254
{
6255
    $t_tool = Database::get_course_table(TABLE_TOOL_LIST);
6256
    $course_id = api_get_course_int_id();
6257
6258
    $sql = "SELECT id FROM tool
6259
            WHERE name = '".Database::escape_string($name)."' ";
6260
    $rs = Database::query($sql);
6261
    $data = Database::fetch_array($rs);
6262
    $tool = $data['id'];
6263
6264
    $sql = "SELECT * FROM $t_tool
6265
            WHERE c_id = $course_id  AND tool_id = '".$tool."' ";
6266
    $rs = Database::query($sql);
6267
6268
    return Database::fetch_array($rs, 'ASSOC');
6269
}
6270
6271
/**
6272
 * Function used to protect a "global" admin script.
6273
 * The function blocks access when the user has no global platform admin rights.
6274
 * Global admins are the admins that are registered in the main.admin table
6275
 * AND the users who have access to the "principal" portal.
6276
 * That means that there is a record in the main.access_url_rel_user table
6277
 * with his user id and the access_url_id=1.
6278
 *
6279
 * @author Julio Montoya
6280
 *
6281
 * @param int $user_id
6282
 *
6283
 * @return bool
6284
 */
6285
function api_is_global_platform_admin($user_id = null)
6286
{
6287
    $user_id = (int) $user_id;
6288
    if (empty($user_id)) {
6289
        $user_id = api_get_user_id();
6290
    }
6291
    if (api_is_platform_admin_by_id($user_id)) {
6292
        $urlList = api_get_access_url_from_user($user_id);
6293
        // The admin is registered in the first "main" site with access_url_id = 1
6294
        if (in_array(1, $urlList)) {
6295
            return true;
6296
        } else {
6297
            return false;
6298
        }
6299
    }
6300
6301
    return false;
6302
}
6303
6304
/**
6305
 * @param int  $admin_id_to_check
6306
 * @param int  $my_user_id
6307
 * @param bool $allow_session_admin
6308
 *
6309
 * @return bool
6310
 */
6311
function api_global_admin_can_edit_admin(
6312
    $admin_id_to_check,
6313
    $my_user_id = null,
6314
    $allow_session_admin = false
6315
) {
6316
    if (empty($my_user_id)) {
6317
        $my_user_id = api_get_user_id();
6318
    }
6319
6320
    $iam_a_global_admin = api_is_global_platform_admin($my_user_id);
6321
    $user_is_global_admin = api_is_global_platform_admin($admin_id_to_check);
6322
6323
    if ($iam_a_global_admin) {
6324
        // Global admin can edit everything
6325
        return true;
6326
    } else {
6327
        // If i'm a simple admin
6328
        $is_platform_admin = api_is_platform_admin_by_id($my_user_id);
6329
6330
        if ($allow_session_admin) {
6331
            $is_platform_admin = api_is_platform_admin_by_id($my_user_id) || (SESSIONADMIN == api_get_user_status($my_user_id));
6332
        }
6333
6334
        if ($is_platform_admin) {
6335
            if ($user_is_global_admin) {
6336
                return false;
6337
            } else {
6338
                return true;
6339
            }
6340
        } else {
6341
            return false;
6342
        }
6343
    }
6344
}
6345
6346
/**
6347
 * @param int  $admin_id_to_check
6348
 * @param int  $my_user_id
6349
 * @param bool $allow_session_admin
6350
 *
6351
 * @return bool|null
6352
 */
6353
function api_protect_super_admin($admin_id_to_check, $my_user_id = null, $allow_session_admin = false)
6354
{
6355
    if (api_global_admin_can_edit_admin($admin_id_to_check, $my_user_id, $allow_session_admin)) {
6356
        return true;
6357
    } else {
6358
        api_not_allowed();
6359
    }
6360
}
6361
6362
/**
6363
 * Function used to protect a global admin script.
6364
 * The function blocks access when the user has no global platform admin rights.
6365
 * See also the api_is_global_platform_admin() function wich defines who's a "global" admin.
6366
 *
6367
 * @author Julio Montoya
6368
 */
6369
function api_protect_global_admin_script()
6370
{
6371
    if (!api_is_global_platform_admin()) {
6372
        api_not_allowed();
6373
6374
        return false;
6375
    }
6376
6377
    return true;
6378
}
6379
6380
/**
6381
 * Check browser support for specific file types or features
6382
 * This function checks if the user's browser supports a file format or given
6383
 * feature, or returns the current browser and major version when
6384
 * $format=check_browser. Only a limited number of formats and features are
6385
 * checked by this method. Make sure you check its definition first.
6386
 *
6387
 * @param string $format Can be a file format (extension like svg, webm, ...) or a feature (like autocapitalize, ...)
6388
 *
6389
 * @deprecated
6390
 *
6391
 * @return bool or return text array if $format=check_browser
6392
 *
6393
 * @author Juan Carlos Raña Trabado
6394
 */
6395
function api_browser_support($format = '')
6396
{
6397
    return true;
6398
6399
    $browser = new Browser();
0 ignored issues
show
Unused Code introduced by
$browser = new Browser() 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...
6400
    $current_browser = $browser->getBrowser();
6401
    $a_versiontemp = explode('.', $browser->getVersion());
6402
    $current_majorver = $a_versiontemp[0];
6403
6404
    static $result;
6405
6406
    if (isset($result[$format])) {
6407
        return $result[$format];
6408
    }
6409
6410
    // Native svg support
6411
    if ('svg' == $format) {
6412
        if (('Internet Explorer' == $current_browser && $current_majorver >= 9) ||
6413
            ('Firefox' == $current_browser && $current_majorver > 1) ||
6414
            ('Safari' == $current_browser && $current_majorver >= 4) ||
6415
            ('Chrome' == $current_browser && $current_majorver >= 1) ||
6416
            ('Opera' == $current_browser && $current_majorver >= 9)
6417
        ) {
6418
            $result[$format] = true;
6419
6420
            return true;
6421
        } else {
6422
            $result[$format] = false;
6423
6424
            return false;
6425
        }
6426
    } elseif ('pdf' == $format) {
6427
        // native pdf support
6428
        if ('Chrome' == $current_browser && $current_majorver >= 6) {
6429
            $result[$format] = true;
6430
6431
            return true;
6432
        } else {
6433
            $result[$format] = false;
6434
6435
            return false;
6436
        }
6437
    } elseif ('tif' == $format || 'tiff' == $format) {
6438
        //native tif support
6439
        if ('Safari' == $current_browser && $current_majorver >= 5) {
6440
            $result[$format] = true;
6441
6442
            return true;
6443
        } else {
6444
            $result[$format] = false;
6445
6446
            return false;
6447
        }
6448
    } elseif ('ogg' == $format || 'ogx' == $format || 'ogv' == $format || 'oga' == $format) {
6449
        //native ogg, ogv,oga support
6450
        if (('Firefox' == $current_browser && $current_majorver >= 3) ||
6451
            ('Chrome' == $current_browser && $current_majorver >= 3) ||
6452
            ('Opera' == $current_browser && $current_majorver >= 9)) {
6453
            $result[$format] = true;
6454
6455
            return true;
6456
        } else {
6457
            $result[$format] = false;
6458
6459
            return false;
6460
        }
6461
    } elseif ('mpg' == $format || 'mpeg' == $format) {
6462
        //native mpg support
6463
        if (('Safari' == $current_browser && $current_majorver >= 5)) {
6464
            $result[$format] = true;
6465
6466
            return true;
6467
        } else {
6468
            $result[$format] = false;
6469
6470
            return false;
6471
        }
6472
    } elseif ('mp4' == $format) {
6473
        //native mp4 support (TODO: Android, iPhone)
6474
        if ('Android' == $current_browser || 'iPhone' == $current_browser) {
6475
            $result[$format] = true;
6476
6477
            return true;
6478
        } else {
6479
            $result[$format] = false;
6480
6481
            return false;
6482
        }
6483
    } elseif ('mov' == $format) {
6484
        //native mov support( TODO:check iPhone)
6485
        if ('Safari' == $current_browser && $current_majorver >= 5 || 'iPhone' == $current_browser) {
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: ('Safari' == $current_br...ne' == $current_browser, Probably Intended Meaning: 'Safari' == $current_bro...e' == $current_browser)
Loading history...
6486
            $result[$format] = true;
6487
6488
            return true;
6489
        } else {
6490
            $result[$format] = false;
6491
6492
            return false;
6493
        }
6494
    } elseif ('avi' == $format) {
6495
        //native avi support
6496
        if ('Safari' == $current_browser && $current_majorver >= 5) {
6497
            $result[$format] = true;
6498
6499
            return true;
6500
        } else {
6501
            $result[$format] = false;
6502
6503
            return false;
6504
        }
6505
    } elseif ('wmv' == $format) {
6506
        //native wmv support
6507
        if ('Firefox' == $current_browser && $current_majorver >= 4) {
6508
            $result[$format] = true;
6509
6510
            return true;
6511
        } else {
6512
            $result[$format] = false;
6513
6514
            return false;
6515
        }
6516
    } elseif ('webm' == $format) {
6517
        //native webm support (TODO:check IE9, Chrome9, Android)
6518
        if (('Firefox' == $current_browser && $current_majorver >= 4) ||
6519
            ('Opera' == $current_browser && $current_majorver >= 9) ||
6520
            ('Internet Explorer' == $current_browser && $current_majorver >= 9) ||
6521
            ('Chrome' == $current_browser && $current_majorver >= 9) ||
6522
            'Android' == $current_browser
6523
        ) {
6524
            $result[$format] = true;
6525
6526
            return true;
6527
        } else {
6528
            $result[$format] = false;
6529
6530
            return false;
6531
        }
6532
    } elseif ('wav' == $format) {
6533
        //native wav support (only some codecs !)
6534
        if (('Firefox' == $current_browser && $current_majorver >= 4) ||
6535
            ('Safari' == $current_browser && $current_majorver >= 5) ||
6536
            ('Opera' == $current_browser && $current_majorver >= 9) ||
6537
            ('Internet Explorer' == $current_browser && $current_majorver >= 9) ||
6538
            ('Chrome' == $current_browser && $current_majorver > 9) ||
6539
            'Android' == $current_browser ||
6540
            'iPhone' == $current_browser
6541
        ) {
6542
            $result[$format] = true;
6543
6544
            return true;
6545
        } else {
6546
            $result[$format] = false;
6547
6548
            return false;
6549
        }
6550
    } elseif ('mid' == $format || 'kar' == $format) {
6551
        //native midi support (TODO:check Android)
6552
        if ('Opera' == $current_browser && $current_majorver >= 9 || 'Android' == $current_browser) {
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: ('Opera' == $current_bro...id' == $current_browser, Probably Intended Meaning: 'Opera' == $current_brow...d' == $current_browser)
Loading history...
6553
            $result[$format] = true;
6554
6555
            return true;
6556
        } else {
6557
            $result[$format] = false;
6558
6559
            return false;
6560
        }
6561
    } elseif ('wma' == $format) {
6562
        //native wma support
6563
        if ('Firefox' == $current_browser && $current_majorver >= 4) {
6564
            $result[$format] = true;
6565
6566
            return true;
6567
        } else {
6568
            $result[$format] = false;
6569
6570
            return false;
6571
        }
6572
    } elseif ('au' == $format) {
6573
        //native au support
6574
        if ('Safari' == $current_browser && $current_majorver >= 5) {
6575
            $result[$format] = true;
6576
6577
            return true;
6578
        } else {
6579
            $result[$format] = false;
6580
6581
            return false;
6582
        }
6583
    } elseif ('mp3' == $format) {
6584
        //native mp3 support (TODO:check Android, iPhone)
6585
        if (('Safari' == $current_browser && $current_majorver >= 5) ||
6586
            ('Chrome' == $current_browser && $current_majorver >= 6) ||
6587
            ('Internet Explorer' == $current_browser && $current_majorver >= 9) ||
6588
            'Android' == $current_browser ||
6589
            'iPhone' == $current_browser ||
6590
            'Firefox' == $current_browser
6591
        ) {
6592
            $result[$format] = true;
6593
6594
            return true;
6595
        } else {
6596
            $result[$format] = false;
6597
6598
            return false;
6599
        }
6600
    } elseif ('autocapitalize' == $format) {
6601
        // Help avoiding showing the autocapitalize option if the browser doesn't
6602
        // support it: this attribute is against the HTML5 standard
6603
        if ('Safari' == $current_browser || 'iPhone' == $current_browser) {
6604
            return true;
6605
        } else {
6606
            return false;
6607
        }
6608
    } elseif ("check_browser" == $format) {
6609
        $array_check_browser = [$current_browser, $current_majorver];
6610
6611
        return $array_check_browser;
6612
    } else {
6613
        $result[$format] = false;
6614
6615
        return false;
6616
    }
6617
}
6618
6619
/**
6620
 * This function checks if exist path and file browscap.ini
6621
 * In order for this to work, your browscap configuration setting in php.ini
6622
 * must point to the correct location of the browscap.ini file on your system
6623
 * http://php.net/manual/en/function.get-browser.php.
6624
 *
6625
 * @return bool
6626
 *
6627
 * @author Juan Carlos Raña Trabado
6628
 */
6629
function api_check_browscap()
6630
{
6631
    $setting = ini_get('browscap');
6632
    if ($setting) {
6633
        $browser = get_browser($_SERVER['HTTP_USER_AGENT'], true);
6634
        if (strpos($setting, 'browscap.ini') && !empty($browser)) {
6635
            return true;
6636
        }
6637
    }
6638
6639
    return false;
6640
}
6641
6642
/**
6643
 * Returns the <script> HTML tag.
6644
 */
6645
function api_get_js($file)
6646
{
6647
    return '<script type="text/javascript" src="'.api_get_path(WEB_LIBRARY_PATH).'javascript/'.$file.'"></script>'."\n";
6648
}
6649
6650
function api_get_build_js($file)
6651
{
6652
    return '<script type="text/javascript" src="'.api_get_path(WEB_PUBLIC_PATH).'build/'.$file.'"></script>'."\n";
6653
}
6654
6655
/**
6656
 * Returns the <script> HTML tag.
6657
 *
6658
 * @return string
6659
 */
6660
function api_get_asset($file)
6661
{
6662
    return '<script type="text/javascript" src="'.api_get_path(WEB_PUBLIC_PATH).'build/libs/'.$file.'"></script>'."\n";
6663
}
6664
6665
/**
6666
 * Returns the <script> HTML tag.
6667
 *
6668
 * @param string $file
6669
 * @param string $media
6670
 *
6671
 * @return string
6672
 */
6673
function api_get_css_asset($file, $media = 'screen')
6674
{
6675
    return '<link href="'.api_get_path(WEB_PUBLIC_PATH).'libs/'.$file.'" rel="stylesheet" media="'.$media.'" type="text/css" />'."\n";
6676
}
6677
6678
/**
6679
 * Returns the <link> HTML tag.
6680
 *
6681
 * @param string $file
6682
 * @param string $media
6683
 */
6684
function api_get_css($file, $media = 'screen')
6685
{
6686
    return '<link href="'.$file.'" rel="stylesheet" media="'.$media.'" type="text/css" />'."\n";
6687
}
6688
6689
function api_get_bootstrap_and_font_awesome($returnOnlyPath = false)
6690
{
6691
    $url = api_get_path(WEB_PUBLIC_PATH).'build/css/bootstrap.css';
6692
    if ($returnOnlyPath) {
6693
        return $url;
6694
    }
6695
6696
    return '<link href="'.$url.'" rel="stylesheet" type="text/css" />'."\n";
6697
}
6698
6699
/**
6700
 * Returns the js header to include the jquery library.
6701
 */
6702
function api_get_jquery_js()
6703
{
6704
    return api_get_asset('jquery/jquery.min.js');
6705
}
6706
6707
/**
6708
 * Returns the jquery path.
6709
 *
6710
 * @return string
6711
 */
6712
function api_get_jquery_web_path()
6713
{
6714
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery/jquery.min.js';
6715
}
6716
6717
/**
6718
 * @return string
6719
 */
6720
function api_get_jquery_ui_js_web_path()
6721
{
6722
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery-ui/jquery-ui.min.js';
6723
}
6724
6725
/**
6726
 * @return string
6727
 */
6728
function api_get_jquery_ui_css_web_path()
6729
{
6730
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery-ui/themes/smoothness/jquery-ui.min.css';
6731
}
6732
6733
/**
6734
 * Returns the jquery-ui library js headers.
6735
 *
6736
 * @return string html tags
6737
 */
6738
function api_get_jquery_ui_js()
6739
{
6740
    $libraries = [];
6741
6742
    return api_get_jquery_libraries_js($libraries);
6743
}
6744
6745
function api_get_jqgrid_js()
6746
{
6747
    $routePublic = Container::getRouter()->generate('home');
6748
6749
    return api_get_css($routePublic.'build/free-jqgrid.css').PHP_EOL
6750
        .api_get_js_simple($routePublic.'build/free-jqgrid.js');
6751
}
6752
6753
/**
6754
 * Returns the jquery library js and css headers.
6755
 *
6756
 * @param   array   list of jquery libraries supported jquery-ui
6757
 * @param   bool    add the jquery library
6758
 *
6759
 * @return string html tags
6760
 */
6761
function api_get_jquery_libraries_js($libraries)
6762
{
6763
    $js = '';
6764
6765
    //Document multiple upload funcionality
6766
    if (in_array('jquery-uploadzs', $libraries)) {
6767
        $js .= api_get_asset('blueimp-load-image/js/load-image.all.min.js');
6768
        $js .= api_get_asset('blueimp-canvas-to-blob/js/canvas-to-blob.min.js');
6769
        $js .= api_get_asset('jquery-file-upload/js/jquery.iframe-transport.js');
6770
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload.js');
6771
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-process.js');
6772
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-image.js');
6773
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-audio.js');
6774
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-video.js');
6775
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-validate.js');
6776
6777
        $js .= api_get_css(api_get_path(WEB_PUBLIC_PATH).'assets/jquery-file-upload/css/jquery.fileupload.css');
6778
        $js .= api_get_css(api_get_path(WEB_PUBLIC_PATH).'assets/jquery-file-upload/css/jquery.fileupload-ui.css');
6779
    }
6780
6781
    // jquery datepicker
6782
    if (in_array('datepicker', $libraries)) {
6783
        $languaje = 'en-GB';
6784
        $platform_isocode = strtolower(api_get_language_isocode());
6785
6786
        $datapicker_langs = [
6787
            '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',
6788
        ];
6789
        if (in_array($platform_isocode, $datapicker_langs)) {
6790
            $languaje = $platform_isocode;
6791
        }
6792
6793
        $js .= api_get_js('jquery-ui/jquery-ui-i18n.min.js');
6794
        $script = '<script>
6795
        $(function(){
6796
            $.datepicker.setDefaults($.datepicker.regional["'.$languaje.'"]);
6797
            $.datepicker.regional["local"] = $.datepicker.regional["'.$languaje.'"];
6798
        });
6799
        </script>
6800
        ';
6801
        $js .= $script;
6802
    }
6803
6804
    return $js;
6805
}
6806
6807
/**
6808
 * Returns the URL to the course or session, removing the complexity of the URL
6809
 * building piece by piece.
6810
 *
6811
 * This function relies on api_get_course_info()
6812
 *
6813
 * @param string $courseCode The course code - optional (takes it from context if not given)
6814
 * @param int    $sessionId  The session ID  - optional (takes it from context if not given)
6815
 * @param int    $groupId    The group ID - optional (takes it from context if not given)
6816
 *
6817
 * @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
6818
 *
6819
 * @author  Julio Montoya <[email protected]>
6820
 */
6821
function api_get_course_url($courseCode = null, $sessionId = null, $groupId = null)
6822
{
6823
    $courseDirectory = '';
6824
    $url = '';
6825
    // If courseCode not set, get context or []
6826
    if (empty($courseCode)) {
6827
        $courseInfo = api_get_course_info();
6828
    } else {
6829
        $courseInfo = api_get_course_info($courseCode);
6830
    }
6831
6832
    // If course defined, get directory, otherwise keep empty string
6833
    if (!empty($courseInfo['directory'])) {
6834
        $courseDirectory = $courseInfo['directory'];
6835
    }
6836
6837
    // If sessionId not set, get context or 0
6838
    if (empty($sessionId)) {
6839
        $sessionId = api_get_session_id();
6840
    }
6841
6842
    // If groupId not set, get context or 0
6843
    if (empty($groupId)) {
6844
        $groupId = api_get_group_id();
6845
    }
6846
6847
    // Build the URL
6848
    if (!empty($courseDirectory)) {
6849
        // directory not empty, so we do have a course
6850
        $url = api_get_path(WEB_COURSE_PATH).$courseDirectory.'/index.php?id_session='.$sessionId.'&gidReq='.$groupId;
6851
    } elseif (!empty($sessionId) &&
6852
        'true' !== api_get_setting('session.remove_session_url')
6853
    ) {
6854
        // if the course was unset and the session was set, send directly to the session
6855
        $url = api_get_path(WEB_CODE_PATH).'session/index.php?session_id='.$sessionId;
6856
    }
6857
6858
    // if not valid combination was found, return an empty string
6859
    return $url;
6860
}
6861
6862
/**
6863
 * Check if the current portal has the $_configuration['multiple_access_urls'] parameter on.
6864
 *
6865
 * @return bool true if multi site is enabled
6866
 */
6867
function api_get_multiple_access_url()
6868
{
6869
    global $_configuration;
6870
    if (isset($_configuration['multiple_access_urls']) && $_configuration['multiple_access_urls']) {
6871
        return true;
6872
    }
6873
6874
    return false;
6875
}
6876
6877
/**
6878
 * @return bool
6879
 */
6880
function api_is_multiple_url_enabled()
6881
{
6882
    return api_get_multiple_access_url();
6883
}
6884
6885
/**
6886
 * Returns a md5 unique id.
6887
 *
6888
 * @todo add more parameters
6889
 */
6890
function api_get_unique_id()
6891
{
6892
    $id = md5(time().uniqid().api_get_user_id().api_get_course_id().api_get_session_id());
6893
6894
    return $id;
6895
}
6896
6897
/**
6898
 * @param int Course id
6899
 * @param int tool id: TOOL_QUIZ, TOOL_FORUM, TOOL_STUDENTPUBLICATION, TOOL_LEARNPATH
6900
 * @param int the item id (tool id, exercise id, lp id)
6901
 *
6902
 * @return bool
6903
 */
6904
function api_resource_is_locked_by_gradebook($item_id, $link_type, $course_code = null)
6905
{
6906
    if (api_is_platform_admin()) {
6907
        return false;
6908
    }
6909
    if ('true' == api_get_setting('gradebook_locking_enabled')) {
6910
        if (empty($course_code)) {
6911
            $course_code = api_get_course_id();
6912
        }
6913
        $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_LINK);
6914
        $item_id = (int) $item_id;
6915
        $link_type = (int) $link_type;
6916
        $course_code = Database::escape_string($course_code);
6917
        $sql = "SELECT locked FROM $table
6918
                WHERE locked = 1 AND ref_id = $item_id AND type = $link_type AND course_code = '$course_code' ";
6919
        $result = Database::query($sql);
6920
        if (Database::num_rows($result)) {
6921
            return true;
6922
        }
6923
    }
6924
6925
    return false;
6926
}
6927
6928
/**
6929
 * Blocks a page if the item was added in a gradebook.
6930
 *
6931
 * @param int       exercise id, work id, thread id,
6932
 * @param int       LINK_EXERCISE, LINK_STUDENTPUBLICATION, LINK_LEARNPATH LINK_FORUM_THREAD, LINK_ATTENDANCE
6933
 * see gradebook/lib/be/linkfactory
6934
 * @param string    course code
6935
 *
6936
 * @return false|null
6937
 */
6938
function api_block_course_item_locked_by_gradebook($item_id, $link_type, $course_code = null)
6939
{
6940
    if (api_is_platform_admin()) {
6941
        return false;
6942
    }
6943
6944
    if (api_resource_is_locked_by_gradebook($item_id, $link_type, $course_code)) {
6945
        $message = Display::return_message(get_lang('This option is not available because this activity is contained by an assessment, which is currently locked. To unlock the assessment, ask your platform administrator.'), 'warning');
6946
        api_not_allowed(true, $message);
6947
    }
6948
}
6949
6950
/**
6951
 * Checks the PHP version installed is enough to run Chamilo.
6952
 *
6953
 * @param string Include path (used to load the error page)
6954
 */
6955
function api_check_php_version()
6956
{
6957
    if (!function_exists('version_compare') ||
6958
        version_compare(phpversion(), REQUIRED_PHP_VERSION, '<')
6959
    ) {
6960
        throw new Exception('Wrong PHP version');
6961
    }
6962
}
6963
6964
/**
6965
 * Checks whether the Archive directory is present and writeable. If not,
6966
 * prints a warning message.
6967
 */
6968
function api_check_archive_dir()
6969
{
6970
    if (is_dir(api_get_path(SYS_ARCHIVE_PATH)) && !is_writable(api_get_path(SYS_ARCHIVE_PATH))) {
6971
        $message = Display::return_message(get_lang('The app/cache/ directory, used by this tool, is not writeable. Please contact your platform administrator.'), 'warning');
6972
        api_not_allowed(true, $message);
6973
    }
6974
}
6975
6976
/**
6977
 * Returns an array of global configuration settings which should be ignored
6978
 * when printing the configuration settings screens.
6979
 *
6980
 * @return array Array of strings, each identifying one of the excluded settings
6981
 */
6982
function api_get_locked_settings()
6983
{
6984
    return [
6985
        'permanently_remove_deleted_files',
6986
        'account_valid_duration',
6987
        'service_ppt2lp',
6988
        'wcag_anysurfer_public_pages',
6989
        'upload_extensions_list_type',
6990
        'upload_extensions_blacklist',
6991
        'upload_extensions_whitelist',
6992
        'upload_extensions_skip',
6993
        'upload_extensions_replace_by',
6994
        'hide_dltt_markup',
6995
        'split_users_upload_directory',
6996
        'permissions_for_new_directories',
6997
        'permissions_for_new_files',
6998
        'platform_charset',
6999
        'ldap_description',
7000
        'cas_activate',
7001
        'cas_server',
7002
        'cas_server_uri',
7003
        'cas_port',
7004
        'cas_protocol',
7005
        'cas_add_user_activate',
7006
        'update_user_info_cas_with_ldap',
7007
        'languagePriority1',
7008
        'languagePriority2',
7009
        'languagePriority3',
7010
        'languagePriority4',
7011
        'login_is_email',
7012
        'chamilo_database_version',
7013
    ];
7014
}
7015
7016
/**
7017
 * Guess the real ip for register in the database, even in reverse proxy cases.
7018
 * To be recognized, the IP has to be found in either $_SERVER['REMOTE_ADDR'] or
7019
 * in $_SERVER['HTTP_X_FORWARDED_FOR'], which is in common use with rproxies.
7020
 * Note: the result of this function is not SQL-safe. Please escape it before
7021
 * inserting in a database.
7022
 *
7023
 * @return string the user's real ip (unsafe - escape it before inserting to db)
7024
 *
7025
 * @author Jorge Frisancho Jibaja <[email protected]>, USIL - Some changes to allow the use of real IP using reverse proxy
7026
 *
7027
 * @version CEV CHANGE 24APR2012
7028
 */
7029
function api_get_real_ip()
7030
{
7031
    $ip = trim($_SERVER['REMOTE_ADDR']);
7032
    if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
7033
        if (preg_match('/,/', $_SERVER['HTTP_X_FORWARDED_FOR'])) {
7034
            @list($ip1, $ip2) = @explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
7035
        } else {
7036
            $ip1 = $_SERVER['HTTP_X_FORWARDED_FOR'];
7037
        }
7038
        $ip = trim($ip1);
7039
    }
7040
7041
    return $ip;
7042
}
7043
7044
/**
7045
 * Checks whether an IP is included inside an IP range.
7046
 *
7047
 * @param string IP address
7048
 * @param string IP range
7049
 * @param string $ip
7050
 *
7051
 * @return bool True if IP is in the range, false otherwise
7052
 *
7053
 * @author claudiu at cnixs dot com  on http://www.php.net/manual/fr/ref.network.php#55230
7054
 * @author Yannick Warnier for improvements and managment of multiple ranges
7055
 *
7056
 * @todo check for IPv6 support
7057
 */
7058
function api_check_ip_in_range($ip, $range)
7059
{
7060
    if (empty($ip) or empty($range)) {
7061
        return false;
7062
    }
7063
    $ip_ip = ip2long($ip);
7064
    // divide range param into array of elements
7065
    if (false !== strpos($range, ',')) {
7066
        $ranges = explode(',', $range);
7067
    } else {
7068
        $ranges = [$range];
7069
    }
7070
    foreach ($ranges as $range) {
0 ignored issues
show
introduced by
$range is overwriting one of the parameters of this function.
Loading history...
7071
        $range = trim($range);
7072
        if (empty($range)) {
7073
            continue;
7074
        }
7075
        if (false === strpos($range, '/')) {
7076
            if (0 === strcmp($ip, $range)) {
7077
                return true; // there is a direct IP match, return OK
7078
            }
7079
            continue; //otherwise, get to the next range
7080
        }
7081
        // the range contains a "/", so analyse completely
7082
        [$net, $mask] = explode("/", $range);
7083
7084
        $ip_net = ip2long($net);
7085
        // mask binary magic
7086
        $ip_mask = ~((1 << (32 - $mask)) - 1);
7087
7088
        $ip_ip_net = $ip_ip & $ip_mask;
7089
        if ($ip_ip_net == $ip_net) {
7090
            return true;
7091
        }
7092
    }
7093
7094
    return false;
7095
}
7096
7097
function api_check_user_access_to_legal($course_visibility)
7098
{
7099
    $course_visibility_list = [COURSE_VISIBILITY_OPEN_WORLD, COURSE_VISIBILITY_OPEN_PLATFORM];
7100
7101
    return in_array($course_visibility, $course_visibility_list) || api_is_drh();
7102
}
7103
7104
/**
7105
 * Checks if the global chat is enabled or not.
7106
 *
7107
 * @return bool
7108
 */
7109
function api_is_global_chat_enabled()
7110
{
7111
    return
7112
        !api_is_anonymous() &&
7113
        'true' === api_get_setting('allow_global_chat') &&
7114
        'true' === api_get_setting('allow_social_tool');
7115
}
7116
7117
/**
7118
 * @param int $item_id
7119
 * @param int   $tool_id
7120
 * @param int   $group_id   id
7121
 * @param array $courseInfo
7122
 * @param int   $sessionId
7123
 * @param int   $userId
7124
 *
7125
 * @deprecated
7126
 *
7127
 */
7128
function api_set_default_visibility(
7129
    $item_id,
7130
    $tool_id,
7131
    $group_id = 0,
7132
    $courseInfo = [],
7133
    $sessionId = 0,
7134
    $userId = 0
7135
) {
7136
    $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
7137
    $courseId = $courseInfo['real_id'];
7138
    $courseCode = $courseInfo['code'];
7139
    $sessionId = empty($sessionId) ? api_get_session_id() : $sessionId;
7140
    $userId = empty($userId) ? api_get_user_id() : $userId;
7141
7142
    // if group is null force group_id = 0, this force is needed to create a LP folder with group = 0
7143
    if (is_null($group_id)) {
7144
        $group_id = 0;
7145
    } else {
7146
        $group_id = empty($group_id) ? api_get_group_id() : $group_id;
7147
    }
7148
7149
    $groupInfo = [];
7150
    if (!empty($group_id)) {
7151
        $groupInfo = GroupManager::get_group_properties($group_id);
7152
    }
7153
    $original_tool_id = $tool_id;
7154
7155
    switch ($tool_id) {
7156
        case TOOL_LINK:
7157
        case TOOL_LINK_CATEGORY:
7158
            $tool_id = 'links';
7159
            break;
7160
        case TOOL_DOCUMENT:
7161
            $tool_id = 'documents';
7162
            break;
7163
        case TOOL_LEARNPATH:
7164
            $tool_id = 'learning';
7165
            break;
7166
        case TOOL_ANNOUNCEMENT:
7167
            $tool_id = 'announcements';
7168
            break;
7169
        case TOOL_FORUM:
7170
        case TOOL_FORUM_CATEGORY:
7171
        case TOOL_FORUM_THREAD:
7172
            $tool_id = 'forums';
7173
            break;
7174
        case TOOL_QUIZ:
7175
            $tool_id = 'quiz';
7176
            break;
7177
    }
7178
    $setting = api_get_setting('tool_visible_by_default_at_creation');
7179
7180
    if (isset($setting[$tool_id])) {
7181
        $visibility = 'invisible';
7182
        if ('true' == $setting[$tool_id]) {
7183
            $visibility = 'visible';
7184
        }
7185
7186
        // Read the portal and course default visibility
7187
        if ('documents' === $tool_id) {
7188
            $visibility = DocumentManager::getDocumentDefaultVisibility($courseInfo);
7189
        }
7190
7191
        /*api_item_property_update(
7192
            $courseInfo,
7193
            $original_tool_id,
7194
            $item_id,
7195
            $visibility,
7196
            $userId,
7197
            $groupInfo,
7198
            null,
7199
            null,
7200
            null,
7201
            $sessionId
7202
        );*/
7203
7204
        // Fixes default visibility for tests
7205
        switch ($original_tool_id) {
7206
            case TOOL_QUIZ:
7207
                if (empty($sessionId)) {
7208
                    $objExerciseTmp = new Exercise($courseId);
7209
                    $objExerciseTmp->read($item_id);
7210
                    if ('visible' == $visibility) {
7211
                        $objExerciseTmp->enable();
7212
                        $objExerciseTmp->save();
7213
                    } else {
7214
                        $objExerciseTmp->disable();
7215
                        $objExerciseTmp->save();
7216
                    }
7217
                }
7218
                break;
7219
        }
7220
    }
7221
}
7222
7223
/**
7224
 * @return string
7225
 */
7226
function api_get_security_key()
7227
{
7228
    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...
7229
}
7230
7231
/**
7232
 * @param int $user_id
7233
 * @param int $courseId
7234
 * @param int $session_id
7235
 *
7236
 * @return array
7237
 */
7238
function api_detect_user_roles($user_id, $courseId, $session_id = 0)
7239
{
7240
    $user_roles = [];
7241
    $courseInfo = api_get_course_info_by_id($courseId);
7242
    $course_code = $courseInfo['code'];
7243
7244
    $url_id = api_get_current_access_url_id();
7245
    if (api_is_platform_admin_by_id($user_id, $url_id)) {
7246
        $user_roles[] = PLATFORM_ADMIN;
7247
    }
7248
7249
    /*if (api_is_drh()) {
7250
        $user_roles[] = DRH;
7251
    }*/
7252
7253
    if (!empty($session_id)) {
7254
        if (SessionManager::user_is_general_coach($user_id, $session_id)) {
7255
            $user_roles[] = SESSION_GENERAL_COACH;
7256
        }
7257
    }
7258
7259
    if (!empty($course_code)) {
7260
        if (empty($session_id)) {
7261
            if (CourseManager::is_course_teacher($user_id, $course_code)) {
7262
                $user_roles[] = COURSEMANAGER;
7263
            }
7264
            if (CourseManager::get_tutor_in_course_status($user_id, $courseInfo['real_id'])) {
7265
                $user_roles[] = COURSE_TUTOR;
7266
            }
7267
7268
            if (CourseManager::is_user_subscribed_in_course($user_id, $course_code)) {
7269
                $user_roles[] = COURSE_STUDENT;
7270
            }
7271
        } else {
7272
            $user_status_in_session = SessionManager::get_user_status_in_course_session(
7273
                $user_id,
7274
                $courseId,
7275
                $session_id
7276
            );
7277
7278
            if (!empty($user_status_in_session)) {
7279
                if (0 == $user_status_in_session) {
7280
                    $user_roles[] = SESSION_STUDENT;
7281
                }
7282
                if (2 == $user_status_in_session) {
7283
                    $user_roles[] = SESSION_COURSE_COACH;
7284
                }
7285
            }
7286
7287
            /*if (api_is_course_session_coach($user_id, $course_code, $session_id)) {
7288
               $user_roles[] = SESSION_COURSE_COACH;
7289
            }*/
7290
        }
7291
    }
7292
7293
    return $user_roles;
7294
}
7295
7296
/**
7297
 * @param int $courseId
7298
 * @param int $session_id
7299
 *
7300
 * @return bool
7301
 */
7302
function api_coach_can_edit_view_results($courseId = null, $session_id = null)
7303
{
7304
    if (api_is_platform_admin()) {
7305
        return true;
7306
    }
7307
7308
    $user_id = api_get_user_id();
7309
7310
    if (empty($courseId)) {
7311
        $courseId = api_get_course_int_id();
7312
    }
7313
7314
    if (empty($session_id)) {
7315
        $session_id = api_get_session_id();
7316
    }
7317
7318
    $roles = api_detect_user_roles($user_id, $courseId, $session_id);
7319
7320
    if (in_array(SESSION_COURSE_COACH, $roles)) {
7321
        //return api_get_setting('session_tutor_reports_visibility') == 'true';
7322
        return true;
7323
    } else {
7324
        if (in_array(COURSEMANAGER, $roles)) {
7325
            return true;
7326
        }
7327
7328
        return false;
7329
    }
7330
}
7331
7332
/**
7333
 * @param string $file
7334
 *
7335
 * @return string
7336
 */
7337
function api_get_js_simple($file)
7338
{
7339
    return '<script type="text/javascript" src="'.$file.'"></script>'."\n";
7340
}
7341
7342
/**
7343
 * Modify default memory_limit and max_execution_time limits
7344
 * Needed when processing long tasks.
7345
 */
7346
function api_set_more_memory_and_time_limits()
7347
{
7348
    if (function_exists('ini_set')) {
7349
        api_set_memory_limit('256M');
7350
        ini_set('max_execution_time', 1800);
7351
    }
7352
}
7353
7354
/**
7355
 * Tries to set memory limit, if authorized and new limit is higher than current.
7356
 *
7357
 * @param string $mem New memory limit
7358
 *
7359
 * @return bool True on success, false on failure or current is higher than suggested
7360
 * @assert (null) === false
7361
 * @assert (-1) === false
7362
 * @assert (0) === true
7363
 * @assert ('1G') === true
7364
 */
7365
function api_set_memory_limit($mem)
7366
{
7367
    //if ini_set() not available, this function is useless
7368
    if (!function_exists('ini_set') || is_null($mem) || -1 == $mem) {
7369
        return false;
7370
    }
7371
7372
    $memory_limit = ini_get('memory_limit');
7373
    if (api_get_bytes_memory_limit($mem) > api_get_bytes_memory_limit($memory_limit)) {
7374
        ini_set('memory_limit', $mem);
7375
7376
        return true;
7377
    }
7378
7379
    return false;
7380
}
7381
7382
/**
7383
 * Gets memory limit in bytes.
7384
 *
7385
 * @param string The memory size (128M, 1G, 1000K, etc)
7386
 *
7387
 * @return int
7388
 * @assert (null) === false
7389
 * @assert ('1t')  === 1099511627776
7390
 * @assert ('1g')  === 1073741824
7391
 * @assert ('1m')  === 1048576
7392
 * @assert ('100k') === 102400
7393
 */
7394
function api_get_bytes_memory_limit($mem)
7395
{
7396
    $size = strtolower(substr($mem, -1));
7397
7398
    switch ($size) {
7399
        case 't':
7400
            $mem = intval(substr($mem, -1)) * 1024 * 1024 * 1024 * 1024;
7401
            break;
7402
        case 'g':
7403
            $mem = intval(substr($mem, 0, -1)) * 1024 * 1024 * 1024;
7404
            break;
7405
        case 'm':
7406
            $mem = intval(substr($mem, 0, -1)) * 1024 * 1024;
7407
            break;
7408
        case 'k':
7409
            $mem = intval(substr($mem, 0, -1)) * 1024;
7410
            break;
7411
        default:
7412
            // we assume it's integer only
7413
            $mem = intval($mem);
7414
            break;
7415
    }
7416
7417
    return $mem;
7418
}
7419
7420
/**
7421
 * Finds all the information about a user from username instead of user id.
7422
 *
7423
 * @param string $officialCode
7424
 *
7425
 * @return array $user_info user_id, lastname, firstname, username, email, ...
7426
 *
7427
 * @author Yannick Warnier <[email protected]>
7428
 */
7429
function api_get_user_info_from_official_code($officialCode)
7430
{
7431
    if (empty($officialCode)) {
7432
        return false;
7433
    }
7434
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
7435
            WHERE official_code ='".Database::escape_string($officialCode)."'";
7436
    $result = Database::query($sql);
7437
    if (Database::num_rows($result) > 0) {
7438
        $result_array = Database::fetch_array($result);
7439
7440
        return _api_format_user($result_array);
7441
    }
7442
7443
    return false;
7444
}
7445
7446
/**
7447
 * @param string $usernameInputId
7448
 * @param string $passwordInputId
7449
 *
7450
 * @return string|null
7451
 */
7452
function api_get_password_checker_js($usernameInputId, $passwordInputId)
7453
{
7454
    $checkPass = api_get_setting('allow_strength_pass_checker');
7455
    $useStrengthPassChecker = 'true' === $checkPass;
7456
7457
    if (false === $useStrengthPassChecker) {
7458
        return null;
7459
    }
7460
7461
    $translations = [
7462
        'wordLength' => get_lang('The password is too short'),
7463
        'wordNotEmail' => get_lang('Your password cannot be the same as your email'),
7464
        'wordSimilarToUsername' => get_lang('Your password cannot contain your username'),
7465
        'wordTwoCharacterClasses' => get_lang('Use different character classes'),
7466
        'wordRepetitions' => get_lang('Too many repetitions'),
7467
        'wordSequences' => get_lang('Your password contains sequences'),
7468
        'errorList' => get_lang('errors found'),
7469
        'veryWeak' => get_lang('Very weak'),
7470
        'weak' => get_lang('Weak'),
7471
        'normal' => get_lang('Normal'),
7472
        'medium' => get_lang('Medium'),
7473
        'strong' => get_lang('Strong'),
7474
        'veryStrong' => get_lang('Very strong'),
7475
    ];
7476
7477
    $js = api_get_asset('pwstrength-bootstrap/dist/pwstrength-bootstrap.min.js');
7478
    $js .= "<script>
7479
    var errorMessages = {
7480
        password_to_short : \"".get_lang('The password is too short')."\",
7481
        same_as_username : \"".get_lang('Your password cannot be the same as your username')."\"
7482
    };
7483
7484
    $(function() {
7485
        var lang = ".json_encode($translations).";
7486
        var options = {
7487
            onLoad : function () {
7488
                //$('#messages').text('Start typing password');
7489
            },
7490
            onKeyUp: function (evt) {
7491
                $(evt.target).pwstrength('outputErrorList');
7492
            },
7493
            errorMessages : errorMessages,
7494
            viewports: {
7495
                progress: '#password_progress',
7496
                verdict: '#password-verdict',
7497
                errors: '#password-errors'
7498
            },
7499
            usernameField: '$usernameInputId'
7500
        };
7501
        options.i18n = {
7502
            t: function (key) {
7503
                var result = lang[key];
7504
                return result === key ? '' : result; // This assumes you return the
7505
            }
7506
        };
7507
        $('".$passwordInputId."').pwstrength(options);
7508
    });
7509
    </script>";
7510
7511
    return $js;
7512
}
7513
7514
/**
7515
 * create an user extra field called 'captcha_blocked_until_date'.
7516
 *
7517
 * @param string $username
7518
 *
7519
 * @return bool
7520
 */
7521
function api_block_account_captcha($username)
7522
{
7523
    $userInfo = api_get_user_info_from_username($username);
7524
    if (empty($userInfo)) {
7525
        return false;
7526
    }
7527
    $minutesToBlock = api_get_setting('captcha_time_to_block');
7528
    $time = time() + $minutesToBlock * 60;
7529
    UserManager::update_extra_field_value(
7530
        $userInfo['user_id'],
7531
        'captcha_blocked_until_date',
7532
        api_get_utc_datetime($time)
7533
    );
7534
7535
    return true;
7536
}
7537
7538
/**
7539
 * @param string $username
7540
 *
7541
 * @return bool
7542
 */
7543
function api_clean_account_captcha($username)
7544
{
7545
    $userInfo = api_get_user_info_from_username($username);
7546
    if (empty($userInfo)) {
7547
        return false;
7548
    }
7549
    Session::erase('loginFailedCount');
7550
    UserManager::update_extra_field_value(
7551
        $userInfo['user_id'],
7552
        'captcha_blocked_until_date',
7553
        null
7554
    );
7555
7556
    return true;
7557
}
7558
7559
/**
7560
 * @param string $username
7561
 *
7562
 * @return bool
7563
 */
7564
function api_get_user_blocked_by_captcha($username)
7565
{
7566
    $userInfo = api_get_user_info_from_username($username);
7567
    if (empty($userInfo)) {
7568
        return false;
7569
    }
7570
    $data = UserManager::get_extra_user_data_by_field(
7571
        $userInfo['user_id'],
7572
        'captcha_blocked_until_date'
7573
    );
7574
    if (isset($data) && isset($data['captcha_blocked_until_date'])) {
7575
        return $data['captcha_blocked_until_date'];
7576
    }
7577
7578
    return false;
7579
}
7580
7581
/**
7582
 * Remove tags from HTML anf return the $in_number_char first non-HTML char
7583
 * Postfix the text with "..." if it has been truncated.
7584
 *
7585
 * @param string $text
7586
 * @param int    $number
7587
 *
7588
 * @return string
7589
 *
7590
 * @author hubert borderiou
7591
 */
7592
function api_get_short_text_from_html($text, $number)
7593
{
7594
    // Delete script and style tags
7595
    $text = preg_replace('/(<(script|style)\b[^>]*>).*?(<\/\2>)/is', "$1$3", $text);
7596
    $text = api_html_entity_decode($text);
7597
    $out_res = api_remove_tags_with_space($text, false);
7598
    $postfix = "...";
7599
    if (strlen($out_res) > $number) {
7600
        $out_res = substr($out_res, 0, $number).$postfix;
7601
    }
7602
7603
    return $out_res;
7604
}
7605
7606
/**
7607
 * Replace tags with a space in a text.
7608
 * If $in_double_quote_replace, replace " with '' (for HTML attribute purpose, for exemple).
7609
 *
7610
 * @return string
7611
 *
7612
 * @author hubert borderiou
7613
 */
7614
function api_remove_tags_with_space($in_html, $in_double_quote_replace = true)
7615
{
7616
    $out_res = $in_html;
7617
    if ($in_double_quote_replace) {
7618
        $out_res = str_replace('"', "''", $out_res);
7619
    }
7620
    // avoid text stuck together when tags are removed, adding a space after >
7621
    $out_res = str_replace(">", "> ", $out_res);
7622
    $out_res = strip_tags($out_res);
7623
7624
    return $out_res;
7625
}
7626
7627
/**
7628
 * If true, the drh can access all content (courses, users) inside a session.
7629
 *
7630
 * @return bool
7631
 */
7632
function api_drh_can_access_all_session_content()
7633
{
7634
    return api_get_setting('drh_can_access_all_session_content') === 'true';
7635
}
7636
7637
/**
7638
 * @param string $tool
7639
 * @param string $setting
7640
 * @param int    $defaultValue
7641
 *
7642
 * @return string
7643
 */
7644
function api_get_default_tool_setting($tool, $setting, $defaultValue)
7645
{
7646
    global $_configuration;
7647
    if (isset($_configuration[$tool]) &&
7648
        isset($_configuration[$tool]['default_settings']) &&
7649
        isset($_configuration[$tool]['default_settings'][$setting])
7650
    ) {
7651
        return $_configuration[$tool]['default_settings'][$setting];
7652
    }
7653
7654
    return $defaultValue;
7655
}
7656
7657
/**
7658
 * Checks if user can login as another user.
7659
 *
7660
 * @param int $loginAsUserId the user id to log in
7661
 * @param int $userId        my user id
7662
 *
7663
 * @return bool
7664
 */
7665
function api_can_login_as($loginAsUserId, $userId = null)
7666
{
7667
    if (empty($userId)) {
7668
        $userId = api_get_user_id();
7669
    }
7670
    if ($loginAsUserId == $userId) {
7671
        return false;
7672
    }
7673
7674
    if (empty($loginAsUserId)) {
7675
        return false;
7676
    }
7677
7678
    if ($loginAsUserId != strval(intval($loginAsUserId))) {
7679
        return false;
7680
    }
7681
7682
    // Check if the user to login is an admin
7683
    if (api_is_platform_admin_by_id($loginAsUserId)) {
7684
        // Only super admins can login to admin accounts
7685
        if (!api_global_admin_can_edit_admin($loginAsUserId)) {
7686
            return false;
7687
        }
7688
    }
7689
7690
    $userInfo = api_get_user_info($loginAsUserId);
7691
    $isDrh = function () use ($loginAsUserId) {
7692
        if (api_is_drh()) {
7693
            if (api_drh_can_access_all_session_content()) {
7694
                $users = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus(
7695
                    'drh_all',
7696
                    api_get_user_id()
7697
                );
7698
                $userList = [];
7699
                if (is_array($users)) {
7700
                    foreach ($users as $user) {
7701
                        $userList[] = $user['user_id'];
7702
                    }
7703
                }
7704
                if (in_array($loginAsUserId, $userList)) {
7705
                    return true;
7706
                }
7707
            } else {
7708
                if (api_is_drh() &&
7709
                    UserManager::is_user_followed_by_drh($loginAsUserId, api_get_user_id())
7710
                ) {
7711
                    return true;
7712
                }
7713
            }
7714
        }
7715
7716
        return false;
7717
    };
7718
7719
    $loginAsStatusForSessionAdmins = [STUDENT];
7720
7721
    if (api_get_setting('session.allow_session_admin_login_as_teacher')) {
7722
        $loginAsStatusForSessionAdmins[] = COURSEMANAGER;
7723
    }
7724
7725
    return api_is_platform_admin() ||
7726
        (api_is_session_admin() && in_array($userInfo['status'], $loginAsStatusForSessionAdmins)) ||
7727
        $isDrh();
7728
}
7729
7730
/**
7731
 * @return bool
7732
 */
7733
function api_is_allowed_in_course()
7734
{
7735
    if (api_is_platform_admin()) {
7736
        return true;
7737
    }
7738
7739
    $user = api_get_current_user();
7740
    if ($user instanceof User) {
7741
        if ($user->hasRole('ROLE_CURRENT_SESSION_COURSE_STUDENT') ||
7742
            $user->hasRole('ROLE_CURRENT_SESSION_COURSE_TEACHER') ||
7743
            $user->hasRole('ROLE_CURRENT_COURSE_STUDENT') ||
7744
            $user->hasRole('ROLE_CURRENT_COURSE_TEACHER')
7745
        ) {
7746
            return true;
7747
        }
7748
    }
7749
7750
    return false;
7751
}
7752
7753
/**
7754
 * Return true on https install.
7755
 *
7756
 * @return bool
7757
 */
7758
function api_is_https()
7759
{
7760
    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...
7761
        'https' == $_SERVER['HTTP_X_FORWARDED_PROTO'] || !empty(api_get_configuration_value('force_https_forwarded_proto'))
7762
    ) {
7763
        $isSecured = true;
7764
    } else {
7765
        if (!empty($_SERVER['HTTPS']) && 'off' != $_SERVER['HTTPS']) {
7766
            $isSecured = true;
7767
        } else {
7768
            $isSecured = false;
7769
            // last chance
7770
            if (!empty($_SERVER['SERVER_PORT']) && 443 == $_SERVER['SERVER_PORT']) {
7771
                $isSecured = true;
7772
            }
7773
        }
7774
    }
7775
7776
    return $isSecured;
7777
}
7778
7779
/**
7780
 * Return protocol (http or https).
7781
 *
7782
 * @return string
7783
 */
7784
function api_get_protocol()
7785
{
7786
    return api_is_https() ? 'https' : 'http';
7787
}
7788
7789
/**
7790
 * Return a string where " are replaced with 2 '
7791
 * It is useful when you pass a PHP variable in a Javascript browser dialog
7792
 * e.g. : alert("<?php get_lang('Message') ?>");
7793
 * and message contains character ".
7794
 *
7795
 * @param string $in_text
7796
 *
7797
 * @return string
7798
 */
7799
function convert_double_quote_to_single($in_text)
7800
{
7801
    return api_preg_replace('/"/', "''", $in_text);
7802
}
7803
7804
/**
7805
 * Get origin.
7806
 *
7807
 * @param string
7808
 *
7809
 * @return string
7810
 */
7811
function api_get_origin()
7812
{
7813
    return isset($_REQUEST['origin']) ? Security::remove_XSS($_REQUEST['origin']) : '';
7814
}
7815
7816
/**
7817
 * Warns an user that the portal reach certain limit.
7818
 *
7819
 * @param string $limitName
7820
 */
7821
function api_warn_hosting_contact($limitName)
7822
{
7823
    $hostingParams = api_get_configuration_value(1);
7824
    $email = null;
7825
7826
    if (!empty($hostingParams)) {
7827
        if (isset($hostingParams['hosting_contact_mail'])) {
7828
            $email = $hostingParams['hosting_contact_mail'];
7829
        }
7830
    }
7831
7832
    if (!empty($email)) {
7833
        $subject = get_lang('Hosting warning reached');
7834
        $body = get_lang('Portal name').': '.api_get_path(WEB_PATH)." \n ";
7835
        $body .= get_lang('Portal\'s limit type').': '.$limitName." \n ";
7836
        if (isset($hostingParams[$limitName])) {
7837
            $body .= get_lang('Value').': '.$hostingParams[$limitName];
7838
        }
7839
        api_mail_html(null, $email, $subject, $body);
7840
    }
7841
}
7842
7843
/**
7844
 * Gets value of a variable from config/configuration.php
7845
 * Variables that are not set in the configuration.php file but set elsewhere:
7846
 * - virtual_css_theme_folder (vchamilo plugin)
7847
 * - access_url (global.inc.php)
7848
 * - apc/apc_prefix (global.inc.php).
7849
 *
7850
 * @param string $variable
7851
 *
7852
 * @return bool|mixed
7853
 */
7854
function api_get_configuration_value($variable)
7855
{
7856
    global $_configuration;
7857
    // Check the current url id, id = 1 by default
7858
    $urlId = isset($_configuration['access_url']) ? (int) $_configuration['access_url'] : 1;
7859
7860
    $variable = trim($variable);
7861
7862
    // Check if variable exists
7863
    if (isset($_configuration[$variable])) {
7864
        if (is_array($_configuration[$variable])) {
7865
            // Check if it exists for the sub portal
7866
            if (array_key_exists($urlId, $_configuration[$variable])) {
7867
                return $_configuration[$variable][$urlId];
7868
            } else {
7869
                // Try to found element with id = 1 (master portal)
7870
                if (array_key_exists(1, $_configuration[$variable])) {
7871
                    return $_configuration[$variable][1];
7872
                }
7873
            }
7874
        }
7875
7876
        return $_configuration[$variable];
7877
    }
7878
7879
    return false;
7880
}
7881
7882
/**
7883
 * Retreives and returns a value in a hierarchical configuration array
7884
 * api_get_configuration_sub_value('a/b/c') returns api_get_configuration_value('a')['b']['c'].
7885
 *
7886
 * @param string $path      the successive array keys, separated by the separator
7887
 * @param mixed  $default   value to be returned if not found, null by default
7888
 * @param string $separator '/' by default
7889
 * @param array  $array     the active configuration array by default
7890
 *
7891
 * @return mixed the found value or $default
7892
 */
7893
function api_get_configuration_sub_value($path, $default = null, $separator = '/', $array = null)
7894
{
7895
    $pos = strpos($path, $separator);
7896
    if (false === $pos) {
7897
        if (is_null($array)) {
7898
            return api_get_configuration_value($path);
7899
        }
7900
        if (is_array($array) && array_key_exists($path, $array)) {
7901
            return $array[$path];
7902
        }
7903
7904
        return $default;
7905
    }
7906
    $key = substr($path, 0, $pos);
7907
    if (is_null($array)) {
7908
        $newArray = api_get_configuration_value($key);
7909
    } elseif (is_array($array) && array_key_exists($key, $array)) {
7910
        $newArray = $array[$key];
7911
    } else {
7912
        return $default;
7913
    }
7914
    if (is_array($newArray)) {
7915
        $newPath = substr($path, $pos + 1);
7916
7917
        return api_get_configuration_sub_value($newPath, $default, $separator, $newArray);
7918
    }
7919
7920
    return $default;
7921
}
7922
7923
/**
7924
 * Retrieves and returns a value in a hierarchical configuration array
7925
 * api_array_sub_value($array, 'a/b/c') returns $array['a']['b']['c'].
7926
 *
7927
 * @param array  $array     the recursive array that contains the value to be returned (or not)
7928
 * @param string $path      the successive array keys, separated by the separator
7929
 * @param mixed  $default   the value to be returned if not found
7930
 * @param string $separator the separator substring
7931
 *
7932
 * @return mixed the found value or $default
7933
 */
7934
function api_array_sub_value($array, $path, $default = null, $separator = '/')
7935
{
7936
    $pos = strpos($path, $separator);
7937
    if (false === $pos) {
7938
        if (is_array($array) && array_key_exists($path, $array)) {
7939
            return $array[$path];
7940
        }
7941
7942
        return $default;
7943
    }
7944
    $key = substr($path, 0, $pos);
7945
    if (is_array($array) && array_key_exists($key, $array)) {
7946
        $newArray = $array[$key];
7947
    } else {
7948
        return $default;
7949
    }
7950
    if (is_array($newArray)) {
7951
        $newPath = substr($path, $pos + 1);
7952
7953
        return api_array_sub_value($newArray, $newPath, $default);
7954
    }
7955
7956
    return $default;
7957
}
7958
7959
/**
7960
 * Returns supported image extensions in the portal.
7961
 *
7962
 * @param bool $supportVectors Whether vector images should also be accepted or not
7963
 *
7964
 * @return array Supported image extensions in the portal
7965
 */
7966
function api_get_supported_image_extensions($supportVectors = true)
7967
{
7968
    // jpg can also be called jpeg, jpe, jfif and jif. See https://en.wikipedia.org/wiki/JPEG#JPEG_filename_extensions
7969
    $supportedImageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'jpe', 'jfif', 'jif'];
7970
    if ($supportVectors) {
7971
        array_push($supportedImageExtensions, 'svg');
7972
    }
7973
    if (version_compare(PHP_VERSION, '5.5.0', '>=')) {
7974
        array_push($supportedImageExtensions, 'webp');
7975
    }
7976
7977
    return $supportedImageExtensions;
7978
}
7979
7980
/**
7981
 * This setting changes the registration status for the campus.
7982
 *
7983
 * @author Patrick Cool <[email protected]>, Ghent University
7984
 *
7985
 * @version August 2006
7986
 *
7987
 * @param bool $listCampus Whether we authorize
7988
 *
7989
 * @todo the $_settings should be reloaded here. => write api function for this and use this in global.inc.php also.
7990
 */
7991
function api_register_campus($listCampus = true)
7992
{
7993
    $tbl_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
7994
7995
    $sql = "UPDATE $tbl_settings SET selected_value='true' WHERE variable='registered'";
7996
    Database::query($sql);
7997
7998
    if (!$listCampus) {
7999
        $sql = "UPDATE $tbl_settings SET selected_value='true' WHERE variable='donotlistcampus'";
8000
        Database::query($sql);
8001
    }
8002
}
8003
8004
/**
8005
 * Checks whether current user is a student boss.
8006
 *
8007
 * @global array $_user
8008
 *
8009
 * @return bool
8010
 */
8011
function api_is_student_boss()
8012
{
8013
    $_user = api_get_user_info();
8014
8015
    return isset($_user['status']) && STUDENT_BOSS == $_user['status'];
8016
}
8017
8018
/**
8019
 * Check whether the user type should be exclude.
8020
 * Such as invited or anonymous users.
8021
 *
8022
 * @param bool $checkDB Optional. Whether check the user status
8023
 * @param int  $userId  Options. The user id
8024
 *
8025
 * @return bool
8026
 */
8027
function api_is_excluded_user_type($checkDB = false, $userId = 0)
8028
{
8029
    if ($checkDB) {
8030
        $userId = empty($userId) ? api_get_user_id() : (int) $userId;
8031
8032
        if (0 == $userId) {
8033
            return true;
8034
        }
8035
8036
        $userInfo = api_get_user_info($userId);
8037
8038
        switch ($userInfo['status']) {
8039
            case INVITEE:
8040
            case ANONYMOUS:
8041
                return true;
8042
            default:
8043
                return false;
8044
        }
8045
    }
8046
8047
    $isInvited = api_is_invitee();
8048
    $isAnonymous = api_is_anonymous();
8049
8050
    if ($isInvited || $isAnonymous) {
8051
        return true;
8052
    }
8053
8054
    return false;
8055
}
8056
8057
/**
8058
 * Get the user status to ignore in reports.
8059
 *
8060
 * @param string $format Optional. The result type (array or string)
8061
 *
8062
 * @return array|string
8063
 */
8064
function api_get_users_status_ignored_in_reports($format = 'array')
8065
{
8066
    $excludedTypes = [
8067
        INVITEE,
8068
        ANONYMOUS,
8069
    ];
8070
8071
    if ('string' == $format) {
8072
        return implode(', ', $excludedTypes);
8073
    }
8074
8075
    return $excludedTypes;
8076
}
8077
8078
/**
8079
 * Set the Site Use Cookie Warning for 1 year.
8080
 */
8081
function api_set_site_use_cookie_warning_cookie()
8082
{
8083
    setcookie('ChamiloUsesCookies', 'ok', time() + 31556926);
8084
}
8085
8086
/**
8087
 * Return true if the Site Use Cookie Warning Cookie warning exists.
8088
 *
8089
 * @return bool
8090
 */
8091
function api_site_use_cookie_warning_cookie_exist()
8092
{
8093
    return isset($_COOKIE['ChamiloUsesCookies']);
8094
}
8095
8096
/**
8097
 * Given a number of seconds, format the time to show hours, minutes and seconds.
8098
 *
8099
 * @param int    $time         The time in seconds
8100
 * @param string $originFormat Optional. PHP o JS
8101
 *
8102
 * @return string (00h00'00")
8103
 */
8104
function api_format_time($time, $originFormat = 'php')
8105
{
8106
    $h = get_lang('h');
8107
    $hours = $time / 3600;
8108
    $mins = ($time % 3600) / 60;
8109
    $secs = ($time % 60);
8110
8111
    if ($time < 0) {
8112
        $hours = 0;
8113
        $mins = 0;
8114
        $secs = 0;
8115
    }
8116
8117
    if ('js' == $originFormat) {
8118
        $formattedTime = trim(sprintf("%02d : %02d : %02d", $hours, $mins, $secs));
8119
    } else {
8120
        $formattedTime = trim(sprintf("%02d$h%02d'%02d\"", $hours, $mins, $secs));
8121
    }
8122
8123
    return $formattedTime;
8124
}
8125
8126
/**
8127
 * Create a new empty directory with index.html file.
8128
 *
8129
 * @param string $name            The new directory name
8130
 * @param string $parentDirectory Directory parent directory name
8131
 *
8132
 * @deprecated use Resources
8133
 *
8134
 * @return bool Return true if the directory was create. Otherwise return false
8135
 */
8136
function api_create_protected_dir($name, $parentDirectory)
8137
{
8138
    $isCreated = false;
8139
8140
    if (!is_writable($parentDirectory)) {
8141
        return false;
8142
    }
8143
8144
    $fullPath = $parentDirectory.api_replace_dangerous_char($name);
8145
8146
    if (mkdir($fullPath, api_get_permissions_for_new_directories(), true)) {
8147
        $fp = fopen($fullPath.'/index.html', 'w');
8148
8149
        if ($fp) {
0 ignored issues
show
introduced by
$fp is of type false|resource, thus it always evaluated to false.
Loading history...
8150
            if (fwrite($fp, '<html><head></head><body></body></html>')) {
8151
                $isCreated = true;
8152
            }
8153
        }
8154
8155
        fclose($fp);
8156
    }
8157
8158
    return $isCreated;
8159
}
8160
8161
/**
8162
 * Sends an email
8163
 * Sender name and email can be specified, if not specified
8164
 * name and email of the platform admin are used.
8165
 *
8166
 * @param string    name of recipient
8167
 * @param string    email of recipient
8168
 * @param string    email subject
8169
 * @param string    email body
8170
 * @param string    sender name
8171
 * @param string    sender e-mail
8172
 * @param array     extra headers in form $headers = array($name => $value) to allow parsing
8173
 * @param array     data file (path and filename)
8174
 * @param bool      True for attaching a embedded file inside content html (optional)
8175
 * @param array     Additional parameters
8176
 *
8177
 * @return bool true if mail was sent
8178
 */
8179
function api_mail_html(
8180
    $recipientName,
8181
    $recipientEmail,
8182
    $subject,
8183
    $body,
8184
    $senderName = '',
8185
    $senderEmail = '',
8186
    $extra_headers = [],
8187
    $data_file = [],
8188
    $embeddedImage = false,
8189
    $additionalParameters = []
8190
) {
8191
    if (!api_valid_email($recipientEmail)) {
8192
        return false;
8193
    }
8194
8195
    // Default values
8196
    $notification = new Notification();
8197
    $defaultEmail = $notification->getDefaultPlatformSenderEmail();
8198
    $defaultName = $notification->getDefaultPlatformSenderName();
8199
8200
    // If the parameter is set don't use the admin.
8201
    $senderName = !empty($senderName) ? $senderName : $defaultName;
8202
    $senderEmail = !empty($senderEmail) ? $senderEmail : $defaultEmail;
8203
8204
    // Reply to first
8205
    $replyToName = '';
8206
    $replyToEmail = '';
8207
    if (isset($extra_headers['reply_to'])) {
8208
        $replyToEmail = $extra_headers['reply_to']['mail'];
8209
        $replyToName = $extra_headers['reply_to']['name'];
8210
    }
8211
8212
    try {
8213
        $message = new TemplatedEmail();
8214
        $message->subject($subject);
8215
8216
        $list = api_get_configuration_value('send_all_emails_to');
8217
        if (!empty($list) && isset($list['emails'])) {
8218
            foreach ($list['emails'] as $email) {
8219
                $message->cc($email);
8220
            }
8221
        }
8222
8223
        // Attachment
8224
        if (!empty($data_file)) {
8225
            foreach ($data_file as $file_attach) {
8226
                if (!empty($file_attach['path']) && !empty($file_attach['filename'])) {
8227
                    $message->attachFromPath($file_attach['path'], $file_attach['filename']);
8228
                }
8229
            }
8230
        }
8231
8232
        $noReply = api_get_setting('noreply_email_address');
8233
        $automaticEmailText = '';
8234
        if (!empty($noReply)) {
8235
            $automaticEmailText = '<br />'.get_lang('This is an automatic email message. Please do not reply to it.');
8236
        }
8237
8238
        $params = [
8239
            'mail_header_style' => api_get_configuration_value('mail_header_style'),
8240
            'mail_content_style' => api_get_configuration_value('mail_content_style'),
8241
            'link' => $additionalParameters['link'] ?? '',
8242
            'automatic_email_text' => $automaticEmailText,
8243
            'content' => $body,
8244
            'theme' => api_get_visual_theme(),
8245
        ];
8246
8247
        if (!empty($senderEmail)) {
8248
            $message->from(new Address($senderEmail, $senderName));
8249
        }
8250
8251
        if (!empty($recipientEmail)) {
8252
            $message->to(new Address($recipientEmail, $recipientName));
8253
        }
8254
8255
        if (!empty($replyToEmail)) {
8256
            $message->replyTo(new Address($replyToEmail, $replyToName));
8257
        }
8258
8259
        $message
8260
            ->htmlTemplate('ChamiloCoreBundle:Mailer:Default/default.html.twig')
8261
            ->textTemplate('ChamiloCoreBundle:Mailer:Default/default.text.twig')
8262
        ;
8263
        $message->context($params);
8264
        Container::getMailer()->send($message);
8265
8266
        return true;
8267
    } catch (Exception $e) {
8268
        error_log($e->getMessage());
8269
    }
8270
8271
    if (!empty($additionalParameters)) {
8272
        $plugin = new AppPlugin();
8273
        $smsPlugin = $plugin->getSMSPluginLibrary();
8274
        if ($smsPlugin) {
0 ignored issues
show
introduced by
$smsPlugin is of type SmsPluginLibraryInterface, thus it always evaluated to true.
Loading history...
8275
            $smsPlugin->send($additionalParameters);
8276
        }
8277
    }
8278
8279
    return 1;
8280
}
8281
8282
/**
8283
 * @param string $tool       Possible values: GroupManager::GROUP_TOOL_*
8284
 * @param bool   $showHeader
8285
 */
8286
function api_protect_course_group($tool, $showHeader = true)
8287
{
8288
    $groupId = api_get_group_id();
8289
    if (!empty($groupId)) {
8290
        if (api_is_platform_admin()) {
8291
            return true;
8292
        }
8293
8294
        if (api_is_allowed_to_edit(false, true, true)) {
8295
            return true;
8296
        }
8297
8298
        $userId = api_get_user_id();
8299
        $sessionId = api_get_session_id();
8300
        if (!empty($sessionId)) {
8301
            if (api_is_coach($sessionId, api_get_course_int_id())) {
8302
                return true;
8303
            }
8304
8305
            if (api_is_drh()) {
8306
                if (SessionManager::isUserSubscribedAsHRM($sessionId, $userId)) {
8307
                    return true;
8308
                }
8309
            }
8310
        }
8311
8312
        $groupInfo = GroupManager::get_group_properties($groupId);
8313
8314
        // Group doesn't exists
8315
        if (empty($groupInfo)) {
8316
            api_not_allowed($showHeader);
8317
        }
8318
8319
        // Check group access
8320
        $allow = GroupManager::user_has_access(
8321
            $userId,
8322
            $groupInfo['iid'],
8323
            $tool
8324
        );
8325
8326
        if (!$allow) {
8327
            api_not_allowed($showHeader);
8328
        }
8329
    }
8330
8331
    return false;
8332
}
8333
8334
/**
8335
 * Check if a date is in a date range.
8336
 *
8337
 * @param datetime $startDate
8338
 * @param datetime $endDate
8339
 * @param datetime $currentDate
8340
 *
8341
 * @return bool true if date is in rage, false otherwise
8342
 */
8343
function api_is_date_in_date_range($startDate, $endDate, $currentDate = null)
8344
{
8345
    $startDate = strtotime(api_get_local_time($startDate));
8346
    $endDate = strtotime(api_get_local_time($endDate));
8347
    $currentDate = strtotime(api_get_local_time($currentDate));
8348
8349
    if ($currentDate >= $startDate && $currentDate <= $endDate) {
8350
        return true;
8351
    }
8352
8353
    return false;
8354
}
8355
8356
/**
8357
 * Eliminate the duplicates of a multidimensional array by sending the key.
8358
 *
8359
 * @param array $array multidimensional array
8360
 * @param int   $key   key to find to compare
8361
 *
8362
 * @return array
8363
 */
8364
function api_unique_multidim_array($array, $key)
8365
{
8366
    $temp_array = [];
8367
    $i = 0;
8368
    $key_array = [];
8369
8370
    foreach ($array as $val) {
8371
        if (!in_array($val[$key], $key_array)) {
8372
            $key_array[$i] = $val[$key];
8373
            $temp_array[$i] = $val;
8374
        }
8375
        $i++;
8376
    }
8377
8378
    return $temp_array;
8379
}
8380
8381
/**
8382
 * Limit the access to Session Admins when the limit_session_admin_role
8383
 * configuration variable is set to true.
8384
 */
8385
function api_protect_limit_for_session_admin()
8386
{
8387
    $limitAdmin = api_get_setting('limit_session_admin_role');
8388
    if (api_is_session_admin() && 'true' === $limitAdmin) {
8389
        api_not_allowed(true);
8390
    }
8391
}
8392
8393
/**
8394
 * Limits that a session admin has access to list users.
8395
 * When limit_session_admin_list_users configuration variable is set to true.
8396
 */
8397
function api_protect_session_admin_list_users()
8398
{
8399
    $limitAdmin = api_get_configuration_value('limit_session_admin_list_users');
8400
8401
    if (api_is_session_admin() && true === $limitAdmin) {
8402
        api_not_allowed(true);
8403
    }
8404
}
8405
8406
/**
8407
 * @return bool
8408
 */
8409
function api_is_student_view_active()
8410
{
8411
    $studentView = Session::read('studentview');
8412
8413
    return 'studentview' === $studentView;
8414
}
8415
8416
/**
8417
 * Adds a file inside the upload/$type/id.
8418
 *
8419
 * @param string $type
8420
 * @param array  $file
8421
 * @param int    $itemId
8422
 * @param string $cropParameters
8423
 *
8424
 * @deprecated use Resources
8425
 *
8426
 * @return array|bool
8427
 */
8428
function api_upload_file($type, $file, $itemId, $cropParameters = '')
8429
{
8430
    $upload = process_uploaded_file($file);
8431
    if ($upload) {
8432
        $name = api_replace_dangerous_char($file['name']);
8433
8434
        // No "dangerous" files
8435
        $name = disable_dangerous_file($name);
8436
8437
        $pathId = '/'.substr((string) $itemId, 0, 1).'/'.$itemId.'/';
8438
        $path = api_get_path(SYS_UPLOAD_PATH).$type.$pathId;
8439
8440
        if (!is_dir($path)) {
8441
            mkdir($path, api_get_permissions_for_new_directories(), true);
8442
        }
8443
8444
        $pathToSave = $path.$name;
8445
        $result = moveUploadedFile($file, $pathToSave);
8446
8447
        if ($result) {
8448
            if (!empty($cropParameters)) {
8449
                $image = new Image($pathToSave);
0 ignored issues
show
Deprecated Code introduced by
The class Image has been deprecated. ( Ignorable by Annotation )

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

8449
                $image = /** @scrutinizer ignore-deprecated */ new Image($pathToSave);
Loading history...
8450
                $image->crop($cropParameters);
8451
            }
8452
8453
            return ['path_to_save' => $pathId.$name];
8454
        }
8455
    }
8456
8457
    return false;
8458
}
8459
8460
/**
8461
 * @param string $type
8462
 * @param int    $itemId
8463
 * @param string $file
8464
 *
8465
 * @return bool
8466
 */
8467
function api_get_uploaded_web_url($type, $itemId, $file)
8468
{
8469
    return api_get_uploaded_file($type, $itemId, $file, true);
8470
}
8471
8472
/**
8473
 * @param string $type
8474
 * @param int    $itemId
8475
 * @param string $file
8476
 * @param bool   $getUrl
8477
 *
8478
 * @return bool
8479
 */
8480
function api_get_uploaded_file($type, $itemId, $file, $getUrl = false)
8481
{
8482
    $itemId = (int) $itemId;
8483
    $pathId = '/'.substr((string) $itemId, 0, 1).'/'.$itemId.'/';
8484
    $path = api_get_path(SYS_UPLOAD_PATH).$type.$pathId;
8485
    $file = basename($file);
8486
    $file = $path.'/'.$file;
8487
    if (Security::check_abs_path($file, $path) && is_file($file) && file_exists($file)) {
8488
        if ($getUrl) {
8489
            return str_replace(api_get_path(SYS_UPLOAD_PATH), api_get_path(WEB_UPLOAD_PATH), $file);
8490
        }
8491
8492
        return $file;
8493
    }
8494
8495
    return false;
8496
}
8497
8498
/**
8499
 * @param string $type
8500
 * @param int    $itemId
8501
 * @param string $file
8502
 * @param string $title
8503
 */
8504
function api_download_uploaded_file($type, $itemId, $file, $title = '')
8505
{
8506
    $file = api_get_uploaded_file($type, $itemId, $file);
8507
    if ($file) {
8508
        if (Security::check_abs_path($file, api_get_path(SYS_UPLOAD_PATH).$type)) {
8509
            DocumentManager::file_send_for_download($file, true, $title);
8510
            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...
8511
        }
8512
    }
8513
    api_not_allowed(true);
8514
}
8515
8516
/**
8517
 * @param string $type
8518
 * @param string $file
8519
 */
8520
function api_remove_uploaded_file($type, $file)
8521
{
8522
    $typePath = api_get_path(SYS_UPLOAD_PATH).$type;
8523
    $path = $typePath.'/'.$file;
8524
    if (Security::check_abs_path($path, $typePath) && file_exists($path) && is_file($path)) {
8525
        unlink($path);
8526
    }
8527
}
8528
8529
/**
8530
 * @param string $type
8531
 * @param int    $itemId
8532
 * @param string $file
8533
 *
8534
 * @return bool
8535
 */
8536
function api_remove_uploaded_file_by_id($type, $itemId, $file)
8537
{
8538
    $file = api_get_uploaded_file($type, $itemId, $file, false);
8539
    $typePath = api_get_path(SYS_UPLOAD_PATH).$type;
8540
    if (Security::check_abs_path($file, $typePath) && file_exists($file) && is_file($file)) {
8541
        unlink($file);
8542
8543
        return true;
8544
    }
8545
8546
    return false;
8547
}
8548
8549
/**
8550
 * Converts string value to float value.
8551
 *
8552
 * 3.141516 => 3.141516
8553
 * 3,141516 => 3.141516
8554
 *
8555
 * @todo WIP
8556
 *
8557
 * @param string $number
8558
 *
8559
 * @return float
8560
 */
8561
function api_float_val($number)
8562
{
8563
    $number = (float) str_replace(',', '.', trim($number));
8564
8565
    return $number;
8566
}
8567
8568
/**
8569
 * Converts float values
8570
 * Example if $decimals = 2.
8571
 *
8572
 * 3.141516 => 3.14
8573
 * 3,141516 => 3,14
8574
 *
8575
 * @param string $number            number in iso code
8576
 * @param int    $decimals
8577
 * @param string $decimalSeparator
8578
 * @param string $thousandSeparator
8579
 *
8580
 * @return bool|string
8581
 */
8582
function api_number_format($number, $decimals = 0, $decimalSeparator = '.', $thousandSeparator = ',')
8583
{
8584
    $number = api_float_val($number);
8585
8586
    return number_format($number, $decimals, $decimalSeparator, $thousandSeparator);
8587
}
8588
8589
/**
8590
 * Set location url with a exit break by default.
8591
 *
8592
 * @param string $url
8593
 * @param bool $exit
8594
 */
8595
function api_location($url, $exit = true)
8596
{
8597
    header('Location: '.$url);
8598
8599
    if ($exit) {
8600
        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...
8601
    }
8602
}
8603
8604
/**
8605
 * @return string
8606
 */
8607
function api_get_web_url()
8608
{
8609
    if ('test' === api_get_setting('server_type')) {
8610
        return api_get_path(WEB_PATH).'web/app_dev.php/';
8611
    } else {
8612
        return api_get_path(WEB_PATH).'web/';
8613
    }
8614
}
8615
8616
/**
8617
 * @param string $from
8618
 * @param string $to
8619
 *
8620
 * @return string
8621
 */
8622
function api_get_relative_path($from, $to)
8623
{
8624
    // some compatibility fixes for Windows paths
8625
    $from = is_dir($from) ? rtrim($from, '\/').'/' : $from;
8626
    $to = is_dir($to) ? rtrim($to, '\/').'/' : $to;
8627
    $from = str_replace('\\', '/', $from);
8628
    $to = str_replace('\\', '/', $to);
8629
8630
    $from = explode('/', $from);
8631
    $to = explode('/', $to);
8632
    $relPath = $to;
8633
8634
    foreach ($from as $depth => $dir) {
8635
        // find first non-matching dir
8636
        if ($dir === $to[$depth]) {
8637
            // ignore this directory
8638
            array_shift($relPath);
8639
        } else {
8640
            // get number of remaining dirs to $from
8641
            $remaining = count($from) - $depth;
8642
            if ($remaining > 1) {
8643
                // add traversals up to first matching dir
8644
                $padLength = (count($relPath) + $remaining - 1) * -1;
8645
                $relPath = array_pad($relPath, $padLength, '..');
8646
                break;
8647
            } else {
8648
                $relPath[0] = './'.$relPath[0];
8649
            }
8650
        }
8651
    }
8652
8653
    return implode('/', $relPath);
8654
}
8655
8656
/**
8657
 * Unserialize content using Brummann\Polyfill\Unserialize.
8658
 *
8659
 * @param string $type
8660
 * @param string $serialized
8661
 * @param bool   $ignoreErrors. Optional.
8662
 *
8663
 * @return mixed
8664
 */
8665
function api_unserialize_content($type, $serialized, $ignoreErrors = false)
8666
{
8667
    switch ($type) {
8668
        case 'career':
8669
        case 'sequence_graph':
8670
            $allowedClasses = [
8671
                \Fhaculty\Graph\Graph::class,
8672
                \Fhaculty\Graph\Set\VerticesMap::class,
8673
                \Fhaculty\Graph\Set\Vertices::class,
8674
                \Fhaculty\Graph\Set\Edges::class,
8675
            ];
8676
            break;
8677
        case 'lp':
8678
            $allowedClasses = [
8679
                learnpath::class,
8680
                learnpathItem::class,
8681
                aicc::class,
8682
                aiccBlock::class,
8683
                aiccItem::class,
8684
                aiccObjective::class,
8685
                aiccResource::class,
8686
                scorm::class,
8687
                scormItem::class,
8688
                scormMetadata::class,
8689
                scormOrganization::class,
8690
                scormResource::class,
8691
                Link::class,
8692
                LpItem::class,
8693
            ];
8694
            break;
8695
        case 'course':
8696
            $allowedClasses = [
8697
                \Chamilo\CourseBundle\Component\CourseCopy\Course::class,
8698
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Announcement::class,
8699
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Attendance::class,
8700
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\CalendarEvent::class,
8701
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\CourseCopyLearnpath::class,
8702
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\CourseCopyTestCategory::class,
8703
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\CourseDescription::class,
8704
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\CourseSession::class,
8705
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Document::class,
8706
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Forum::class,
8707
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\ForumCategory::class,
8708
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\ForumPost::class,
8709
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\ForumTopic::class,
8710
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Glossary::class,
8711
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\GradeBookBackup::class,
8712
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Link::class,
8713
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\LinkCategory::class,
8714
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Quiz::class,
8715
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\QuizQuestion::class,
8716
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\QuizQuestionOption::class,
8717
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\ScormDocument::class,
8718
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Survey::class,
8719
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\SurveyInvitation::class,
8720
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\SurveyQuestion::class,
8721
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Thematic::class,
8722
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\ToolIntro::class,
8723
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Wiki::class,
8724
                \Chamilo\CourseBundle\Component\CourseCopy\Resources\Work::class,
8725
                stdClass::class,
8726
            ];
8727
            break;
8728
        case 'not_allowed_classes':
8729
        default:
8730
            $allowedClasses = false;
8731
    }
8732
8733
    if ($ignoreErrors) {
8734
        return @UnserializeApi::unserialize(
8735
            $serialized,
8736
            ['allowed_classes' => $allowedClasses]
8737
        );
8738
    }
8739
8740
    return UnserializeApi::unserialize(
8741
        $serialized,
8742
        ['allowed_classes' => $allowedClasses]
8743
    );
8744
}
8745
8746
/**
8747
 * @param string $template
8748
 *
8749
 * @return string
8750
 */
8751
function api_find_template($template)
8752
{
8753
    return Template::findTemplateFilePath($template);
8754
}
8755
8756
/**
8757
 * @return array
8758
 */
8759
function api_get_language_list_for_flag()
8760
{
8761
    $table = Database::get_main_table(TABLE_MAIN_LANGUAGE);
8762
    $sql = "SELECT english_name, isocode FROM $table
8763
            ORDER BY original_name ASC";
8764
    static $languages = [];
8765
    if (empty($languages)) {
8766
        $result = Database::query($sql);
8767
        while ($row = Database::fetch_array($result)) {
8768
            $languages[$row['english_name']] = $row['isocode'];
8769
        }
8770
        $languages['english'] = 'gb';
8771
    }
8772
8773
    return $languages;
8774
}
8775
8776
/**
8777
 * @param string $name
8778
 *
8779
 * @return \ZipStream\ZipStream
8780
 */
8781
function api_create_zip($name)
8782
{
8783
    $zipStreamOptions = new \ZipStream\Option\Archive();
8784
    $zipStreamOptions->setSendHttpHeaders(true);
8785
    $zipStreamOptions->setContentDisposition('attachment');
8786
    $zipStreamOptions->setContentType('application/x-zip');
8787
8788
    $zip = new \ZipStream\ZipStream($name, $zipStreamOptions);
8789
8790
    return $zip;
8791
}
8792
8793
/**
8794
 * @return string
8795
 */
8796
function api_get_language_translate_html()
8797
{
8798
    $translate = api_get_configuration_value('translate_html');
8799
8800
    if (!$translate) {
8801
        return '';
8802
    }
8803
8804
    $languageList = api_get_languages();
8805
    $hideAll = '';
8806
    foreach ($languageList['all'] as $language) {
8807
        $hideAll .= '
8808
        $("span:lang('.$language['isocode'].')").filter(
8809
            function(e, val) {
8810
                // Only find the spans if they have set the lang
8811
                if ($(this).attr("lang") == null) {
8812
                    return false;
8813
                }
8814
8815
                // Ignore ckeditor classes
8816
                return !this.className.match(/cke(.*)/);
8817
        }).hide();'."\n";
8818
    }
8819
8820
    $userInfo = api_get_user_info();
8821
    $languageId = api_get_language_id($userInfo['language']);
8822
    $languageInfo = api_get_language_info($languageId);
8823
    $isoCode = 'en';
8824
8825
    if (!empty($languageInfo)) {
8826
        $isoCode = $languageInfo['isocode'];
8827
    }
8828
8829
    return '
8830
            $(function() {
8831
                '.$hideAll.'
8832
                var defaultLanguageFromUser = "'.$isoCode.'";
8833
8834
                $("span:lang('.$isoCode.')").filter(
8835
                    function() {
8836
                        // Ignore ckeditor classes
8837
                        return !this.className.match(/cke(.*)/);
8838
                }).show();
8839
8840
                var defaultLanguage = "";
8841
                var langFromUserFound = false;
8842
8843
                $(this).find("span").filter(
8844
                    function() {
8845
                        // Ignore ckeditor classes
8846
                        return !this.className.match(/cke(.*)/);
8847
                }).each(function() {
8848
                    defaultLanguage = $(this).attr("lang");
8849
                    if (defaultLanguage) {
8850
                        $(this).before().next("br").remove();
8851
                        if (defaultLanguageFromUser == defaultLanguage) {
8852
                            langFromUserFound = true;
8853
                        }
8854
                    }
8855
                });
8856
8857
                // Show default language
8858
                if (langFromUserFound == false && defaultLanguage) {
8859
                    $("span:lang("+defaultLanguage+")").filter(
8860
                    function() {
8861
                            // Ignore ckeditor classes
8862
                            return !this.className.match(/cke(.*)/);
8863
                    }).show();
8864
                }
8865
            });
8866
    ';
8867
}
8868