Passed
Push — master ( bb6d6a...9c6c3f )
by Julito
09:20
created

api_get_lp_entity()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
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 Chamilo\CourseBundle\Entity\CLp;
14
use ChamiloSession as Session;
15
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
16
use Symfony\Component\Finder\Finder;
17
use Symfony\Component\Mime\Address;
18
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
19
use Symfony\Component\Security\Core\User\UserInterface;
20
21
/**
22
 * This is a code library for Chamilo.
23
 * It is included by default in every Chamilo file (through including the global.inc.php)
24
 * This library is in process of being transferred to src/Chamilo/CoreBundle/Component/Utils/ChamiloApi.
25
 * Whenever a function is transferred to the ChamiloApi class, the places where it is used should include
26
 * the "use Chamilo\CoreBundle\Component\Utils\ChamiloApi;" statement.
27
 */
28
29
// PHP version requirement.
30
define('REQUIRED_PHP_VERSION', '7.2');
31
define('REQUIRED_MIN_MEMORY_LIMIT', '128');
32
define('REQUIRED_MIN_UPLOAD_MAX_FILESIZE', '10');
33
define('REQUIRED_MIN_POST_MAX_SIZE', '10');
34
35
// USER STATUS CONSTANTS
36
/** global status of a user: student */
37
define('STUDENT', 5);
38
/** global status of a user: course manager */
39
define('COURSEMANAGER', 1);
40
/** global status of a user: session admin */
41
define('SESSIONADMIN', 3);
42
/** global status of a user: human ressource manager */
43
define('DRH', 4);
44
/** global status of a user: human ressource manager */
45
define('ANONYMOUS', 6);
46
/** global status of a user: low security, necessary for inserting data from
47
 * the teacher through HTMLPurifier */
48
define('COURSEMANAGERLOWSECURITY', 10);
49
// Soft user status
50
define('PLATFORM_ADMIN', 11);
51
define('SESSION_COURSE_COACH', 12);
52
define('SESSION_GENERAL_COACH', 13);
53
define('COURSE_STUDENT', 14); //student subscribed in a course
54
define('SESSION_STUDENT', 15); //student subscribed in a session course
55
define('COURSE_TUTOR', 16); // student is tutor of a course (NOT in session)
56
define('STUDENT_BOSS', 17); // student is boss
57
define('INVITEE', 20);
58
define('HRM_REQUEST', 21); //HRM has request for vinculation with user
59
60
// COURSE VISIBILITY CONSTANTS
61
/** only visible for course admin */
62
define('COURSE_VISIBILITY_CLOSED', 0);
63
/** only visible for users registered in the course */
64
define('COURSE_VISIBILITY_REGISTERED', 1);
65
/** Open for all registered users on the platform */
66
define('COURSE_VISIBILITY_OPEN_PLATFORM', 2);
67
/** Open for the whole world */
68
define('COURSE_VISIBILITY_OPEN_WORLD', 3);
69
/** Invisible to all except admin */
70
define('COURSE_VISIBILITY_HIDDEN', 4);
71
72
define('COURSE_REQUEST_PENDING', 0);
73
define('COURSE_REQUEST_ACCEPTED', 1);
74
define('COURSE_REQUEST_REJECTED', 2);
75
define('DELETE_ACTION_ENABLED', false);
76
77
// EMAIL SENDING RECIPIENT CONSTANTS
78
define('SEND_EMAIL_EVERYONE', 1);
79
define('SEND_EMAIL_STUDENTS', 2);
80
define('SEND_EMAIL_TEACHERS', 3);
81
82
// SESSION VISIBILITY CONSTANTS
83
define('SESSION_VISIBLE_READ_ONLY', 1);
84
define('SESSION_VISIBLE', 2);
85
define('SESSION_INVISIBLE', 3); // not available
86
define('SESSION_AVAILABLE', 4);
87
88
define('SESSION_LINK_TARGET', '_self');
89
90
define('SUBSCRIBE_ALLOWED', 1);
91
define('SUBSCRIBE_NOT_ALLOWED', 0);
92
define('UNSUBSCRIBE_ALLOWED', 1);
93
define('UNSUBSCRIBE_NOT_ALLOWED', 0);
94
95
// SURVEY VISIBILITY CONSTANTS
96
define('SURVEY_VISIBLE_TUTOR', 0);
97
define('SURVEY_VISIBLE_TUTOR_STUDENT', 1);
98
define('SURVEY_VISIBLE_PUBLIC', 2);
99
100
// CONSTANTS defining all tools, using the english version
101
/* When you add a new tool you must add it into function api_get_tools_lists() too */
102
define('TOOL_DOCUMENT', 'document');
103
define('TOOL_LP_FINAL_ITEM', 'final_item');
104
define('TOOL_READOUT_TEXT', 'readout_text');
105
define('TOOL_THUMBNAIL', 'thumbnail');
106
define('TOOL_HOTPOTATOES', 'hotpotatoes');
107
define('TOOL_CALENDAR_EVENT', 'calendar_event');
108
define('TOOL_LINK', 'link');
109
define('TOOL_LINK_CATEGORY', 'link_category');
110
define('TOOL_COURSE_DESCRIPTION', 'course_description');
111
define('TOOL_SEARCH', 'search');
112
define('TOOL_LEARNPATH', 'learnpath');
113
define('TOOL_LEARNPATH_CATEGORY', 'learnpath_category');
114
define('TOOL_AGENDA', 'agenda');
115
define('TOOL_ANNOUNCEMENT', 'announcement');
116
define('TOOL_FORUM', 'forum');
117
define('TOOL_FORUM_CATEGORY', 'forum_category');
118
define('TOOL_FORUM_THREAD', 'forum_thread');
119
define('TOOL_FORUM_POST', 'forum_post');
120
define('TOOL_FORUM_ATTACH', 'forum_attachment');
121
define('TOOL_FORUM_THREAD_QUALIFY', 'forum_thread_qualify');
122
define('TOOL_THREAD', 'thread');
123
define('TOOL_POST', 'post');
124
define('TOOL_DROPBOX', 'dropbox');
125
define('TOOL_QUIZ', 'quiz');
126
define('TOOL_TEST_CATEGORY', 'test_category');
127
define('TOOL_USER', 'user');
128
define('TOOL_GROUP', 'group');
129
define('TOOL_BLOGS', 'blog_management');
130
define('TOOL_CHAT', 'chat');
131
define('TOOL_STUDENTPUBLICATION', 'student_publication');
132
define('TOOL_TRACKING', 'tracking');
133
define('TOOL_HOMEPAGE_LINK', 'homepage_link');
134
define('TOOL_COURSE_SETTING', 'course_setting');
135
define('TOOL_BACKUP', 'backup');
136
define('TOOL_COPY_COURSE_CONTENT', 'copy_course_content');
137
define('TOOL_RECYCLE_COURSE', 'recycle_course');
138
define('TOOL_COURSE_HOMEPAGE', 'course_homepage');
139
define('TOOL_COURSE_RIGHTS_OVERVIEW', 'course_rights');
140
define('TOOL_UPLOAD', 'file_upload');
141
define('TOOL_COURSE_MAINTENANCE', 'course_maintenance');
142
define('TOOL_SURVEY', 'survey');
143
define('TOOL_WIKI', 'wiki');
144
define('TOOL_GLOSSARY', 'glossary');
145
define('TOOL_GRADEBOOK', 'gradebook');
146
define('TOOL_NOTEBOOK', 'notebook');
147
define('TOOL_ATTENDANCE', 'attendance');
148
define('TOOL_COURSE_PROGRESS', 'course_progress');
149
define('TOOL_PORTFOLIO', 'portfolio');
150
define('TOOL_PLAGIARISM', 'compilatio');
151
152
// CONSTANTS defining Chamilo interface sections
153
define('SECTION_CAMPUS', 'mycampus');
154
define('SECTION_COURSES', 'mycourses');
155
define('SECTION_CATALOG', 'catalog');
156
define('SECTION_MYPROFILE', 'myprofile');
157
define('SECTION_MYAGENDA', 'myagenda');
158
define('SECTION_COURSE_ADMIN', 'course_admin');
159
define('SECTION_PLATFORM_ADMIN', 'platform_admin');
160
define('SECTION_MYGRADEBOOK', 'mygradebook');
161
define('SECTION_TRACKING', 'session_my_space');
162
define('SECTION_SOCIAL', 'social-network');
163
define('SECTION_DASHBOARD', 'dashboard');
164
define('SECTION_REPORTS', 'reports');
165
define('SECTION_GLOBAL', 'global');
166
define('SECTION_INCLUDE', 'include');
167
168
// CONSTANT name for local authentication source
169
define('PLATFORM_AUTH_SOURCE', 'platform');
170
define('CAS_AUTH_SOURCE', 'cas');
171
define('LDAP_AUTH_SOURCE', 'extldap');
172
173
// CONSTANT defining the default HotPotatoes files directory
174
define('DIR_HOTPOTATOES', '/HotPotatoes_files');
175
176
// event logs types
177
define('LOG_COURSE_DELETE', 'course_deleted');
178
define('LOG_COURSE_CREATE', 'course_created');
179
define('LOG_COURSE_SETTINGS_CHANGED', 'course_settings_changed');
180
181
// @todo replace 'soc_gr' with social_group
182
define('LOG_GROUP_PORTAL_CREATED', 'soc_gr_created');
183
define('LOG_GROUP_PORTAL_UPDATED', 'soc_gr_updated');
184
define('LOG_GROUP_PORTAL_DELETED', 'soc_gr_deleted');
185
define('LOG_GROUP_PORTAL_USER_DELETE_ALL', 'soc_gr_delete_users');
186
187
define('LOG_GROUP_PORTAL_ID', 'soc_gr_portal_id');
188
define('LOG_GROUP_PORTAL_REL_USER_ARRAY', 'soc_gr_user_array');
189
190
define('LOG_GROUP_PORTAL_USER_SUBSCRIBED', 'soc_gr_u_subs');
191
define('LOG_GROUP_PORTAL_USER_UNSUBSCRIBED', 'soc_gr_u_unsubs');
192
define('LOG_GROUP_PORTAL_USER_UPDATE_ROLE', 'soc_gr_update_role');
193
194
define('LOG_USER_DELETE', 'user_deleted');
195
define('LOG_USER_CREATE', 'user_created');
196
define('LOG_USER_UPDATE', 'user_updated');
197
define('LOG_USER_PASSWORD_UPDATE', 'user_password_updated');
198
define('LOG_USER_ENABLE', 'user_enable');
199
define('LOG_USER_DISABLE', 'user_disable');
200
define('LOG_USER_ANONYMIZE', 'user_anonymized');
201
define('LOG_USER_FIELD_CREATE', 'user_field_created');
202
define('LOG_USER_FIELD_DELETE', 'user_field_deleted');
203
define('LOG_SESSION_CREATE', 'session_created');
204
define('LOG_SESSION_DELETE', 'session_deleted');
205
define('LOG_SESSION_ADD_USER_COURSE', 'session_add_user_course');
206
define('LOG_SESSION_DELETE_USER_COURSE', 'session_delete_user_course');
207
define('LOG_SESSION_ADD_USER', 'session_add_user');
208
define('LOG_SESSION_DELETE_USER', 'session_delete_user');
209
define('LOG_SESSION_ADD_COURSE', 'session_add_course');
210
define('LOG_SESSION_DELETE_COURSE', 'session_delete_course');
211
define('LOG_SESSION_CATEGORY_CREATE', 'session_cat_created'); //changed in 1.9.8
212
define('LOG_SESSION_CATEGORY_DELETE', 'session_cat_deleted'); //changed in 1.9.8
213
define('LOG_CONFIGURATION_SETTINGS_CHANGE', 'settings_changed');
214
define('LOG_PLATFORM_LANGUAGE_CHANGE', 'platform_lng_changed'); //changed in 1.9.8
215
define('LOG_SUBSCRIBE_USER_TO_COURSE', 'user_subscribed');
216
define('LOG_UNSUBSCRIBE_USER_FROM_COURSE', 'user_unsubscribed');
217
define('LOG_ATTEMPTED_FORCED_LOGIN', 'attempted_forced_login');
218
define('LOG_PLUGIN_CHANGE', 'plugin_changed');
219
define('LOG_HOMEPAGE_CHANGED', 'homepage_changed');
220
define('LOG_PROMOTION_CREATE', 'promotion_created');
221
define('LOG_PROMOTION_DELETE', 'promotion_deleted');
222
define('LOG_CAREER_CREATE', 'career_created');
223
define('LOG_CAREER_DELETE', 'career_deleted');
224
define('LOG_USER_PERSONAL_DOC_DELETED', 'user_doc_deleted');
225
define('LOG_WIKI_ACCESS', 'wiki_page_view');
226
// All results from an exercise
227
define('LOG_EXERCISE_RESULT_DELETE', 'exe_result_deleted');
228
// Logs only the one attempt
229
define('LOG_EXERCISE_ATTEMPT_DELETE', 'exe_attempt_deleted');
230
define('LOG_LP_ATTEMPT_DELETE', 'lp_attempt_deleted');
231
define('LOG_QUESTION_RESULT_DELETE', 'qst_attempt_deleted');
232
233
define('LOG_MY_FOLDER_CREATE', 'my_folder_created');
234
define('LOG_MY_FOLDER_CHANGE', 'my_folder_changed');
235
define('LOG_MY_FOLDER_DELETE', 'my_folder_deleted');
236
define('LOG_MY_FOLDER_COPY', 'my_folder_copied');
237
define('LOG_MY_FOLDER_CUT', 'my_folder_cut');
238
define('LOG_MY_FOLDER_PASTE', 'my_folder_pasted');
239
define('LOG_MY_FOLDER_UPLOAD', 'my_folder_uploaded');
240
241
// Event logs data types (max 20 chars)
242
define('LOG_COURSE_CODE', 'course_code');
243
define('LOG_COURSE_ID', 'course_id');
244
define('LOG_USER_ID', 'user_id');
245
define('LOG_USER_OBJECT', 'user_object');
246
define('LOG_USER_FIELD_VARIABLE', 'user_field_variable');
247
define('LOG_SESSION_ID', 'session_id');
248
249
define('LOG_QUESTION_ID', 'question_id');
250
define('LOG_SESSION_CATEGORY_ID', 'session_category_id');
251
define('LOG_CONFIGURATION_SETTINGS_CATEGORY', 'settings_category');
252
define('LOG_CONFIGURATION_SETTINGS_VARIABLE', 'settings_variable');
253
define('LOG_PLATFORM_LANGUAGE', 'default_platform_language');
254
define('LOG_PLUGIN_UPLOAD', 'plugin_upload');
255
define('LOG_PLUGIN_ENABLE', 'plugin_enable');
256
define('LOG_PLUGIN_SETTINGS_CHANGE', 'plugin_settings_change');
257
define('LOG_CAREER_ID', 'career_id');
258
define('LOG_PROMOTION_ID', 'promotion_id');
259
define('LOG_GRADEBOOK_LOCKED', 'gradebook_locked');
260
define('LOG_GRADEBOOK_UNLOCKED', 'gradebook_unlocked');
261
define('LOG_GRADEBOOK_ID', 'gradebook_id');
262
define('LOG_WIKI_PAGE_ID', 'wiki_page_id');
263
define('LOG_EXERCISE_ID', 'exercise_id');
264
define('LOG_EXERCISE_AND_USER_ID', 'exercise_and_user_id');
265
define('LOG_LP_ID', 'lp_id');
266
define('LOG_EXERCISE_ATTEMPT_QUESTION_ID', 'exercise_a_q_id');
267
define('LOG_EXERCISE_ATTEMPT', 'exe_id');
268
269
define('LOG_WORK_DIR_DELETE', 'work_dir_delete');
270
define('LOG_WORK_FILE_DELETE', 'work_file_delete');
271
define('LOG_WORK_DATA', 'work_data_array');
272
273
define('LOG_MY_FOLDER_PATH', 'path');
274
define('LOG_MY_FOLDER_NEW_PATH', 'new_path');
275
276
define('LOG_TERM_CONDITION_ACCEPTED', 'term_condition_accepted');
277
define('LOG_USER_CONFIRMED_EMAIL', 'user_confirmed_email');
278
define('LOG_USER_REMOVED_LEGAL_ACCEPT', 'user_removed_legal_accept');
279
280
define('LOG_USER_DELETE_ACCOUNT_REQUEST', 'user_delete_account_request');
281
282
define('LOG_QUESTION_CREATED', 'question_created');
283
define('LOG_QUESTION_UPDATED', 'question_updated');
284
define('LOG_QUESTION_DELETED', 'question_deleted');
285
define('LOG_QUESTION_REMOVED_FROM_QUIZ', 'question_removed_from_quiz');
286
287
define('USERNAME_PURIFIER', '/[^0-9A-Za-z_\.-]/');
288
289
//used when login_is_email setting is true
290
define('USERNAME_PURIFIER_MAIL', '/[^0-9A-Za-z_\.@]/');
291
define('USERNAME_PURIFIER_SHALLOW', '/\s/');
292
293
// This constant is a result of Windows OS detection, it has a boolean value:
294
// true whether the server runs on Windows OS, false otherwise.
295
define('IS_WINDOWS_OS', api_is_windows_os());
296
297
// iconv extension, for PHP5 on Windows it is installed by default.
298
define('ICONV_INSTALLED', function_exists('iconv'));
299
define('MBSTRING_INSTALLED', function_exists('mb_strlen')); // mbstring extension.
300
301
// Patterns for processing paths. Examples.
302
define('REPEATED_SLASHES_PURIFIER', '/\/{2,}/'); // $path = preg_replace(REPEATED_SLASHES_PURIFIER, '/', $path);
303
define('VALID_WEB_PATH', '/https?:\/\/[^\/]*(\/.*)?/i'); // $is_valid_path = preg_match(VALID_WEB_PATH, $path);
304
// $new_path = preg_replace(VALID_WEB_SERVER_BASE, $new_base, $path);
305
define('VALID_WEB_SERVER_BASE', '/https?:\/\/[^\/]*/i');
306
// Constants for api_get_path() and api_get_path_type(), etc. - registered path types.
307
// basic (leaf elements)
308
define('REL_CODE_PATH', 'REL_CODE_PATH');
309
define('REL_COURSE_PATH', 'REL_COURSE_PATH');
310
define('REL_HOME_PATH', 'REL_HOME_PATH');
311
312
// Constants for api_get_path() and api_get_path_type(), etc. - registered path types.
313
define('WEB_PATH', 'WEB_PATH');
314
define('SYS_PATH', 'SYS_PATH');
315
define('SYMFONY_SYS_PATH', 'SYMFONY_SYS_PATH');
316
define('SYS_UPLOAD_PATH', 'SYS_UPLOAD_PATH');
317
define('WEB_UPLOAD_PATH', 'WEB_UPLOAD_PATH');
318
319
define('REL_PATH', 'REL_PATH');
320
define('WEB_COURSE_PATH', 'WEB_COURSE_PATH');
321
define('WEB_CODE_PATH', 'WEB_CODE_PATH');
322
define('SYS_CODE_PATH', 'SYS_CODE_PATH');
323
define('SYS_LANG_PATH', 'SYS_LANG_PATH');
324
define('WEB_IMG_PATH', 'WEB_IMG_PATH');
325
define('WEB_CSS_PATH', 'WEB_CSS_PATH');
326
define('WEB_PUBLIC_PATH', 'WEB_PUBLIC_PATH');
327
define('SYS_CSS_PATH', 'SYS_CSS_PATH');
328
define('SYS_PLUGIN_PATH', 'SYS_PLUGIN_PATH');
329
define('WEB_PLUGIN_PATH', 'WEB_PLUGIN_PATH');
330
define('WEB_PLUGIN_ASSET_PATH', 'WEB_PLUGIN_ASSET_PATH');
331
define('SYS_ARCHIVE_PATH', 'SYS_ARCHIVE_PATH');
332
define('WEB_ARCHIVE_PATH', 'WEB_ARCHIVE_PATH');
333
define('LIBRARY_PATH', 'LIBRARY_PATH');
334
define('CONFIGURATION_PATH', 'CONFIGURATION_PATH');
335
define('WEB_LIBRARY_PATH', 'WEB_LIBRARY_PATH');
336
define('WEB_LIBRARY_JS_PATH', 'WEB_LIBRARY_JS_PATH');
337
define('WEB_AJAX_PATH', 'WEB_AJAX_PATH');
338
define('SYS_TEST_PATH', 'SYS_TEST_PATH');
339
define('SYS_TEMPLATE_PATH', 'SYS_TEMPLATE_PATH');
340
define('SYS_PUBLIC_PATH', 'SYS_PUBLIC_PATH');
341
define('SYS_FONTS_PATH', 'SYS_FONTS_PATH');
342
343
// Relations type with Course manager
344
define('COURSE_RELATION_TYPE_COURSE_MANAGER', 1);
345
define('SESSION_RELATION_TYPE_COURSE_MANAGER', 1);
346
347
// Relations type with Human resources manager
348
define('COURSE_RELATION_TYPE_RRHH', 1);
349
define('SESSION_RELATION_TYPE_RRHH', 1);
350
351
//User image sizes
352
define('USER_IMAGE_SIZE_ORIGINAL', 1);
353
define('USER_IMAGE_SIZE_BIG', 2);
354
define('USER_IMAGE_SIZE_MEDIUM', 3);
355
define('USER_IMAGE_SIZE_SMALL', 4);
356
357
// Relation type between users
358
define('USER_UNKNOWN', 0);
359
define('USER_RELATION_TYPE_UNKNOWN', 1);
360
define('USER_RELATION_TYPE_PARENT', 2); // should be deprecated is useless
361
define('USER_RELATION_TYPE_FRIEND', 3);
362
define('USER_RELATION_TYPE_GOODFRIEND', 4); // should be deprecated is useless
363
define('USER_RELATION_TYPE_ENEMY', 5); // should be deprecated is useless
364
define('USER_RELATION_TYPE_DELETED', 6);
365
define('USER_RELATION_TYPE_RRHH', 7);
366
define('USER_RELATION_TYPE_BOSS', 8);
367
define('USER_RELATION_TYPE_HRM_REQUEST', 9);
368
369
// Gradebook link constants
370
// Please do not change existing values, they are used in the database !
371
define('GRADEBOOK_ITEM_LIMIT', 1000);
372
373
define('LINK_EXERCISE', 1);
374
define('LINK_DROPBOX', 2);
375
define('LINK_STUDENTPUBLICATION', 3);
376
define('LINK_LEARNPATH', 4);
377
define('LINK_FORUM_THREAD', 5);
378
//define('LINK_WORK',6);
379
define('LINK_ATTENDANCE', 7);
380
define('LINK_SURVEY', 8);
381
define('LINK_HOTPOTATOES', 9);
382
383
// Score display types constants
384
define('SCORE_DIV', 1); // X / Y
385
define('SCORE_PERCENT', 2); // XX %
386
define('SCORE_DIV_PERCENT', 3); // X / Y (XX %)
387
define('SCORE_AVERAGE', 4); // XX %
388
define('SCORE_DECIMAL', 5); // 0.50  (X/Y)
389
define('SCORE_BAR', 6); // Uses the Display::bar_progress function
390
define('SCORE_SIMPLE', 7); // X
391
define('SCORE_IGNORE_SPLIT', 8); //  ??
392
define('SCORE_DIV_PERCENT_WITH_CUSTOM', 9); // X / Y (XX %) - Good!
393
define('SCORE_CUSTOM', 10); // Good!
394
define('SCORE_DIV_SIMPLE_WITH_CUSTOM', 11); // X - Good!
395
define('SCORE_DIV_SIMPLE_WITH_CUSTOM_LETTERS', 12); // X - Good!
396
define('SCORE_ONLY_SCORE', 13); // X - Good!
397
define('SCORE_NUMERIC', 14);
398
399
define('SCORE_BOTH', 1);
400
define('SCORE_ONLY_DEFAULT', 2);
401
define('SCORE_ONLY_CUSTOM', 3);
402
403
// From display.lib.php
404
405
define('MAX_LENGTH_BREADCRUMB', 100);
406
define('ICON_SIZE_ATOM', 8);
407
define('ICON_SIZE_TINY', 16);
408
define('ICON_SIZE_SMALL', 22);
409
define('ICON_SIZE_MEDIUM', 32);
410
define('ICON_SIZE_LARGE', 48);
411
define('ICON_SIZE_BIG', 64);
412
define('ICON_SIZE_HUGE', 128);
413
define('SHOW_TEXT_NEAR_ICONS', false);
414
415
// Session catalog
416
define('CATALOG_COURSES', 0);
417
define('CATALOG_SESSIONS', 1);
418
define('CATALOG_COURSES_SESSIONS', 2);
419
420
// Hook type events, pre-process and post-process.
421
// All means to be executed for both hook event types
422
define('HOOK_EVENT_TYPE_PRE', 0);
423
define('HOOK_EVENT_TYPE_POST', 1);
424
define('HOOK_EVENT_TYPE_ALL', 10);
425
426
define('CAREER_STATUS_ACTIVE', 1);
427
define('CAREER_STATUS_INACTIVE', 0);
428
429
define('PROMOTION_STATUS_ACTIVE', 1);
430
define('PROMOTION_STATUS_INACTIVE', 0);
431
432
// Group permissions
433
define('GROUP_PERMISSION_OPEN', '1');
434
define('GROUP_PERMISSION_CLOSED', '2');
435
436
// Group user permissions
437
define('GROUP_USER_PERMISSION_ADMIN', 1); // the admin of a group
438
define('GROUP_USER_PERMISSION_READER', 2); // a normal user
439
define('GROUP_USER_PERMISSION_PENDING_INVITATION', 3); // When an admin/moderator invites a user
440
define('GROUP_USER_PERMISSION_PENDING_INVITATION_SENT_BY_USER', 4); // an user joins a group
441
define('GROUP_USER_PERMISSION_MODERATOR', 5); // a moderator
442
define('GROUP_USER_PERMISSION_ANONYMOUS', 6); // an anonymous user
443
define('GROUP_USER_PERMISSION_HRM', 7); // a human resources manager
444
445
define('GROUP_IMAGE_SIZE_ORIGINAL', 1);
446
define('GROUP_IMAGE_SIZE_BIG', 2);
447
define('GROUP_IMAGE_SIZE_MEDIUM', 3);
448
define('GROUP_IMAGE_SIZE_SMALL', 4);
449
define('GROUP_TITLE_LENGTH', 50);
450
451
// Exercise
452
// @todo move into a class
453
define('ALL_ON_ONE_PAGE', 1);
454
define('ONE_PER_PAGE', 2);
455
456
define('EXERCISE_FEEDBACK_TYPE_END', 0); //Feedback 		 - show score and expected answers
457
define('EXERCISE_FEEDBACK_TYPE_DIRECT', 1); //DirectFeedback - Do not show score nor answers
458
define('EXERCISE_FEEDBACK_TYPE_EXAM', 2); // NoFeedback 	 - Show score only
459
define('EXERCISE_FEEDBACK_TYPE_POPUP', 3); // Popup BT#15827
460
461
define('RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS', 0); //show score and expected answers
462
define('RESULT_DISABLE_NO_SCORE_AND_EXPECTED_ANSWERS', 1); //Do not show score nor answers
463
define('RESULT_DISABLE_SHOW_SCORE_ONLY', 2); //Show score only
464
define('RESULT_DISABLE_SHOW_FINAL_SCORE_ONLY_WITH_CATEGORIES', 3); //Show final score only with categories
465
define('RESULT_DISABLE_SHOW_SCORE_ATTEMPT_SHOW_ANSWERS_LAST_ATTEMPT', 4);
466
define('RESULT_DISABLE_DONT_SHOW_SCORE_ONLY_IF_USER_FINISHES_ATTEMPTS_SHOW_ALWAYS_FEEDBACK', 5);
467
define('RESULT_DISABLE_RANKING', 6);
468
define('RESULT_DISABLE_SHOW_ONLY_IN_CORRECT_ANSWER', 7);
469
define('RESULT_DISABLE_SHOW_SCORE_AND_EXPECTED_ANSWERS_AND_RANKING', 8);
470
471
define('EXERCISE_MAX_NAME_SIZE', 80);
472
473
// Question types (edit next array as well when adding values)
474
// @todo move into a class
475
define('UNIQUE_ANSWER', 1);
476
define('MULTIPLE_ANSWER', 2);
477
define('FILL_IN_BLANKS', 3);
478
define('MATCHING', 4);
479
define('FREE_ANSWER', 5);
480
define('HOT_SPOT', 6);
481
define('HOT_SPOT_ORDER', 7);
482
define('HOT_SPOT_DELINEATION', 8);
483
define('MULTIPLE_ANSWER_COMBINATION', 9);
484
define('UNIQUE_ANSWER_NO_OPTION', 10);
485
define('MULTIPLE_ANSWER_TRUE_FALSE', 11);
486
define('MULTIPLE_ANSWER_COMBINATION_TRUE_FALSE', 12);
487
define('ORAL_EXPRESSION', 13);
488
define('GLOBAL_MULTIPLE_ANSWER', 14);
489
define('MEDIA_QUESTION', 15);
490
define('CALCULATED_ANSWER', 16);
491
define('UNIQUE_ANSWER_IMAGE', 17);
492
define('DRAGGABLE', 18);
493
define('MATCHING_DRAGGABLE', 19);
494
define('ANNOTATION', 20);
495
define('READING_COMPREHENSION', 21);
496
define('MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY', 22);
497
498
define('EXERCISE_CATEGORY_RANDOM_SHUFFLED', 1);
499
define('EXERCISE_CATEGORY_RANDOM_ORDERED', 2);
500
define('EXERCISE_CATEGORY_RANDOM_DISABLED', 0);
501
502
// Question selection type
503
define('EX_Q_SELECTION_ORDERED', 1);
504
define('EX_Q_SELECTION_RANDOM', 2);
505
define('EX_Q_SELECTION_CATEGORIES_ORDERED_QUESTIONS_ORDERED', 3);
506
define('EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_ORDERED', 4);
507
define('EX_Q_SELECTION_CATEGORIES_ORDERED_QUESTIONS_RANDOM', 5);
508
define('EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_RANDOM', 6);
509
define('EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_ORDERED_NO_GROUPED', 7);
510
define('EX_Q_SELECTION_CATEGORIES_RANDOM_QUESTIONS_RANDOM_NO_GROUPED', 8);
511
define('EX_Q_SELECTION_CATEGORIES_ORDERED_BY_PARENT_QUESTIONS_ORDERED', 9);
512
define('EX_Q_SELECTION_CATEGORIES_ORDERED_BY_PARENT_QUESTIONS_RANDOM', 10);
513
514
// Used to save the skill_rel_item table
515
define('ITEM_TYPE_EXERCISE', 1);
516
define('ITEM_TYPE_HOTPOTATOES', 2);
517
define('ITEM_TYPE_LINK', 3);
518
define('ITEM_TYPE_LEARNPATH', 4);
519
define('ITEM_TYPE_GRADEBOOK', 5);
520
define('ITEM_TYPE_STUDENT_PUBLICATION', 6);
521
//define('ITEM_TYPE_FORUM', 7);
522
define('ITEM_TYPE_ATTENDANCE', 8);
523
define('ITEM_TYPE_SURVEY', 9);
524
define('ITEM_TYPE_FORUM_THREAD', 10);
525
526
// one big string with all question types, for the validator in pear/HTML/QuickForm/Rule/QuestionType
527
define(
528
    'QUESTION_TYPES',
529
    UNIQUE_ANSWER.':'.
530
    MULTIPLE_ANSWER.':'.
531
    FILL_IN_BLANKS.':'.
532
    MATCHING.':'.
533
    FREE_ANSWER.':'.
534
    HOT_SPOT.':'.
535
    HOT_SPOT_ORDER.':'.
536
    HOT_SPOT_DELINEATION.':'.
537
    MULTIPLE_ANSWER_COMBINATION.':'.
538
    UNIQUE_ANSWER_NO_OPTION.':'.
539
    MULTIPLE_ANSWER_TRUE_FALSE.':'.
540
    MULTIPLE_ANSWER_COMBINATION_TRUE_FALSE.':'.
541
    ORAL_EXPRESSION.':'.
542
    GLOBAL_MULTIPLE_ANSWER.':'.
543
    MEDIA_QUESTION.':'.
544
    CALCULATED_ANSWER.':'.
545
    UNIQUE_ANSWER_IMAGE.':'.
546
    DRAGGABLE.':'.
547
    MATCHING_DRAGGABLE.':'.
548
    MULTIPLE_ANSWER_TRUE_FALSE_DEGREE_CERTAINTY.':'.
549
    ANNOTATION
550
);
551
552
//Some alias used in the QTI exports
553
define('MCUA', 1);
554
define('TF', 1);
555
define('MCMA', 2);
556
define('FIB', 3);
557
558
// Skills
559
define('SKILL_TYPE_REQUIREMENT', 'required');
560
define('SKILL_TYPE_ACQUIRED', 'acquired');
561
define('SKILL_TYPE_BOTH', 'both');
562
563
// Message
564
define('MESSAGE_STATUS_NEW', '0');
565
define('MESSAGE_STATUS_UNREAD', '1');
566
//2 ??
567
define('MESSAGE_STATUS_DELETED', '3');
568
define('MESSAGE_STATUS_OUTBOX', '4');
569
define('MESSAGE_STATUS_INVITATION_PENDING', '5');
570
define('MESSAGE_STATUS_INVITATION_ACCEPTED', '6');
571
define('MESSAGE_STATUS_INVITATION_DENIED', '7');
572
define('MESSAGE_STATUS_WALL', '8');
573
define('MESSAGE_STATUS_WALL_DELETE', '9');
574
define('MESSAGE_STATUS_WALL_POST', '10');
575
define('MESSAGE_STATUS_CONVERSATION', '11');
576
define('MESSAGE_STATUS_FORUM', '12');
577
define('MESSAGE_STATUS_PROMOTED', '13');
578
579
// Images
580
define('IMAGE_WALL_SMALL_SIZE', 200);
581
define('IMAGE_WALL_MEDIUM_SIZE', 500);
582
define('IMAGE_WALL_BIG_SIZE', 2000);
583
define('IMAGE_WALL_SMALL', 'small');
584
define('IMAGE_WALL_MEDIUM', 'medium');
585
define('IMAGE_WALL_BIG', 'big');
586
587
// Social PLUGIN PLACES
588
define('SOCIAL_LEFT_PLUGIN', 1);
589
define('SOCIAL_CENTER_PLUGIN', 2);
590
define('SOCIAL_RIGHT_PLUGIN', 3);
591
define('CUT_GROUP_NAME', 50);
592
593
/**
594
 * FormValidator Filter.
595
 */
596
define('NO_HTML', 1);
597
define('STUDENT_HTML', 2);
598
define('TEACHER_HTML', 3);
599
define('STUDENT_HTML_FULLPAGE', 4);
600
define('TEACHER_HTML_FULLPAGE', 5);
601
602
// Timeline
603
define('TIMELINE_STATUS_ACTIVE', '1');
604
define('TIMELINE_STATUS_INACTIVE', '2');
605
606
// Event email template class
607
define('EVENT_EMAIL_TEMPLATE_ACTIVE', 1);
608
define('EVENT_EMAIL_TEMPLATE_INACTIVE', 0);
609
610
// Course home
611
define('SHORTCUTS_HORIZONTAL', 0);
612
define('SHORTCUTS_VERTICAL', 1);
613
614
// Image class
615
define('IMAGE_PROCESSOR', 'gd'); // 'imagick' or 'gd' strings
616
617
// Course copy
618
define('FILE_SKIP', 1);
619
define('FILE_RENAME', 2);
620
define('FILE_OVERWRITE', 3);
621
define('UTF8_CONVERT', false); //false by default
622
623
define('DOCUMENT', 'file');
624
define('FOLDER', 'folder');
625
626
define('RESOURCE_ASSET', 'asset');
627
define('RESOURCE_DOCUMENT', 'document');
628
define('RESOURCE_GLOSSARY', 'glossary');
629
define('RESOURCE_EVENT', 'calendar_event');
630
define('RESOURCE_LINK', 'link');
631
define('RESOURCE_COURSEDESCRIPTION', 'course_description');
632
define('RESOURCE_LEARNPATH', 'learnpath');
633
define('RESOURCE_LEARNPATH_CATEGORY', 'learnpath_category');
634
define('RESOURCE_ANNOUNCEMENT', 'announcement');
635
define('RESOURCE_FORUM', 'forum');
636
define('RESOURCE_FORUMTOPIC', 'thread');
637
define('RESOURCE_FORUMPOST', 'post');
638
define('RESOURCE_QUIZ', 'quiz');
639
define('RESOURCE_TEST_CATEGORY', 'test_category');
640
define('RESOURCE_QUIZQUESTION', 'Exercise_Question');
641
define('RESOURCE_TOOL_INTRO', 'Tool introduction');
642
define('RESOURCE_LINKCATEGORY', 'Link_Category');
643
define('RESOURCE_FORUMCATEGORY', 'Forum_Category');
644
define('RESOURCE_SCORM', 'Scorm');
645
define('RESOURCE_SURVEY', 'survey');
646
define('RESOURCE_SURVEYQUESTION', 'survey_question');
647
define('RESOURCE_SURVEYINVITATION', 'survey_invitation');
648
define('RESOURCE_WIKI', 'wiki');
649
define('RESOURCE_THEMATIC', 'thematic');
650
define('RESOURCE_ATTENDANCE', 'attendance');
651
define('RESOURCE_WORK', 'work');
652
define('RESOURCE_SESSION_COURSE', 'session_course');
653
define('RESOURCE_GRADEBOOK', 'gradebook');
654
define('ADD_THEMATIC_PLAN', 6);
655
656
// Max online users to show per page (whoisonline)
657
define('MAX_ONLINE_USERS', 12);
658
659
// Number of characters maximum to show in preview of course blog posts
660
define('BLOG_MAX_PREVIEW_CHARS', 800);
661
// HTML string to replace with a 'Read more...' link
662
define('BLOG_PAGE_BREAK', '<div style="page-break-after: always"><span style="display: none;">&nbsp;</span></div>');
663
664
// Make sure the CHAMILO_LOAD_WYSIWYG constant is defined
665
// To remove CKeditor libs from HTML, set this constant to true before loading
666
if (!defined('CHAMILO_LOAD_WYSIWYG')) {
667
    define('CHAMILO_LOAD_WYSIWYG', true);
668
}
669
670
/* Constants for course home */
671
define('TOOL_PUBLIC', 'Public');
672
define('TOOL_PUBLIC_BUT_HIDDEN', 'PublicButHide');
673
define('TOOL_COURSE_ADMIN', 'courseAdmin');
674
define('TOOL_PLATFORM_ADMIN', 'platformAdmin');
675
define('TOOL_AUTHORING', 'toolauthoring');
676
define('TOOL_INTERACTION', 'toolinteraction');
677
define('TOOL_COURSE_PLUGIN', 'toolcourseplugin'); //all plugins that can be enabled in courses
678
define('TOOL_ADMIN', 'tooladmin');
679
define('TOOL_ADMIN_PLATFORM', 'tooladminplatform');
680
define('TOOL_DRH', 'tool_drh');
681
define('TOOL_STUDENT_VIEW', 'toolstudentview');
682
define('TOOL_ADMIN_VISIBLE', 'tooladminvisible');
683
684
// Search settings (from main/inc/lib/search/IndexableChunk.class.php )
685
// some constants to avoid serialize string keys on serialized data array
686
define('SE_COURSE_ID', 0);
687
define('SE_TOOL_ID', 1);
688
define('SE_DATA', 2);
689
define('SE_USER', 3);
690
691
// in some cases we need top differenciate xapian documents of the same tool
692
define('SE_DOCTYPE_EXERCISE_EXERCISE', 0);
693
define('SE_DOCTYPE_EXERCISE_QUESTION', 1);
694
695
// xapian prefixes
696
define('XAPIAN_PREFIX_COURSEID', 'C');
697
define('XAPIAN_PREFIX_TOOLID', 'O');
698
699
/**
700
 * Returns a path to a certain resource within the Chamilo area, specifyed through a parameter.
701
 * Also, this function provides conversion between path types, in this case the input path points inside the Chamilo area too.
702
 *
703
 * See $_configuration['course_folder'] in the configuration.php to alter the WEB_COURSE_PATH and SYS_COURSE_PATH parameters.
704
705
 *
706
 * @param string $path (optional)   A path which type is to be converted. Also, it may be a defined constant for a path.
707
 *                     This parameter has meaning when $type parameter has one of the following values: TO_WEB, TO_SYS, TO_REL. Otherwise it is ignored.
708
 *
709
 * @return string the requested path or the converted path
710
 *
711
 * Notes about the current behaviour model:
712
 * 1. Windows back-slashes are converted to slashes in the result.
713
 * 2. A semi-absolute web-path is detected by its leading slash. On Linux systems, absolute system paths start with
714
 * a slash too, so an additional check about presence of leading system server base is implemented. For example, the function is
715
 * able to distinguish type difference between /var/www/chamilo/courses/ (SYS) and /chamilo/courses/ (REL).
716
 * 3. The function api_get_path() returns only these three types of paths, which in some sense are absolute. The function has
717
 * no a mechanism for processing relative web/system paths, such as: lesson01.html, ./lesson01.html, ../css/my_styles.css.
718
 * It has not been identified as needed yet.
719
 * 4. Also, resolving the meta-symbols "." and ".." within paths has not been implemented, it is to be identified as needed.
720
 *
721
 * For examples go to: *
722
 * See main/admin/system_status.php?section=paths
723
 *
724
 * Vchamilo changes : allow using an alternate configuration
725
 * to get vchamilo  instance paths
726
 */
727
function api_get_path($path = '', $configuration = [])
728
{
729
    global $paths;
730
731
    // get proper configuration data if exists
732
    global $_configuration;
733
734
    $emptyConfigurationParam = false;
735
    if (empty($configuration)) {
736
        $configuration = (array) $_configuration;
737
        $emptyConfigurationParam = true;
738
    }
739
740
    $root_sys = Container::getProjectDir();
741
742
    $root_web = '';
743
    // If no $root_web has been set so far *and* no custom config has been passed to the function
744
    // then re-use the previously-calculated (run-specific) $root_web and skip this complex calculation
745
    /*
746
    if (empty($root_web) || $emptyConfigurationParam === false || empty($configuration)) {
747
        // Resolve master hostname.
748
        if (!empty($configuration) && array_key_exists('root_web', $configuration)) {
749
            $root_web = $configuration['root_web'];
750
        } else {
751
            $root_web = '';
752
            // Try guess it from server.
753
            if (defined('SYSTEM_INSTALLATION') && SYSTEM_INSTALLATION) {
754
                if (($pos = strpos(($requested_page_rel = api_get_self()), 'main/install')) !== false) {
755
                    $root_rel = substr($requested_page_rel, 0, $pos);
756
                    // See http://www.mediawiki.org/wiki/Manual:$wgServer
757
                    $server_protocol = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https' : 'http';
758
                    $server_name =
759
                        isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME']
760
                            : (isset($_SERVER['HOSTNAME']) ? $_SERVER['HOSTNAME']
761
                            : (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST']
762
                                : (isset($_SERVER['SERVER_ADDR']) ? $_SERVER['SERVER_ADDR']
763
                                    : 'localhost')));
764
                    if (isset($_SERVER['SERVER_PORT']) && !strpos($server_name, ':')
765
                        && (($server_protocol == 'http'
766
                                && $_SERVER['SERVER_PORT'] != 80) || ($server_protocol == 'https' && $_SERVER['SERVER_PORT'] != 443))
767
                    ) {
768
                        $server_name .= ":".$_SERVER['SERVER_PORT'];
769
                    }
770
                    $root_web = $server_protocol.'://'.$server_name.$root_rel;
771
                    $root_sys = str_replace('\\', '/', realpath(__DIR__.'/../../../')).'/';
772
                }
773
                // Here we give up, so we don't touch anything.
774
            }
775
        }
776
    }*/
777
    if (isset(Container::$container)) {
778
        $root_web = Container::$container->get('router')->generate(
779
            'home',
780
            [],
781
            UrlGeneratorInterface::ABSOLUTE_URL
782
        );
783
    }
784
785
    if (isset($configuration['multiple_access_urls']) &&
786
        $configuration['multiple_access_urls']
787
    ) {
788
        // To avoid that the api_get_access_url() function fails since global.inc.php also calls the main_api.lib.php
789
        if (isset($configuration['access_url']) && !empty($configuration['access_url'])) {
790
            // We look into the DB the function api_get_access_url
791
            $urlInfo = api_get_access_url($configuration['access_url']);
792
            // Avoid default value
793
            $defaultValues = ['http://localhost/', 'https://localhost/'];
794
            if (!empty($urlInfo['url']) && !in_array($urlInfo['url'], $defaultValues)) {
795
                $root_web = 1 == $urlInfo['active'] ? $urlInfo['url'] : $configuration['root_web'];
796
            }
797
        }
798
    }
799
800
    $paths = [
801
        WEB_PATH => $root_web,
802
        SYMFONY_SYS_PATH => $root_sys,
803
        SYS_PATH => $root_sys.'public/',
804
        REL_PATH => '',
805
        CONFIGURATION_PATH => 'app/config/',
806
        LIBRARY_PATH => $root_sys.'public/main/inc/lib/',
807
808
        REL_COURSE_PATH => '',
809
        REL_CODE_PATH => '/main/',
810
811
        SYS_CODE_PATH => $root_sys.'public/main/',
812
        SYS_CSS_PATH => $root_sys.'public/build/css/',
813
        SYS_PLUGIN_PATH => $root_sys.'public/plugin/',
814
        SYS_ARCHIVE_PATH => $root_sys.'var/cache/',
815
       // SYS_UPLOAD_PATH => 'var/upload/',
816
        SYS_TEST_PATH => $root_sys.'tests/',
817
        SYS_TEMPLATE_PATH => $root_sys.'public/main/template/',
818
        SYS_PUBLIC_PATH => $root_sys.'public/',
819
        SYS_FONTS_PATH => $root_sys.'public/fonts/',
820
821
        WEB_CODE_PATH => $root_web.'main/',
822
        WEB_PLUGIN_ASSET_PATH => $root_web.'plugins/',
823
        WEB_COURSE_PATH => $root_web.'course/',
824
        WEB_IMG_PATH => $root_web.'img/',
825
        WEB_CSS_PATH => $root_web.'build/css/',
826
        WEB_AJAX_PATH => $root_web.'main/inc/ajax/',
827
        WEB_LIBRARY_PATH => $root_web.'main/inc/lib/',
828
        WEB_LIBRARY_JS_PATH => $root_web.'main/inc/lib/javascript/',
829
        WEB_PLUGIN_PATH => $root_web.'plugin/',
830
       // WEB_ARCHIVE_PATH => 'var/cache/',
831
        //WEB_UPLOAD_PATH => 'var/upload/',
832
        WEB_PUBLIC_PATH => $root_web,
833
    ];
834
835
    $root_rel = '';
836
837
    // Dealing with trailing slashes.
838
    $rootWebWithSlash = api_add_trailing_slash($root_web);
839
    $root_sys = api_add_trailing_slash($root_sys);
840
    $root_rel = api_add_trailing_slash($root_rel);
841
842
    // Initialization of a table that contains common-purpose paths.
843
    /*$paths[$root_web][REL_PATH] = $root_rel;
844
    $paths[$root_web][REL_CODE_PATH] = $root_rel.$code_folder;
845
    $paths[$root_web][WEB_PATH] = $rootWebWithSlash;
846
    $paths[$root_web][WEB_CODE_PATH] = $rootWebWithSlash.'main/';
847
    $paths[$root_web][WEB_COURSE_PATH] = $rootWebWithSlash.$course_folder;
848
    $paths[$root_web][WEB_PLUGIN_PATH] = $rootWebWithSlash.$paths[$root_web][WEB_PLUGIN_PATH];
849
    $paths[$root_web][WEB_PLUGIN_ASSET_PATH] = $rootWebWithSlash.$paths[$root_web][WEB_PLUGIN_ASSET_PATH];
850
    $paths[$root_web][WEB_ARCHIVE_PATH] = $rootWebWithSlash.$paths[$root_web][WEB_ARCHIVE_PATH];
851
    $paths[$root_web][WEB_CSS_PATH] = $rootWebWithSlash.$paths[$root_web][WEB_CSS_PATH];
852
    //$paths[$root_web][WEB_UPLOAD_PATH] = $rootWebWithSlash.$paths[$root_web][WEB_UPLOAD_PATH];
853
    $paths[$root_web][WEB_PUBLIC_PATH] = $rootWebWithSlash;
854
855
    $paths[$root_web][WEB_IMG_PATH] = $rootWebWithSlash.$paths[$root_web][WEB_IMG_PATH];
856
    $paths[$root_web][WEB_LIBRARY_PATH] = $paths[$root_web][WEB_CODE_PATH].$paths[$root_web][WEB_LIBRARY_PATH];
857
    $paths[$root_web][WEB_LIBRARY_JS_PATH] = $paths[$root_web][WEB_CODE_PATH].$paths[$root_web][WEB_LIBRARY_JS_PATH];
858
    $paths[$root_web][WEB_AJAX_PATH] = $paths[$root_web][WEB_CODE_PATH].$paths[$root_web][WEB_AJAX_PATH];
859
860
    $paths[$root_web][SYS_PATH] = $root_sys;
861
    $paths[$root_web][SYS_CODE_PATH] = $root_sys.$code_folder;
862
    $paths[$root_web][SYS_TEST_PATH] = $paths[$root_web][SYS_PATH].$paths[$root_web][SYS_TEST_PATH];
863
    $paths[$root_web][SYS_TEMPLATE_PATH] = $paths[$root_web][SYS_CODE_PATH].$paths[$root_web][SYS_TEMPLATE_PATH];
864
    $paths[$root_web][SYS_PUBLIC_PATH] = $paths[$root_web][SYS_PATH].$paths[$root_web][SYS_PUBLIC_PATH];
865
    $paths[$root_web][SYS_CSS_PATH] = $paths[$root_web][SYS_PATH].$paths[$root_web][SYS_CSS_PATH];
866
    $paths[$root_web][SYS_FONTS_PATH] = $paths[$root_web][SYS_CODE_PATH].$paths[$root_web][SYS_FONTS_PATH];
867
    $paths[$root_web][SYS_ARCHIVE_PATH] = $paths[$root_web][SYS_PATH].$paths[$root_web][SYS_ARCHIVE_PATH];
868
    $paths[$root_web][SYS_APP_PATH] = $paths[$root_web][SYS_PATH].$paths[$root_web][SYS_APP_PATH];
869
    $paths[$root_web][SYS_UPLOAD_PATH] = $paths[$root_web][SYS_PATH].$paths[$root_web][SYS_UPLOAD_PATH];
870
    $paths[$root_web][SYS_PLUGIN_PATH] = $paths[$root_web][SYS_PATH].$paths[$root_web][SYS_PLUGIN_PATH];
871
    $paths[$root_web][LIBRARY_PATH] = $paths[$root_web][SYS_CODE_PATH].$paths[$root_web][LIBRARY_PATH];
872
    $paths[$root_web][CONFIGURATION_PATH] = $paths[$root_web][SYS_PATH].$paths[$root_web][CONFIGURATION_PATH];*/
873
874
    global $virtualChamilo;
875
    if (!empty($virtualChamilo)) {
876
        $paths[SYS_ARCHIVE_PATH] = api_add_trailing_slash($virtualChamilo[SYS_ARCHIVE_PATH]);
877
        $paths[SYS_UPLOAD_PATH] = api_add_trailing_slash($virtualChamilo[SYS_UPLOAD_PATH]);
878
        //$paths[$root_web][WEB_UPLOAD_PATH] = api_add_trailing_slash($virtualChamilo[WEB_UPLOAD_PATH]);
879
        $paths[WEB_ARCHIVE_PATH] = api_add_trailing_slash($virtualChamilo[WEB_ARCHIVE_PATH]);
880
        //$paths[$root_web][WEB_COURSE_PATH] = api_add_trailing_slash($virtualChamilo[WEB_COURSE_PATH]);
881
882
        // WEB_UPLOAD_PATH should be handle by apache htaccess in the vhost
883
884
        // RewriteEngine On
885
        // RewriteRule /app/upload/(.*)$ http://localhost/other/upload/my-chamilo111-net/$1 [QSA,L]
886
887
        //$paths[$root_web][WEB_UPLOAD_PATH] = api_add_trailing_slash($virtualChamilo[WEB_UPLOAD_PATH]);
888
        //$paths[$root_web][REL_PATH] = $virtualChamilo[REL_PATH];
889
        //$paths[$root_web][REL_COURSE_PATH] = $virtualChamilo[REL_COURSE_PATH];
890
    }
891
892
    $path = trim($path);
893
894
    // Retrieving a common-purpose path.
895
    if (isset($paths[$path])) {
896
        return $paths[$path];
897
    }
898
899
    return false;
900
}
901
902
/**
903
 * Adds to a given path a trailing slash if it is necessary (adds "/" character at the end of the string).
904
 *
905
 * @param string $path the input path
906
 *
907
 * @return string returns the modified path
908
 */
909
function api_add_trailing_slash($path)
910
{
911
    return '/' == substr($path, -1) ? $path : $path.'/';
912
}
913
914
/**
915
 * Removes from a given path the trailing slash if it is necessary (removes "/" character from the end of the string).
916
 *
917
 * @param string $path the input path
918
 *
919
 * @return string returns the modified path
920
 */
921
function api_remove_trailing_slash($path)
922
{
923
    return '/' == substr($path, -1) ? substr($path, 0, -1) : $path;
924
}
925
926
/**
927
 * Checks the RFC 3986 syntax of a given URL.
928
 *
929
 * @param string $url      the URL to be checked
930
 * @param bool   $absolute whether the URL is absolute (beginning with a scheme such as "http:")
931
 *
932
 * @return string|false Returns the URL if it is valid, FALSE otherwise.
933
 *                      This function is an adaptation from the function valid_url(), Drupal CMS.
934
 *
935
 * @see http://drupal.org
936
 * Note: The built-in function filter_var($urs, FILTER_VALIDATE_URL) has a bug for some versions of PHP.
937
 * @see http://bugs.php.net/51192
938
 */
939
function api_valid_url($url, $absolute = false)
940
{
941
    if ($absolute) {
942
        if (preg_match("
943
            /^                                                      # Start at the beginning of the text
944
            (?:ftp|https?|feed):\/\/                                # Look for ftp, http, https or feed schemes
945
            (?:                                                     # Userinfo (optional) which is typically
946
                (?:(?:[\w\.\-\+!$&'\(\)*\+,;=]|%[0-9a-f]{2})+:)*    # a username or a username and password
947
                (?:[\w\.\-\+%!$&'\(\)*\+,;=]|%[0-9a-f]{2})+@        # combination
948
            )?
949
            (?:
950
                (?:[a-z0-9\-\.]|%[0-9a-f]{2})+                      # A domain name or a IPv4 address
951
                |(?:\[(?:[0-9a-f]{0,4}:)*(?:[0-9a-f]{0,4})\])       # or a well formed IPv6 address
952
            )
953
            (?::[0-9]+)?                                            # Server port number (optional)
954
            (?:[\/|\?]
955
                (?:[\w#!:\.\?\+=&@$'~*,;\/\(\)\[\]\-]|%[0-9a-f]{2}) # The path and query (optional)
956
            *)?
957
            $/xi", $url)) {
958
            return $url;
959
        }
960
961
        return false;
962
    } else {
963
        return preg_match("/^(?:[\w#!:\.\?\+=&@$'~*,;\/\(\)\[\]\-]|%[0-9a-f]{2})+$/i", $url) ? $url : false;
964
    }
965
}
966
967
/**
968
 * Checks whether a given string looks roughly like an email address.
969
 *
970
 * @param string $address the e-mail address to be checked
971
 *
972
 * @return mixed returns the e-mail if it is valid, FALSE otherwise
973
 */
974
function api_valid_email($address)
975
{
976
    return filter_var($address, FILTER_VALIDATE_EMAIL);
977
}
978
979
/* PROTECTION FUNCTIONS
980
   Use these functions to protect your scripts. */
981
982
/**
983
 * Function used to protect a course script.
984
 * The function blocks access when
985
 * - there is no $_SESSION["_course"] defined; or
986
 * - $is_allowed_in_course is set to false (this depends on the course
987
 * visibility and user status).
988
 *
989
 * This is only the first proposal, test and improve!
990
 *
991
 * @param bool Option to print headers when displaying error message. Default: false
992
 * @param bool whether session admins should be allowed or not
993
 * @param string $checkTool check if tool is available for users (user, group)
994
 *
995
 * @return bool True if the user has access to the current course or is out of a course context, false otherwise
996
 *
997
 * @todo replace global variable
998
 *
999
 * @author Roan Embrechts
1000
 */
1001
function api_protect_course_script($print_headers = false, $allow_session_admins = false, $checkTool = '')
1002
{
1003
    $course_info = api_get_course_info();
1004
    if (empty($course_info)) {
1005
        api_not_allowed($print_headers);
1006
1007
        return false;
1008
    }
1009
1010
    if (api_is_drh()) {
1011
        return true;
1012
    }
1013
1014
    // Session admin has access to course
1015
    $sessionAccess = api_get_configuration_value('session_admins_access_all_content');
1016
    if ($sessionAccess) {
1017
        $allow_session_admins = true;
1018
    }
1019
1020
    if (api_is_platform_admin($allow_session_admins)) {
1021
        return true;
1022
    }
1023
1024
    $isAllowedInCourse = api_is_allowed_in_course();
1025
    $is_visible = false;
1026
    if (isset($course_info) && isset($course_info['visibility'])) {
1027
        switch ($course_info['visibility']) {
1028
            default:
1029
            case COURSE_VISIBILITY_CLOSED:
1030
                // Completely closed: the course is only accessible to the teachers. - 0
1031
                if ($isAllowedInCourse && api_get_user_id() && !api_is_anonymous()) {
1032
                    $is_visible = true;
1033
                }
1034
                break;
1035
            case COURSE_VISIBILITY_REGISTERED:
1036
                // Private - access authorized to course members only - 1
1037
                if ($isAllowedInCourse && api_get_user_id() && !api_is_anonymous()) {
1038
                    $is_visible = true;
1039
                }
1040
                break;
1041
            case COURSE_VISIBILITY_OPEN_PLATFORM:
1042
                // Open - access allowed for users registered on the platform - 2
1043
                if ($isAllowedInCourse && api_get_user_id() && !api_is_anonymous()) {
1044
                    $is_visible = true;
1045
                }
1046
                break;
1047
            case COURSE_VISIBILITY_OPEN_WORLD:
1048
                //Open - access allowed for the whole world - 3
1049
                $is_visible = true;
1050
                break;
1051
            case COURSE_VISIBILITY_HIDDEN:
1052
                //Completely closed: the course is only accessible to the teachers. - 0
1053
                if (api_is_platform_admin()) {
1054
                    $is_visible = true;
1055
                }
1056
                break;
1057
        }
1058
1059
        //If password is set and user is not registered to the course then the course is not visible
1060
        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...
1061
            isset($course_info['registration_code']) &&
1062
            !empty($course_info['registration_code'])
1063
        ) {
1064
            $is_visible = false;
1065
        }
1066
    }
1067
1068
    if (!empty($checkTool)) {
1069
        if (!api_is_allowed_to_edit(true, true, true)) {
1070
            $toolInfo = api_get_tool_information_by_name($checkTool);
1071
            if (!empty($toolInfo) && isset($toolInfo['visibility']) && 0 == $toolInfo['visibility']) {
1072
                api_not_allowed(true);
1073
1074
                return false;
1075
            }
1076
        }
1077
    }
1078
1079
    // Check session visibility
1080
    $session_id = api_get_session_id();
1081
1082
    if (!empty($session_id)) {
1083
        // $isAllowedInCourse was set in local.inc.php
1084
        if (!$isAllowedInCourse) {
1085
            $is_visible = false;
1086
        }
1087
    }
1088
1089
    if (!$is_visible) {
1090
        api_not_allowed($print_headers);
1091
1092
        return false;
1093
    }
1094
1095
    return true;
1096
}
1097
1098
/**
1099
 * Function used to protect an admin script.
1100
 *
1101
 * The function blocks access when the user has no platform admin rights
1102
 * with an error message printed on default output
1103
 *
1104
 * @param bool Whether to allow session admins as well
1105
 * @param bool Whether to allow HR directors as well
1106
 * @param string An optional message (already passed through get_lang)
1107
 *
1108
 * @return bool True if user is allowed, false otherwise.
1109
 *              The function also outputs an error message in case not allowed
1110
 *
1111
 * @author Roan Embrechts (original author)
1112
 */
1113
function api_protect_admin_script($allow_sessions_admins = false, $allow_drh = false, $message = null)
1114
{
1115
    if (!api_is_platform_admin($allow_sessions_admins, $allow_drh)) {
1116
        api_not_allowed(true, $message);
1117
1118
        return false;
1119
    }
1120
1121
    return true;
1122
}
1123
1124
/**
1125
 * Function used to protect a teacher script.
1126
 * The function blocks access when the user has no teacher rights.
1127
 *
1128
 * @return bool True if the current user can access the script, false otherwise
1129
 *
1130
 * @author Yoselyn Castillo
1131
 */
1132
function api_protect_teacher_script()
1133
{
1134
    if (!api_is_allowed_to_edit()) {
1135
        api_not_allowed(true);
1136
1137
        return false;
1138
    }
1139
1140
    return true;
1141
}
1142
1143
/**
1144
 * Function used to prevent anonymous users from accessing a script.
1145
 *
1146
 * @param bool|true $printHeaders
1147
 *
1148
 * @author Roan Embrechts
1149
 *
1150
 * @return bool
1151
 */
1152
function api_block_anonymous_users($printHeaders = true)
1153
{
1154
    $user = api_get_user_info();
1155
    if (!(isset($user['user_id']) && $user['user_id']) || api_is_anonymous($user['user_id'], true)) {
1156
        api_not_allowed($printHeaders);
1157
1158
        return false;
1159
    }
1160
1161
    return true;
1162
}
1163
1164
/**
1165
 * Returns a rough evaluation of the browser's name and version based on very
1166
 * simple regexp.
1167
 *
1168
 * @return array with the navigator name and version ['name' => '...', 'version' => '...']
1169
 */
1170
function api_get_navigator()
1171
{
1172
    $navigator = 'Unknown';
1173
    $version = 0;
1174
1175
    if (!isset($_SERVER['HTTP_USER_AGENT'])) {
1176
        return ['name' => 'Unknown', 'version' => '0.0.0'];
1177
    }
1178
1179
    if (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Opera')) {
1180
        $navigator = 'Opera';
1181
        [, $version] = explode('Opera', $_SERVER['HTTP_USER_AGENT']);
1182
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Edge')) {
1183
        $navigator = 'Edge';
1184
        [, $version] = explode('Edge', $_SERVER['HTTP_USER_AGENT']);
1185
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE')) {
1186
        $navigator = 'Internet Explorer';
1187
        [, $version] = explode('MSIE ', $_SERVER['HTTP_USER_AGENT']);
1188
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Chrome')) {
1189
        $navigator = 'Chrome';
1190
        [, $version] = explode('Chrome', $_SERVER['HTTP_USER_AGENT']);
1191
    } elseif (false !== stripos($_SERVER['HTTP_USER_AGENT'], 'Safari')) {
1192
        $navigator = 'Safari';
1193
        if (false !== stripos($_SERVER['HTTP_USER_AGENT'], 'Version/')) {
1194
            // If this Safari does have the "Version/" string in its user agent
1195
            // then use that as a version indicator rather than what's after
1196
            // "Safari/" which is rather a "build number" or something
1197
            [, $version] = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1198
        } else {
1199
            [, $version] = explode('Safari/', $_SERVER['HTTP_USER_AGENT']);
1200
        }
1201
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Firefox')) {
1202
        $navigator = 'Firefox';
1203
        [, $version] = explode('Firefox', $_SERVER['HTTP_USER_AGENT']);
1204
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Netscape')) {
1205
        $navigator = 'Netscape';
1206
        if (false !== stripos($_SERVER['HTTP_USER_AGENT'], 'Netscape/')) {
1207
            [, $version] = explode('Netscape', $_SERVER['HTTP_USER_AGENT']);
1208
        } else {
1209
            [, $version] = explode('Navigator', $_SERVER['HTTP_USER_AGENT']);
1210
        }
1211
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Konqueror')) {
1212
        $navigator = 'Konqueror';
1213
        [, $version] = explode('Konqueror', $_SERVER['HTTP_USER_AGENT']);
1214
    } elseif (false !== stripos($_SERVER['HTTP_USER_AGENT'], 'applewebkit')) {
1215
        $navigator = 'AppleWebKit';
1216
        [, $version] = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1217
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Gecko')) {
1218
        $navigator = 'Mozilla';
1219
        [, $version] = explode('; rv:', $_SERVER['HTTP_USER_AGENT']);
1220
    }
1221
1222
    // Now cut extra stuff around (mostly *after*) the version number
1223
    $version = preg_replace('/^([\/\s])?([\d\.]+)?.*/', '\2', $version);
1224
1225
    if (false === strpos($version, '.')) {
1226
        $version = number_format(doubleval($version), 1);
1227
    }
1228
1229
    return ['name' => $navigator, 'version' => $version];
1230
}
1231
1232
/**
1233
 * @return true if user self registration is allowed, false otherwise
1234
 */
1235
function api_is_self_registration_allowed()
1236
{
1237
    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...
1238
}
1239
1240
/**
1241
 * This function returns the id of the user which is stored in the $_user array.
1242
 *
1243
 * example: The function can be used to check if a user is logged in
1244
 *          if (api_get_user_id())
1245
 *
1246
 * @return int the id of the current user, 0 if is empty
1247
 */
1248
function api_get_user_id()
1249
{
1250
    $userInfo = Session::read('_user');
1251
    if ($userInfo && isset($userInfo['user_id'])) {
1252
        return (int) $userInfo['user_id'];
1253
    }
1254
1255
    return 0;
1256
}
1257
1258
/**
1259
 * Gets the list of courses a specific user is subscribed to.
1260
 *
1261
 * @param int       User ID
1262
 * @param bool $fetch_session Whether to get session courses or not - NOT YET IMPLEMENTED
1263
 *
1264
 * @return array Array of courses in the form [0]=>('code'=>xxx,'db'=>xxx,'dir'=>xxx,'status'=>d)
1265
 *
1266
 * @deprecated use CourseManager::get_courses_list_by_user_id()
1267
 */
1268
function api_get_user_courses($userId, $fetch_session = true)
1269
{
1270
    // Get out if not integer
1271
    if ($userId != strval(intval($userId))) {
1272
        return [];
1273
    }
1274
1275
    $t_course = Database::get_main_table(TABLE_MAIN_COURSE);
1276
    $t_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
1277
1278
    $sql = "SELECT cc.id as real_id, cc.code code, cc.directory dir, cu.status status
1279
            FROM $t_course cc, $t_course_user cu
1280
            WHERE
1281
                cc.id = cu.c_id AND
1282
                cu.user_id = $userId AND
1283
                cu.relation_type <> ".COURSE_RELATION_TYPE_RRHH;
1284
    $result = Database::query($sql);
1285
    if (false === $result) {
1286
        return [];
1287
    }
1288
1289
    $courses = [];
1290
    while ($row = Database::fetch_array($result)) {
1291
        // we only need the database name of the course
1292
        $courses[] = $row;
1293
    }
1294
1295
    return $courses;
1296
}
1297
1298
/**
1299
 * Formats user information into a standard array
1300
 * This function should be only used inside api_get_user_info().
1301
 *
1302
 * @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...
1303
 * @param bool $add_password
1304
 * @param bool $loadAvatars  turn off to improve performance
1305
 *
1306
 * @return array Standard user array
1307
 */
1308
function _api_format_user($user, $add_password = false, $loadAvatars = true)
1309
{
1310
    $result = [];
1311
1312
    if (!isset($user['id'])) {
1313
        return [];
1314
    }
1315
1316
    $result['firstname'] = null;
1317
    $result['lastname'] = null;
1318
1319
    if (isset($user['firstname']) && isset($user['lastname'])) {
1320
        // with only lowercase
1321
        $result['firstname'] = $user['firstname'];
1322
        $result['lastname'] = $user['lastname'];
1323
    } elseif (isset($user['firstName']) && isset($user['lastName'])) {
1324
        // with uppercase letters
1325
        $result['firstname'] = isset($user['firstName']) ? $user['firstName'] : null;
1326
        $result['lastname'] = isset($user['lastName']) ? $user['lastName'] : null;
1327
    }
1328
1329
    if (isset($user['email'])) {
1330
        $result['mail'] = isset($user['email']) ? $user['email'] : null;
1331
        $result['email'] = isset($user['email']) ? $user['email'] : null;
1332
    } else {
1333
        $result['mail'] = isset($user['mail']) ? $user['mail'] : null;
1334
        $result['email'] = isset($user['mail']) ? $user['mail'] : null;
1335
    }
1336
1337
    $result['complete_name'] = api_get_person_name($result['firstname'], $result['lastname']);
1338
    $result['complete_name_with_username'] = $result['complete_name'];
1339
1340
    if (!empty($user['username']) && 'false' === api_get_setting('profile.hide_username_with_complete_name')) {
1341
        $result['complete_name_with_username'] = $result['complete_name'].' ('.$user['username'].')';
1342
    }
1343
1344
    $showEmail = 'true' === api_get_setting('show_email_addresses');
1345
    if (!empty($user['email'])) {
1346
        $result['complete_name_with_email_forced'] = $result['complete_name'].' ('.$user['email'].')';
1347
        if ($showEmail) {
1348
            $result['complete_name_with_email'] = $result['complete_name'].' ('.$user['email'].')';
1349
        }
1350
    } else {
1351
        $result['complete_name_with_email'] = $result['complete_name'];
1352
        $result['complete_name_with_email_forced'] = $result['complete_name'];
1353
    }
1354
1355
    // Kept for historical reasons
1356
    $result['firstName'] = $result['firstname'];
1357
    $result['lastName'] = $result['lastname'];
1358
1359
    $attributes = [
1360
        'phone',
1361
        'address',
1362
        'picture_uri',
1363
        'official_code',
1364
        'status',
1365
        'active',
1366
        'auth_source',
1367
        'username',
1368
        'theme',
1369
        'language',
1370
        'creator_id',
1371
        'registration_date',
1372
        'hr_dept_id',
1373
        'expiration_date',
1374
        'last_login',
1375
        'user_is_online',
1376
    ];
1377
1378
    if ('true' === api_get_setting('extended_profile')) {
1379
        $attributes[] = 'competences';
1380
        $attributes[] = 'diplomas';
1381
        $attributes[] = 'teach';
1382
        $attributes[] = 'openarea';
1383
    }
1384
1385
    foreach ($attributes as $attribute) {
1386
        $result[$attribute] = isset($user[$attribute]) ? $user[$attribute] : null;
1387
    }
1388
1389
    $user_id = (int) $user['id'];
1390
    // Maintain the user_id index for backwards compatibility
1391
    $result['user_id'] = $result['id'] = $user_id;
1392
1393
    $hasCertificates = Certificate::getCertificateByUser($user_id);
1394
    $result['has_certificates'] = 0;
1395
    if (!empty($hasCertificates)) {
1396
        $result['has_certificates'] = 1;
1397
    }
1398
1399
    $result['icon_status'] = '';
1400
    $result['icon_status_medium'] = '';
1401
    $result['is_admin'] = UserManager::is_admin($user_id);
1402
1403
    // Getting user avatar.
1404
    if ($loadAvatars) {
1405
        $result['avatar'] = '';
1406
        $result['avatar_no_query'] = '';
1407
        $result['avatar_small'] = '';
1408
        $result['avatar_medium'] = '';
1409
1410
        /*if (!isset($user['avatar'])) {
1411
            $originalFile = UserManager::getUserPicture(
1412
                $user_id,
1413
                USER_IMAGE_SIZE_ORIGINAL,
1414
                null,
1415
                $result
1416
            );
1417
            $result['avatar'] = $originalFile;
1418
            $avatarString = explode('?', $result['avatar']);
1419
            $result['avatar_no_query'] = reset($avatarString);
1420
        } else {
1421
            $result['avatar'] = $user['avatar'];
1422
            $avatarString = explode('?', $user['avatar']);
1423
            $result['avatar_no_query'] = reset($avatarString);
1424
        }
1425
1426
        if (!isset($user['avatar_small'])) {
1427
            $smallFile = UserManager::getUserPicture(
1428
                $user_id,
1429
                USER_IMAGE_SIZE_SMALL,
1430
                null,
1431
                $result
1432
            );
1433
            $result['avatar_small'] = $smallFile;
1434
        } else {
1435
            $result['avatar_small'] = $user['avatar_small'];
1436
        }
1437
1438
        if (!isset($user['avatar_medium'])) {
1439
            $mediumFile = UserManager::getUserPicture(
1440
                $user_id,
1441
                USER_IMAGE_SIZE_MEDIUM,
1442
                null,
1443
                $result
1444
            );
1445
            $result['avatar_medium'] = $mediumFile;
1446
        } else {
1447
            $result['avatar_medium'] = $user['avatar_medium'];
1448
        }*/
1449
1450
        $urlImg = api_get_path(WEB_IMG_PATH);
1451
        $iconStatus = '';
1452
        $iconStatusMedium = '';
1453
        $label = '';
1454
        switch ($result['status']) {
1455
            case STUDENT:
1456
                if ($result['has_certificates']) {
1457
                    $iconStatus = $urlImg.'icons/svg/identifier_graduated.svg';
1458
                    $label = get_lang('Graduated');
1459
                } else {
1460
                    $iconStatus = $urlImg.'icons/svg/identifier_student.svg';
1461
                    $label = get_lang('Student');
1462
                }
1463
                break;
1464
            case COURSEMANAGER:
1465
                if ($result['is_admin']) {
1466
                    $iconStatus = $urlImg.'icons/svg/identifier_admin.svg';
1467
                    $label = get_lang('Admin');
1468
                } else {
1469
                    $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1470
                    $label = get_lang('Teacher');
1471
                }
1472
                break;
1473
            case STUDENT_BOSS:
1474
                $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1475
                $label = get_lang('StudentBoss');
1476
                break;
1477
        }
1478
1479
        if (!empty($iconStatus)) {
1480
            $iconStatusMedium = '<img src="'.$iconStatus.'" width="32px" height="32px">';
1481
            $iconStatus = '<img src="'.$iconStatus.'" width="22px" height="22px">';
1482
        }
1483
1484
        $result['icon_status'] = $iconStatus;
1485
        $result['icon_status_label'] = $label;
1486
        $result['icon_status_medium'] = $iconStatusMedium;
1487
    }
1488
1489
    if (isset($user['user_is_online'])) {
1490
        $result['user_is_online'] = true == $user['user_is_online'] ? 1 : 0;
1491
    }
1492
    if (isset($user['user_is_online_in_chat'])) {
1493
        $result['user_is_online_in_chat'] = (int) $user['user_is_online_in_chat'];
1494
    }
1495
1496
    if ($add_password) {
1497
        $result['password'] = $user['password'];
1498
    }
1499
1500
    if (isset($result['profile_completed'])) {
1501
        $result['profile_completed'] = $user['profile_completed'];
1502
    }
1503
1504
    $result['profile_url'] = api_get_path(WEB_CODE_PATH).'social/profile.php?u='.$user_id;
1505
1506
    // Send message link
1507
    $sendMessage = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&user_id='.$user_id;
1508
    $result['complete_name_with_message_link'] = Display::url(
1509
        $result['complete_name_with_username'],
1510
        $sendMessage,
1511
        ['class' => 'ajax']
1512
    );
1513
1514
    if (isset($user['extra'])) {
1515
        $result['extra'] = $user['extra'];
1516
    }
1517
1518
    return $result;
1519
}
1520
1521
/**
1522
 * Finds all the information about a user.
1523
 * If no parameter is passed you find all the information about the current user.
1524
 *
1525
 * @param int  $user_id
1526
 * @param bool $checkIfUserOnline
1527
 * @param bool $showPassword
1528
 * @param bool $loadExtraData
1529
 * @param bool $loadOnlyVisibleExtraData Get the user extra fields that are visible
1530
 * @param bool $loadAvatars              turn off to improve performance and if avatars are not needed
1531
 * @param bool $updateCache              update apc cache if exists
1532
 *
1533
 * @return mixed $user_info user_id, lastname, firstname, username, email, etc or false on error
1534
 *
1535
 * @author Patrick Cool <[email protected]>
1536
 * @author Julio Montoya
1537
 *
1538
 * @version 21 September 2004
1539
 */
1540
function api_get_user_info(
1541
    $user_id = 0,
1542
    $checkIfUserOnline = false,
1543
    $showPassword = false,
1544
    $loadExtraData = false,
1545
    $loadOnlyVisibleExtraData = false,
1546
    $loadAvatars = true,
1547
    $updateCache = false
1548
) {
1549
    // Make sure user_id is safe
1550
    $user_id = (int) $user_id;
1551
    $user = false;
1552
    if (empty($user_id)) {
1553
        $userFromSession = Session::read('_user');
1554
        if (isset($userFromSession) && !empty($userFromSession)) {
1555
            return $userFromSession;
1556
            /*
1557
            return _api_format_user(
1558
                $userFromSession,
1559
                $showPassword,
1560
                $loadAvatars
1561
            );*/
1562
        }
1563
1564
        return false;
1565
    }
1566
1567
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1568
            WHERE id = $user_id";
1569
    $result = Database::query($sql);
1570
    if (Database::num_rows($result) > 0) {
1571
        $result_array = Database::fetch_array($result);
1572
        $result_array['user_is_online_in_chat'] = 0;
1573
        if ($checkIfUserOnline) {
1574
            $use_status_in_platform = user_is_online($user_id);
1575
            $result_array['user_is_online'] = $use_status_in_platform;
1576
            $user_online_in_chat = 0;
1577
            if ($use_status_in_platform) {
1578
                $user_status = UserManager::get_extra_user_data_by_field(
1579
                    $user_id,
1580
                    'user_chat_status',
1581
                    false,
1582
                    true
1583
                );
1584
                if (1 == (int) $user_status['user_chat_status']) {
1585
                    $user_online_in_chat = 1;
1586
                }
1587
            }
1588
            $result_array['user_is_online_in_chat'] = $user_online_in_chat;
1589
        }
1590
1591
        if ($loadExtraData) {
1592
            $fieldValue = new ExtraFieldValue('user');
1593
            $result_array['extra'] = $fieldValue->getAllValuesForAnItem(
1594
                $user_id,
1595
                $loadOnlyVisibleExtraData
1596
            );
1597
        }
1598
        $user = _api_format_user($result_array, $showPassword, $loadAvatars);
1599
    }
1600
1601
    return $user;
1602
}
1603
1604
function api_get_user_info_from_entity(
1605
    User $user,
1606
    $checkIfUserOnline = false,
1607
    $showPassword = false,
1608
    $loadExtraData = false,
1609
    $loadOnlyVisibleExtraData = false,
1610
    $loadAvatars = true,
1611
    $loadCertificate = false
1612
) {
1613
    if (!$user instanceof UserInterface) {
1614
        return false;
1615
    }
1616
1617
    // Make sure user_id is safe
1618
    $user_id = (int) $user->getId();
1619
1620
    if (empty($user_id)) {
1621
        $userFromSession = Session::read('_user');
1622
1623
        if (isset($userFromSession) && !empty($userFromSession)) {
1624
            return $userFromSession;
1625
        }
1626
1627
        return false;
1628
    }
1629
1630
    $result = [];
1631
    $result['user_is_online_in_chat'] = 0;
1632
    if ($checkIfUserOnline) {
1633
        $use_status_in_platform = user_is_online($user_id);
1634
        $result['user_is_online'] = $use_status_in_platform;
1635
        $user_online_in_chat = 0;
1636
        if ($use_status_in_platform) {
1637
            $user_status = UserManager::get_extra_user_data_by_field(
1638
                $user_id,
1639
                'user_chat_status',
1640
                false,
1641
                true
1642
            );
1643
            if (1 == (int) $user_status['user_chat_status']) {
1644
                $user_online_in_chat = 1;
1645
            }
1646
        }
1647
        $result['user_is_online_in_chat'] = $user_online_in_chat;
1648
    }
1649
1650
    if ($loadExtraData) {
1651
        $fieldValue = new ExtraFieldValue('user');
1652
        $result['extra'] = $fieldValue->getAllValuesForAnItem(
1653
            $user_id,
1654
            $loadOnlyVisibleExtraData
1655
        );
1656
    }
1657
1658
    $result['username'] = $user->getUsername();
1659
    $result['status'] = $user->getStatus();
1660
    $result['firstname'] = $user->getFirstname();
1661
    $result['lastname'] = $user->getLastname();
1662
    $result['email'] = $result['mail'] = $user->getEmail();
1663
    $result['complete_name'] = api_get_person_name($result['firstname'], $result['lastname']);
1664
    $result['complete_name_with_username'] = $result['complete_name'];
1665
1666
    if (!empty($result['username']) && 'false' === api_get_setting('profile.hide_username_with_complete_name')) {
1667
        $result['complete_name_with_username'] = $result['complete_name'].' ('.$result['username'].')';
1668
    }
1669
1670
    $showEmail = 'true' === api_get_setting('show_email_addresses');
1671
    if (!empty($result['email'])) {
1672
        $result['complete_name_with_email_forced'] = $result['complete_name'].' ('.$result['email'].')';
1673
        if ($showEmail) {
1674
            $result['complete_name_with_email'] = $result['complete_name'].' ('.$result['email'].')';
1675
        }
1676
    } else {
1677
        $result['complete_name_with_email'] = $result['complete_name'];
1678
        $result['complete_name_with_email_forced'] = $result['complete_name'];
1679
    }
1680
1681
    // Kept for historical reasons
1682
    $result['firstName'] = $result['firstname'];
1683
    $result['lastName'] = $result['lastname'];
1684
1685
    $attributes = [
1686
        'picture_uri',
1687
        'last_login',
1688
        'user_is_online',
1689
    ];
1690
1691
    $result['phone'] = $user->getPhone();
1692
    $result['address'] = $user->getAddress();
1693
    $result['official_code'] = $user->getOfficialCode();
1694
    $result['active'] = $user->getActive();
1695
    $result['auth_source'] = $user->getAuthSource();
1696
    $result['language'] = $user->getLanguage();
1697
    $result['creator_id'] = $user->getCreatorId();
1698
    $result['registration_date'] = $user->getRegistrationDate()->format('Y-m-d H:i:s');
1699
    $result['hr_dept_id'] = $user->getHrDeptId();
1700
    $result['expiration_date'] = '';
1701
    if ($user->getExpirationDate()) {
1702
        $result['expiration_date'] = $user->getExpirationDate()->format('Y-m-d H:i:s');
1703
    }
1704
1705
    $result['last_login'] = null;
1706
    if ($user->getLastLogin()) {
1707
        $result['last_login'] = $user->getLastLogin()->format('Y-m-d H:i:s');
1708
    }
1709
1710
    $result['competences'] = $user->getCompetences();
1711
    $result['diplomas'] = $user->getDiplomas();
1712
    $result['teach'] = $user->getTeach();
1713
    $result['openarea'] = $user->getOpenarea();
1714
    $user_id = (int) $user->getId();
1715
1716
    // Maintain the user_id index for backwards compatibility
1717
    $result['user_id'] = $result['id'] = $user_id;
1718
1719
    if ($loadCertificate) {
1720
        $hasCertificates = Certificate::getCertificateByUser($user_id);
1721
        $result['has_certificates'] = 0;
1722
        if (!empty($hasCertificates)) {
1723
            $result['has_certificates'] = 1;
1724
        }
1725
    }
1726
1727
    $result['icon_status'] = '';
1728
    $result['icon_status_medium'] = '';
1729
    $result['is_admin'] = UserManager::is_admin($user_id);
1730
1731
    // Getting user avatar.
1732
    if ($loadAvatars) {
1733
        $result['avatar'] = '';
1734
        $result['avatar_no_query'] = '';
1735
        $result['avatar_small'] = '';
1736
        $result['avatar_medium'] = '';
1737
1738
        /*if (!isset($user['avatar'])) {
1739
            $originalFile = UserManager::getUserPicture(
1740
                $user_id,
1741
                USER_IMAGE_SIZE_ORIGINAL,
1742
                null,
1743
                $result
1744
            );
1745
            $result['avatar'] = $originalFile;
1746
            $avatarString = explode('?', $result['avatar']);
1747
            $result['avatar_no_query'] = reset($avatarString);
1748
        } else {
1749
            $result['avatar'] = $user['avatar'];
1750
            $avatarString = explode('?', $user['avatar']);
1751
            $result['avatar_no_query'] = reset($avatarString);
1752
        }
1753
1754
        if (!isset($user['avatar_small'])) {
1755
            $smallFile = UserManager::getUserPicture(
1756
                $user_id,
1757
                USER_IMAGE_SIZE_SMALL,
1758
                null,
1759
                $result
1760
            );
1761
            $result['avatar_small'] = $smallFile;
1762
        } else {
1763
            $result['avatar_small'] = $user['avatar_small'];
1764
        }
1765
1766
        if (!isset($user['avatar_medium'])) {
1767
            $mediumFile = UserManager::getUserPicture(
1768
                $user_id,
1769
                USER_IMAGE_SIZE_MEDIUM,
1770
                null,
1771
                $result
1772
            );
1773
            $result['avatar_medium'] = $mediumFile;
1774
        } else {
1775
            $result['avatar_medium'] = $user['avatar_medium'];
1776
        }*/
1777
1778
        //$urlImg = api_get_path(WEB_IMG_PATH);
1779
        $urlImg = '/';
1780
        $iconStatus = '';
1781
        $iconStatusMedium = '';
1782
1783
        switch ($user->getStatus()) {
1784
            case STUDENT:
1785
                if (isset($result['has_certificates']) && $result['has_certificates']) {
1786
                    $iconStatus = $urlImg.'icons/svg/identifier_graduated.svg';
1787
                } else {
1788
                    $iconStatus = $urlImg.'icons/svg/identifier_student.svg';
1789
                }
1790
                break;
1791
            case COURSEMANAGER:
1792
                if ($result['is_admin']) {
1793
                    $iconStatus = $urlImg.'icons/svg/identifier_admin.svg';
1794
                } else {
1795
                    $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1796
                }
1797
                break;
1798
            case STUDENT_BOSS:
1799
                $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1800
                break;
1801
        }
1802
1803
        if (!empty($iconStatus)) {
1804
            $iconStatusMedium = '<img src="'.$iconStatus.'" width="32px" height="32px">';
1805
            $iconStatus = '<img src="'.$iconStatus.'" width="22px" height="22px">';
1806
        }
1807
1808
        $result['icon_status'] = $iconStatus;
1809
        $result['icon_status_medium'] = $iconStatusMedium;
1810
    }
1811
1812
    if (isset($result['user_is_online'])) {
1813
        $result['user_is_online'] = true == $result['user_is_online'] ? 1 : 0;
1814
    }
1815
    if (isset($result['user_is_online_in_chat'])) {
1816
        $result['user_is_online_in_chat'] = (int) $result['user_is_online_in_chat'];
1817
    }
1818
1819
    $result['password'] = '';
1820
    if ($showPassword) {
1821
        $result['password'] = $user->getPassword();
1822
    }
1823
1824
    if (isset($result['profile_completed'])) {
1825
        $result['profile_completed'] = $result['profile_completed'];
1826
    }
1827
1828
    $result['profile_url'] = api_get_path(WEB_CODE_PATH).'social/profile.php?u='.$user_id;
1829
1830
    // Send message link
1831
    $sendMessage = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&user_id='.$user_id;
1832
    $result['complete_name_with_message_link'] = Display::url(
1833
        $result['complete_name_with_username'],
1834
        $sendMessage,
1835
        ['class' => 'ajax']
1836
    );
1837
1838
    if (isset($result['extra'])) {
1839
        $result['extra'] = $result['extra'];
1840
    }
1841
1842
    return $result;
1843
}
1844
1845
function api_get_lp_entity(int $id): ? CLp
1846
{
1847
    return Database::getManager()->getRepository(CLp::class)->find($id);
1848
}
1849
1850
function api_get_user_entity(int $userId = 0): ?User
1851
{
1852
    $userId = $userId ?: api_get_user_id();
1853
    $repo = UserManager::getRepository();
1854
1855
    /** @var User $user */
1856
    $user = $repo->find($userId);
1857
1858
    return $user;
1859
}
1860
1861
/**
1862
 * @return User|null
1863
 */
1864
function api_get_current_user()
1865
{
1866
    $isLoggedIn = Container::$container->get('security.authorization_checker')->isGranted('IS_AUTHENTICATED_REMEMBERED');
1867
    if (false === $isLoggedIn) {
1868
        return null;
1869
    }
1870
1871
    $token = Container::$container->get('security.token_storage')->getToken();
1872
1873
    if (null !== $token) {
1874
        return $token->getUser();
1875
    }
1876
1877
    return null;
1878
}
1879
1880
/**
1881
 * Finds all the information about a user from username instead of user id.
1882
 *
1883
 * @param string $username
1884
 *
1885
 * @return mixed $user_info array user_id, lastname, firstname, username, email or false on error
1886
 *
1887
 * @author Yannick Warnier <[email protected]>
1888
 */
1889
function api_get_user_info_from_username($username)
1890
{
1891
    if (empty($username)) {
1892
        return false;
1893
    }
1894
    $username = trim($username);
1895
1896
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1897
            WHERE username='".Database::escape_string($username)."'";
1898
    $result = Database::query($sql);
1899
    if (Database::num_rows($result) > 0) {
1900
        $resultArray = Database::fetch_array($result);
1901
1902
        return _api_format_user($resultArray);
1903
    }
1904
1905
    return false;
1906
}
1907
1908
/**
1909
 * Get first user with an email.
1910
 *
1911
 * @param string $email
1912
 *
1913
 * @return array|bool
1914
 */
1915
function api_get_user_info_from_email($email = '')
1916
{
1917
    if (empty($email)) {
1918
        return false;
1919
    }
1920
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1921
            WHERE email ='".Database::escape_string($email)."' LIMIT 1";
1922
    $result = Database::query($sql);
1923
    if (Database::num_rows($result) > 0) {
1924
        $resultArray = Database::fetch_array($result);
1925
1926
        return _api_format_user($resultArray);
1927
    }
1928
1929
    return false;
1930
}
1931
1932
/**
1933
 * @return string
1934
 */
1935
function api_get_course_id()
1936
{
1937
    return Session::read('_cid', null);
1938
}
1939
1940
/**
1941
 * Returns the current course id (integer).
1942
 *
1943
 * @param string $code Optional course code
1944
 *
1945
 * @return int
1946
 */
1947
function api_get_course_int_id($code = null)
1948
{
1949
    if (!empty($code)) {
1950
        $code = Database::escape_string($code);
1951
        $row = Database::select(
1952
            'id',
1953
            Database::get_main_table(TABLE_MAIN_COURSE),
1954
            ['where' => ['code = ?' => [$code]]],
1955
            'first'
1956
        );
1957
1958
        if (is_array($row) && isset($row['id'])) {
1959
            return $row['id'];
1960
        } else {
1961
            return false;
1962
        }
1963
    }
1964
1965
    return Session::read('_real_cid', 0);
1966
}
1967
1968
/**
1969
 * Returns the current course directory.
1970
 *
1971
 * This function relies on api_get_course_info()
1972
 *
1973
 * @param string    The course code - optional (takes it from session if not given)
1974
 *
1975
 * @return string The directory where the course is located inside the Chamilo "courses" directory
1976
 *
1977
 * @author Yannick Warnier <[email protected]>
1978
 */
1979
function api_get_course_path($course_code = null)
1980
{
1981
    $info = !empty($course_code) ? api_get_course_info($course_code) : api_get_course_info();
1982
1983
    return $info['path'];
1984
}
1985
1986
/**
1987
 * Gets a course setting from the current course_setting table. Try always using integer values.
1988
 *
1989
 * @param string $settingName The name of the setting we want from the table
1990
 * @param array  $courseInfo
1991
 * @param bool   $force       force checking the value in the database
1992
 *
1993
 * @return mixed The value of that setting in that table. Return -1 if not found.
1994
 */
1995
function api_get_course_setting($settingName, $courseInfo = [], $force = false)
1996
{
1997
    if (empty($courseInfo)) {
1998
        $courseInfo = api_get_course_info();
1999
    }
2000
2001
    if (empty($courseInfo) || empty($settingName)) {
2002
        return -1;
2003
    }
2004
2005
    $courseId = isset($courseInfo['real_id']) && !empty($courseInfo['real_id']) ? $courseInfo['real_id'] : 0;
2006
2007
    if (empty($courseId)) {
2008
        return -1;
2009
    }
2010
2011
    static $courseSettingInfo = [];
2012
2013
    if ($force) {
2014
        $courseSettingInfo = [];
2015
    }
2016
2017
    if (!isset($courseSettingInfo[$courseId])) {
2018
        $table = Database::get_course_table(TABLE_COURSE_SETTING);
2019
        $settingName = Database::escape_string($settingName);
2020
2021
        $sql = "SELECT variable, value FROM $table
2022
                WHERE c_id = $courseId ";
2023
        $res = Database::query($sql);
2024
        if (Database::num_rows($res) > 0) {
2025
            $result = Database::store_result($res, 'ASSOC');
2026
            $courseSettingInfo[$courseId] = array_column($result, 'value', 'variable');
2027
2028
            if (isset($courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'])) {
2029
                $value = $courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'];
2030
                if (!is_null($value)) {
2031
                    $result = explode(',', $value);
2032
                    $courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'] = $result;
2033
                }
2034
            }
2035
        }
2036
    }
2037
2038
    if (isset($courseSettingInfo[$courseId]) && isset($courseSettingInfo[$courseId][$settingName])) {
2039
        return $courseSettingInfo[$courseId][$settingName];
2040
    }
2041
2042
    return -1;
2043
}
2044
2045
function api_get_course_plugin_setting($plugin, $settingName, $courseInfo = [])
2046
{
2047
    $value = api_get_course_setting($settingName, $courseInfo, true);
2048
2049
    if (-1 === $value) {
2050
        // Check global settings
2051
        $value = api_get_plugin_setting($plugin, $settingName);
2052
        if ('true' === $value) {
2053
            return 1;
2054
        }
2055
        if ('false' === $value) {
2056
            return 0;
2057
        }
2058
        if (null === $value) {
2059
            return -1;
2060
        }
2061
    }
2062
2063
    return $value;
2064
}
2065
2066
/**
2067
 * Gets an anonymous user ID.
2068
 *
2069
 * For some tools that need tracking, like the learnpath tool, it is necessary
2070
 * to have a usable user-id to enable some kind of tracking, even if not
2071
 * perfect. An anonymous ID is taken from the users table by looking for a
2072
 * status of "6" (anonymous).
2073
 *
2074
 * @return int User ID of the anonymous user, or O if no anonymous user found
2075
 */
2076
function api_get_anonymous_id()
2077
{
2078
    // Find if another anon is connected now
2079
    $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
2080
    $tableU = Database::get_main_table(TABLE_MAIN_USER);
2081
    $ip = Database::escape_string(api_get_real_ip());
2082
    $max = (int) api_get_configuration_value('max_anonymous_users');
2083
    if ($max >= 2) {
2084
        $sql = "SELECT * FROM $table as TEL
2085
                JOIN $tableU as U
2086
                ON U.user_id = TEL.login_user_id
2087
                WHERE TEL.user_ip = '$ip'
2088
                    AND U.status = ".ANONYMOUS."
2089
                    AND U.user_id != 2 ";
2090
2091
        $result = Database::query($sql);
2092
        if (empty(Database::num_rows($result))) {
2093
            $login = uniqid('anon_');
2094
            $anonList = UserManager::get_user_list(['status' => ANONYMOUS], ['registration_date ASC']);
2095
            if (count($anonList) >= $max) {
2096
                foreach ($anonList as $userToDelete) {
2097
                    UserManager::delete_user($userToDelete['user_id']);
2098
                    break;
2099
                }
2100
            }
2101
2102
            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...
2103
                $login,
2104
                'anon',
2105
                ANONYMOUS,
2106
                ' anonymous@localhost',
2107
                $login,
2108
                $login
2109
            );
2110
        } else {
2111
            $row = Database::fetch_array($result, 'ASSOC');
2112
2113
            return $row['user_id'];
2114
        }
2115
    }
2116
2117
    $table = Database::get_main_table(TABLE_MAIN_USER);
2118
    $sql = "SELECT user_id
2119
            FROM $table
2120
            WHERE status = ".ANONYMOUS." ";
2121
    $res = Database::query($sql);
2122
    if (Database::num_rows($res) > 0) {
2123
        $row = Database::fetch_array($res, 'ASSOC');
2124
2125
        return $row['user_id'];
2126
    }
2127
2128
    // No anonymous user was found.
2129
    return 0;
2130
}
2131
2132
/**
2133
 * @param int $courseId
2134
 * @param int $sessionId
2135
 * @param int $groupId
2136
 *
2137
 * @return string
2138
 */
2139
function api_get_cidreq_params($courseId, $sessionId = 0, $groupId = 0)
2140
{
2141
    $courseId = !empty($courseId) ? (int) $courseId : 0;
2142
    $sessionId = !empty($sessionId) ? (int) $sessionId : 0;
2143
    $groupId = !empty($groupId) ? (int) $groupId : 0;
2144
2145
    $url = 'cid='.$courseId;
2146
    $url .= '&sid='.$sessionId;
2147
    $url .= '&gid='.$groupId;
2148
2149
    return $url;
2150
}
2151
2152
/**
2153
 * Returns the current course url part including session, group, and gradebook params.
2154
 *
2155
 * @param bool   $addSessionId
2156
 * @param bool   $addGroupId
2157
 * @param string $origin
2158
 *
2159
 * @return string Course & session references to add to a URL
2160
 */
2161
function api_get_cidreq($addSessionId = true, $addGroupId = true, $origin = '')
2162
{
2163
    $courseId = api_get_course_int_id();
2164
    $url = empty($courseId) ? '' : 'cid='.$courseId;
2165
    $origin = empty($origin) ? api_get_origin() : Security::remove_XSS($origin);
2166
2167
    if ($addSessionId) {
2168
        if (!empty($url)) {
2169
            $url .= 0 == api_get_session_id() ? '&sid=0' : '&sid='.api_get_session_id();
2170
        }
2171
    }
2172
2173
    if ($addGroupId) {
2174
        if (!empty($url)) {
2175
            $url .= 0 == api_get_group_id() ? '&gid=0' : '&gid='.api_get_group_id();
2176
        }
2177
    }
2178
2179
    if (!empty($url)) {
2180
        $url .= '&gradebook='.(int) api_is_in_gradebook();
2181
        $url .= '&origin='.$origin;
2182
    }
2183
2184
    return $url;
2185
}
2186
2187
/**
2188
 * Get if we visited a gradebook page.
2189
 *
2190
 * @return bool
2191
 */
2192
function api_is_in_gradebook()
2193
{
2194
    return Session::read('in_gradebook', false);
2195
}
2196
2197
/**
2198
 * Set that we are in a page inside a gradebook.
2199
 */
2200
function api_set_in_gradebook()
2201
{
2202
    Session::write('in_gradebook', true);
2203
}
2204
2205
/**
2206
 * Remove gradebook session.
2207
 */
2208
function api_remove_in_gradebook()
2209
{
2210
    Session::erase('in_gradebook');
2211
}
2212
2213
/**
2214
 * Returns the current course info array see api_format_course_array()
2215
 * If the course_code is given, the returned array gives info about that
2216
 * particular course, if none given it gets the course info from the session.
2217
 *
2218
 * @param string $courseCode
2219
 *
2220
 * @return array
2221
 */
2222
function api_get_course_info($courseCode = null)
2223
{
2224
    if (!empty($courseCode)) {
2225
        $course = Container::getCourseRepository()->findOneByCode($courseCode);
2226
2227
        return api_format_course_array($course);
2228
    }
2229
2230
    /*$course_code = Database::escape_string($course_code);
2231
    $courseId = api_get_course_int_id($course_code);
2232
    if (empty($courseId)) {
2233
        return [];
2234
    }
2235
2236
    $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
2237
    $course_cat_table = Database::get_main_table(TABLE_MAIN_CATEGORY);
2238
    $sql = "SELECT
2239
                course.*,
2240
                course_category.code faCode,
2241
                course_category.name faName
2242
            FROM $course_table
2243
            LEFT JOIN $course_cat_table
2244
            ON course.category_code = course_category.code
2245
            WHERE course.id = $courseId";
2246
    $result = Database::query($sql);
2247
    $courseInfo = [];
2248
    if (Database::num_rows($result) > 0) {
2249
        $data = Database::fetch_array($result);
2250
        $courseInfo = api_format_course_array($data);
2251
    }
2252
2253
    return $courseInfo;*/
2254
2255
    $course = Session::read('_course');
2256
    if ('-1' == $course) {
2257
        $course = [];
2258
    }
2259
2260
    return $course;
2261
}
2262
2263
/**
2264
 * @param int $courseId
2265
 */
2266
function api_get_course_entity($courseId = 0): ?Course
2267
{
2268
    if (empty($courseId)) {
2269
        $courseId = api_get_course_int_id();
2270
    }
2271
2272
    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...
2273
}
2274
2275
/**
2276
 * @param int $id
2277
 */
2278
function api_get_session_entity($id = 0): ?SessionEntity
2279
{
2280
    if (empty($id)) {
2281
        $id = api_get_session_id();
2282
    }
2283
2284
    if (empty($id)) {
2285
        return null;
2286
    }
2287
2288
    return Container::getSessionRepository()->find($id);
2289
}
2290
2291
/**
2292
 * @param int $id
2293
 */
2294
function api_get_group_entity($id = 0): ?CGroup
2295
{
2296
    if (empty($id)) {
2297
        $id = api_get_group_id();
2298
    }
2299
2300
    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...
2301
}
2302
2303
/**
2304
 * @param int $id
2305
 *
2306
 * @return AccessUrl
2307
 */
2308
function api_get_url_entity($id = 0)
2309
{
2310
    if (empty($id)) {
2311
        $id = api_get_current_access_url_id();
2312
    }
2313
2314
    return Container::getAccessUrlRepository()->find($id);
2315
}
2316
2317
/**
2318
 * Returns the current course info array.
2319
2320
 * Now if the course_code is given, the returned array gives info about that
2321
 * particular course, not specially the current one.
2322
 *
2323
 * @param int $id Numeric ID of the course
2324
 *
2325
 * @return array The course info as an array formatted by api_format_course_array, including category.name
2326
 */
2327
function api_get_course_info_by_id($id = 0)
2328
{
2329
    $id = (int) $id;
2330
    if (empty($id)) {
2331
        $course = Session::read('_course', []);
2332
2333
        return $course;
2334
    }
2335
2336
    $course = Container::getCourseRepository()->find($id);
2337
    if (empty($course)) {
2338
        return [];
2339
    }
2340
2341
    return api_format_course_array($course);
2342
}
2343
2344
/**
2345
 * Reformat the course array (output by api_get_course_info()) in order, mostly,
2346
 * to switch from 'code' to 'id' in the array.
2347
 *
2348
 * @return array
2349
 *
2350
 * @todo eradicate the false "id"=code field of the $_course array and use the int id
2351
 */
2352
function api_format_course_array(Course $course = null)
2353
{
2354
    if (empty($course)) {
2355
        return [];
2356
    }
2357
2358
    $category = $course->getCategory();
2359
2360
    $courseData = [];
2361
    $courseData['categoryCode'] = '';
2362
    $courseData['categoryName'] = '';
2363
    $courseData['category_id'] = 0;
2364
    if ($category) {
0 ignored issues
show
introduced by
$category is of type Chamilo\CoreBundle\Entity\CourseCategory, thus it always evaluated to true.
Loading history...
2365
        $courseData['categoryCode'] = $category->getCode();
2366
        $courseData['categoryName'] = $category->getName();
2367
        $courseData['category_id'] = $category->getId();
2368
    }
2369
2370
    $courseData['id'] = $courseData['real_id'] = $course->getId();
2371
2372
    // Added
2373
    $courseData['code'] = $courseData['sysCode'] = $course->getCode();
2374
    $courseData['name'] = $courseData['title'] = $course->getTitle();
2375
    $courseData['official_code'] = $courseData['visual_code'] = $course->getVisualCode();
2376
    $courseData['path'] = $courseData['directory'] = $course->getDirectory(); // Use as key in path.
2377
    $courseData['creation_date'] = $course->getCreationDate()->format('Y-m-d H:i:s');
2378
    $courseData['titular'] = $course->getTutorName();
2379
    $courseData['language'] = $courseData['course_language'] = $course->getCourseLanguage();
2380
    $courseData['extLink']['url'] = $courseData['department_url'] = $course->getDepartmentUrl();
2381
    $courseData['extLink']['name'] = $courseData['department_name'] = $course->getDepartmentName();
2382
2383
    $courseData['visibility'] = $course->getVisibility();
2384
    $courseData['subscribe_allowed'] = $courseData['subscribe'] = $course->getSubscribe();
2385
    $courseData['unsubscribe'] = $course->getUnsubscribe();
2386
    $courseData['activate_legal'] = $course->getActivateLegal();
2387
    $courseData['legal'] = $course->getLegal();
2388
    $courseData['show_score'] = $course->getShowScore(); //used in the work tool
2389
2390
    //$coursePath = api_get_path(WEB_COURSE_PATH);
2391
    $coursePath = '/course/';
2392
    $webCourseHome = $coursePath.$courseData['real_id'].'/home';
2393
2394
    // Course password
2395
    $courseData['registration_code'] = $course->getRegistrationCode();
2396
    $courseData['disk_quota'] = $course->getDiskQuota();
2397
    $courseData['course_public_url'] = $webCourseHome;
2398
    $courseData['about_url'] = $coursePath.$courseData['real_id'].'/about';
2399
    $courseData['add_teachers_to_sessions_courses'] = $course->isAddTeachersToSessionsCourses();
2400
    $courseData['entity'] = $course;
2401
2402
    $image = Display::return_icon(
2403
        'course.png',
2404
        null,
2405
        null,
2406
        ICON_SIZE_BIG,
2407
        null,
2408
        true,
2409
        false
2410
    );
2411
2412
    $illustration = Container::getIllustrationRepository()->getIllustrationUrl($course);
2413
    if (!empty($illustration)) {
2414
        $image = $illustration;
2415
    }
2416
2417
    $courseData['course_image'] = $image.'?filter=course_picture_small';
2418
2419
    // Course large image
2420
    /*$courseData['course_image_large_source'] = '';
2421
    if (file_exists($courseSys.'/course-pic.png')) {
2422
        $url_image = $webCourseHome.'/course-pic.png';
2423
        $courseData['course_image_large_source'] = $courseSys.'/course-pic.png';
2424
    } else {
2425
        $url_image = Display::return_icon(
2426
            'session_default.png',
2427
            null,
2428
            null,
2429
            null,
2430
            null,
2431
            true,
2432
            true
2433
        );
2434
    }*/
2435
2436
    $courseData['course_image_large'] = $image.'?filter=course_picture_medium';
2437
2438
    return $courseData;
2439
}
2440
2441
/**
2442
 * Returns a difficult to guess password.
2443
 *
2444
 * @param int $length the length of the password
2445
 *
2446
 * @return string the generated password
2447
 */
2448
function api_generate_password($length = 8)
2449
{
2450
    if ($length < 2) {
2451
        $length = 2;
2452
    }
2453
2454
    $charactersLowerCase = 'abcdefghijkmnopqrstuvwxyz';
2455
    $charactersUpperCase = 'ABCDEFGHJKLMNPQRSTUVWXYZ';
2456
    $minNumbers = 2;
2457
    $length = $length - $minNumbers;
2458
    $minLowerCase = round($length / 2);
2459
    $minUpperCase = $length - $minLowerCase;
2460
2461
    $password = '';
2462
    $passwordRequirements = api_get_configuration_value('password_requirements');
2463
2464
    $factory = new RandomLib\Factory();
2465
    $generator = $factory->getGenerator(new SecurityLib\Strength(SecurityLib\Strength::MEDIUM));
2466
2467
    if (!empty($passwordRequirements)) {
2468
        $length = $passwordRequirements['min']['length'];
2469
        $minNumbers = $passwordRequirements['min']['numeric'];
2470
        $minLowerCase = $passwordRequirements['min']['lowercase'];
2471
        $minUpperCase = $passwordRequirements['min']['uppercase'];
2472
2473
        $rest = $length - $minNumbers - $minLowerCase - $minUpperCase;
2474
        // Add the rest to fill the length requirement
2475
        if ($rest > 0) {
2476
            $password .= $generator->generateString($rest, $charactersLowerCase.$charactersUpperCase);
2477
        }
2478
    }
2479
2480
    // Min digits default 2
2481
    for ($i = 0; $i < $minNumbers; $i++) {
2482
        $password .= $generator->generateInt(2, 9);
2483
    }
2484
2485
    // Min lowercase
2486
    $password .= $generator->generateString($minLowerCase, $charactersLowerCase);
2487
2488
    // Min uppercase
2489
    $password .= $generator->generateString($minUpperCase, $charactersUpperCase);
2490
    $password = str_shuffle($password);
2491
2492
    return $password;
2493
}
2494
2495
/**
2496
 * Checks a password to see wether it is OK to use.
2497
 *
2498
 * @param string $password
2499
 *
2500
 * @return bool if the password is acceptable, false otherwise
2501
 *              Notes about what a password "OK to use" is:
2502
 *              1. The password should be at least 5 characters long.
2503
 *              2. Only English letters (uppercase or lowercase, it doesn't matter) and digits are allowed.
2504
 *              3. The password should contain at least 3 letters.
2505
 *              4. It should contain at least 2 digits.
2506
 *              Settings will change if the configuration value is set: password_requirements
2507
 */
2508
function api_check_password($password)
2509
{
2510
    $passwordRequirements = Security::getPasswordRequirements();
2511
2512
    $minLength = $passwordRequirements['min']['length'];
2513
    $minNumbers = $passwordRequirements['min']['numeric'];
2514
    // Optional
2515
    $minLowerCase = $passwordRequirements['min']['lowercase'];
2516
    $minUpperCase = $passwordRequirements['min']['uppercase'];
2517
2518
    $minLetters = $minLowerCase + $minUpperCase;
2519
    $passwordLength = api_strlen($password);
2520
2521
    $conditions = [
2522
        'min_length' => $passwordLength >= $minLength,
2523
    ];
2524
2525
    $digits = 0;
2526
    $lowerCase = 0;
2527
    $upperCase = 0;
2528
2529
    for ($i = 0; $i < $passwordLength; $i++) {
2530
        $currentCharacterCode = api_ord(api_substr($password, $i, 1));
2531
        if ($currentCharacterCode >= 65 && $currentCharacterCode <= 90) {
2532
            $upperCase++;
2533
        }
2534
2535
        if ($currentCharacterCode >= 97 && $currentCharacterCode <= 122) {
2536
            $lowerCase++;
2537
        }
2538
        if ($currentCharacterCode >= 48 && $currentCharacterCode <= 57) {
2539
            $digits++;
2540
        }
2541
    }
2542
2543
    // Min number of digits
2544
    $conditions['min_numeric'] = $digits >= $minNumbers;
2545
2546
    if (!empty($minUpperCase)) {
2547
        // Uppercase
2548
        $conditions['min_uppercase'] = $upperCase >= $minUpperCase;
2549
    }
2550
2551
    if (!empty($minLowerCase)) {
2552
        // Lowercase
2553
        $conditions['min_lowercase'] = $upperCase >= $minLowerCase;
2554
    }
2555
2556
    // Min letters
2557
    $letters = $upperCase + $lowerCase;
2558
    $conditions['min_letters'] = $letters >= $minLetters;
2559
2560
    $isPasswordOk = true;
2561
    foreach ($conditions as $condition) {
2562
        if (false === $condition) {
2563
            $isPasswordOk = false;
2564
            break;
2565
        }
2566
    }
2567
2568
    if (false === $isPasswordOk) {
2569
        $output = get_lang('The new password does not match the minimum security requirements').'<br />';
2570
        $output .= Security::getPasswordRequirementsToString($conditions);
2571
2572
        Display::addFlash(Display::return_message($output, 'warning', false));
2573
    }
2574
2575
    return $isPasswordOk;
2576
}
2577
2578
/**
2579
 * Returns the status string corresponding to the status code.
2580
 *
2581
 * @author Noel Dieschburg
2582
 *
2583
 * @param the int status code
2584
 *
2585
 * @return string
2586
 */
2587
function get_status_from_code($status_code)
2588
{
2589
    switch ($status_code) {
2590
        case STUDENT:
2591
            return get_lang('Student', '');
2592
        case COURSEMANAGER:
2593
            return get_lang('Teacher', '');
2594
        case SESSIONADMIN:
2595
            return get_lang('SessionsAdmin', '');
2596
        case DRH:
2597
            return get_lang('Drh', '');
2598
    }
2599
}
2600
2601
/**
2602
 * Gets the current Chamilo (not PHP/cookie) session ID.
2603
 *
2604
 * @return int O if no active session, the session ID otherwise
2605
 */
2606
function api_get_session_id()
2607
{
2608
    return (int) Session::read('sid', 0);
2609
}
2610
2611
/**
2612
 * Gets the current Chamilo (not social network) group ID.
2613
 *
2614
 * @return int O if no active session, the session ID otherwise
2615
 */
2616
function api_get_group_id()
2617
{
2618
    return Session::read('gid', 0);
2619
}
2620
2621
/**
2622
 * Gets the current or given session name.
2623
 *
2624
 * @param   int     Session ID (optional)
2625
 *
2626
 * @return string The session name, or null if not found
2627
 */
2628
function api_get_session_name($session_id = 0)
2629
{
2630
    if (empty($session_id)) {
2631
        $session_id = api_get_session_id();
2632
        if (empty($session_id)) {
2633
            return null;
2634
        }
2635
    }
2636
    $t = Database::get_main_table(TABLE_MAIN_SESSION);
2637
    $s = "SELECT name FROM $t WHERE id = ".(int) $session_id;
2638
    $r = Database::query($s);
2639
    $c = Database::num_rows($r);
2640
    if ($c > 0) {
2641
        //technically, there can be only one, but anyway we take the first
2642
        $rec = Database::fetch_array($r);
2643
2644
        return $rec['name'];
2645
    }
2646
2647
    return null;
2648
}
2649
2650
/**
2651
 * Gets the session info by id.
2652
 *
2653
 * @param int $id Session ID
2654
 *
2655
 * @return array information of the session
2656
 */
2657
function api_get_session_info($id)
2658
{
2659
    return SessionManager::fetch($id);
2660
}
2661
2662
/**
2663
 * Gets the session visibility by session id.
2664
 *
2665
 * @param int  $session_id
2666
 * @param int  $courseId
2667
 * @param bool $ignore_visibility_for_admins
2668
 *
2669
 * @return int
2670
 *             0 = session still available,
2671
 *             SESSION_VISIBLE_READ_ONLY = 1,
2672
 *             SESSION_VISIBLE = 2,
2673
 *             SESSION_INVISIBLE = 3
2674
 */
2675
function api_get_session_visibility(
2676
    $session_id,
2677
    $courseId = null,
2678
    $ignore_visibility_for_admins = true
2679
) {
2680
    if (api_is_platform_admin()) {
2681
        if ($ignore_visibility_for_admins) {
2682
            return SESSION_AVAILABLE;
2683
        }
2684
    }
2685
2686
    $now = time();
2687
    if (empty($session_id)) {
2688
        return 0; // Means that the session is still available.
2689
    }
2690
2691
    $session_id = (int) $session_id;
2692
    $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
2693
2694
    $result = Database::query("SELECT * FROM $tbl_session WHERE id = $session_id");
2695
2696
    if (Database::num_rows($result) <= 0) {
2697
        return SESSION_INVISIBLE;
2698
    }
2699
2700
    $row = Database::fetch_array($result, 'ASSOC');
2701
    $visibility = $row['visibility'];
2702
2703
    // I don't care the session visibility.
2704
    if (empty($row['access_start_date']) && empty($row['access_end_date'])) {
2705
        // Session duration per student.
2706
        if (isset($row['duration']) && !empty($row['duration'])) {
2707
            $duration = $row['duration'] * 24 * 60 * 60;
2708
            $courseAccess = CourseManager::getFirstCourseAccessPerSessionAndUser($session_id, api_get_user_id());
2709
2710
            // If there is a session duration but there is no previous
2711
            // access by the user, then the session is still available
2712
            if (0 == count($courseAccess)) {
2713
                return SESSION_AVAILABLE;
2714
            }
2715
2716
            $currentTime = time();
2717
            $firstAccess = isset($courseAccess['login_course_date'])
2718
                ? api_strtotime($courseAccess['login_course_date'], 'UTC')
2719
                : 0;
2720
            $userDurationData = SessionManager::getUserSession(
2721
                api_get_user_id(),
2722
                $session_id
2723
            );
2724
            $userDuration = isset($userDurationData['duration'])
2725
                ? (intval($userDurationData['duration']) * 24 * 60 * 60)
2726
                : 0;
2727
2728
            $totalDuration = $firstAccess + $duration + $userDuration;
2729
2730
            return $totalDuration > $currentTime ? SESSION_AVAILABLE : SESSION_VISIBLE_READ_ONLY;
2731
        }
2732
2733
        return SESSION_AVAILABLE;
2734
    }
2735
2736
    // If start date was set.
2737
    if (!empty($row['access_start_date'])) {
2738
        $visibility = $now > api_strtotime($row['access_start_date'], 'UTC') ? SESSION_AVAILABLE : SESSION_INVISIBLE;
2739
    }
2740
2741
    // If the end date was set.
2742
    if (!empty($row['access_end_date'])) {
2743
        // Only if date_start said that it was ok
2744
        if (SESSION_AVAILABLE === $visibility) {
2745
            $visibility = $now < api_strtotime($row['access_end_date'], 'UTC')
2746
                ? SESSION_AVAILABLE // Date still available
2747
                : $row['visibility']; // Session ends
2748
        }
2749
    }
2750
2751
    // If I'm a coach the visibility can change in my favor depending in the coach dates.
2752
    $isCoach = api_is_coach($session_id, $courseId);
2753
2754
    if ($isCoach) {
2755
        // Test start date.
2756
        if (!empty($row['coach_access_start_date'])) {
2757
            $start = api_strtotime($row['coach_access_start_date'], 'UTC');
2758
            $visibility = $start < $now ? SESSION_AVAILABLE : SESSION_INVISIBLE;
2759
        }
2760
2761
        // Test end date.
2762
        if (!empty($row['coach_access_end_date'])) {
2763
            if (SESSION_AVAILABLE === $visibility) {
2764
                $endDateCoach = api_strtotime($row['coach_access_end_date'], 'UTC');
2765
                $visibility = $endDateCoach >= $now ? SESSION_AVAILABLE : $row['visibility'];
2766
            }
2767
        }
2768
    }
2769
2770
    return $visibility;
2771
}
2772
2773
/**
2774
 * This function returns a (star) session icon if the session is not null and
2775
 * the user is not a student.
2776
 *
2777
 * @param int $sessionId
2778
 * @param int $statusId  User status id - if 5 (student), will return empty
2779
 *
2780
 * @return string Session icon
2781
 */
2782
function api_get_session_image($sessionId, $statusId)
2783
{
2784
    $sessionId = (int) $sessionId;
2785
    $image = '';
2786
    if (STUDENT != $statusId) {
2787
        // Check whether is not a student
2788
        if ($sessionId > 0) {
2789
            $image = '&nbsp;&nbsp;'.Display::return_icon(
2790
                'star.png',
2791
                get_lang('Session-specific resource'),
2792
                ['align' => 'absmiddle'],
2793
                ICON_SIZE_SMALL
2794
            );
2795
        }
2796
    }
2797
2798
    return $image;
2799
}
2800
2801
/**
2802
 * This function add an additional condition according to the session of the course.
2803
 *
2804
 * @param int    $session_id        session id
2805
 * @param bool   $and               optional, true if more than one condition false if the only condition in the query
2806
 * @param bool   $with_base_content optional, true to accept content with session=0 as well,
2807
 *                                  false for strict session condition
2808
 * @param string $session_field
2809
 *
2810
 * @return string condition of the session
2811
 */
2812
function api_get_session_condition(
2813
    $session_id,
2814
    $and = true,
2815
    $with_base_content = false,
2816
    $session_field = 'session_id'
2817
) {
2818
    $session_id = (int) $session_id;
2819
2820
    if (empty($session_field)) {
2821
        $session_field = 'session_id';
2822
    }
2823
    // Condition to show resources by session
2824
    $condition_add = $and ? ' AND ' : ' WHERE ';
2825
2826
    if ($with_base_content) {
2827
        $condition_session = $condition_add." ( $session_field = $session_id OR $session_field = 0 OR $session_field IS NULL) ";
2828
    } else {
2829
        if (empty($session_id)) {
2830
            $condition_session = $condition_add." ($session_field = $session_id OR $session_field IS NULL)";
2831
        } else {
2832
            $condition_session = $condition_add." $session_field = $session_id ";
2833
        }
2834
    }
2835
2836
    return $condition_session;
2837
}
2838
2839
/**
2840
 * Returns the value of a setting from the web-adjustable admin config settings.
2841
 *
2842
 * WARNING true/false are stored as string, so when comparing you need to check e.g.
2843
 * if (api_get_setting('show_navigation_menu') == 'true') //CORRECT
2844
 * instead of
2845
 * if (api_get_setting('show_navigation_menu') == true) //INCORRECT
2846
 *
2847
 * @param string $variable The variable name
2848
 *
2849
 * @return string
2850
 */
2851
function api_get_setting($variable)
2852
{
2853
    $settingsManager = Container::getSettingsManager();
2854
    if (empty($settingsManager)) {
2855
        return '';
2856
    }
2857
    $variable = trim($variable);
2858
2859
    switch ($variable) {
2860
        /*case 'header_extra_content':
2861
            $filename = api_get_path(SYS_PATH).api_get_home_path().'header_extra_content.txt';
2862
            if (file_exists($filename)) {
2863
                $value = file_get_contents($filename);
2864
2865
                return $value;
2866
            } else {
2867
                return '';
2868
            }
2869
            break;
2870
        case 'footer_extra_content':
2871
            $filename = api_get_path(SYS_PATH).api_get_home_path().'footer_extra_content.txt';
2872
            if (file_exists($filename)) {
2873
                $value = file_get_contents($filename);
2874
2875
                return $value;
2876
            } else {
2877
                return '';
2878
            }
2879
            break;*/
2880
        case 'server_type':
2881
            $test = ['dev', 'test'];
2882
            $environment = Container::getEnvironment();
2883
            if (in_array($environment, $test)) {
2884
                return 'test';
2885
            }
2886
2887
            return 'prod';
2888
        case 'stylesheets':
2889
            $variable = 'platform.theme';
2890
        // deprecated settings
2891
        // no break
2892
        case 'openid_authentication':
2893
        case 'service_ppt2lp':
2894
        case 'formLogin_hide_unhide_label':
2895
            return false;
2896
            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...
2897
        case 'tool_visible_by_default_at_creation':
2898
            $values = $settingsManager->getSetting($variable);
2899
            $newResult = [];
2900
            foreach ($values as $parameter) {
2901
                $newResult[$parameter] = 'true';
2902
            }
2903
2904
            return $newResult;
2905
            break;
2906
        default:
2907
            return $settingsManager->getSetting($variable);
2908
            break;
2909
    }
2910
}
2911
2912
/**
2913
 * @param string $variable
2914
 * @param string $option
2915
 *
2916
 * @return bool
2917
 */
2918
function api_get_setting_in_list($variable, $option)
2919
{
2920
    $value = api_get_setting($variable);
2921
2922
    return in_array($option, $value);
2923
}
2924
2925
/**
2926
 * @param string $plugin
2927
 * @param string $variable
2928
 *
2929
 * @return string
2930
 */
2931
function api_get_plugin_setting($plugin, $variable)
2932
{
2933
    $variableName = $plugin.'_'.$variable;
2934
    //$result = api_get_setting($variableName);
2935
    $params = [
2936
        'category = ? AND subkey = ? AND variable = ?' => [
2937
            'Plugins',
2938
            $plugin,
2939
            $variableName,
2940
        ],
2941
    ];
2942
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2943
    $result = Database::select(
2944
        'selected_value',
2945
        $table,
2946
        ['where' => $params],
2947
        'one'
2948
    );
2949
    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...
2950
        $value = $result['selected_value'];
2951
        $serializedValue = @unserialize($result['selected_value'], []);
2952
        if (false !== $serializedValue) {
2953
            $value = $serializedValue;
2954
        }
2955
2956
        return $value;
2957
    }
2958
2959
    return null;
2960
    /// Old code
2961
2962
    $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...
2963
    $result = api_get_setting($variableName);
2964
2965
    if (isset($result[$plugin])) {
2966
        $value = $result[$plugin];
2967
2968
        $unserialized = UnserializeApi::unserialize('not_allowed_classes', $value, true);
2969
2970
        if (false !== $unserialized) {
2971
            $value = $unserialized;
2972
        }
2973
2974
        return $value;
2975
    }
2976
2977
    return null;
2978
}
2979
2980
/**
2981
 * Returns the value of a setting from the web-adjustable admin config settings.
2982
 */
2983
function api_get_settings_params($params)
2984
{
2985
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2986
    $result = Database::select('*', $table, ['where' => $params]);
2987
2988
    return $result;
2989
}
2990
2991
/**
2992
 * @param array $params example: [id = ? => '1']
2993
 *
2994
 * @return array
2995
 */
2996
function api_get_settings_params_simple($params)
2997
{
2998
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2999
    $result = Database::select('*', $table, ['where' => $params], 'one');
3000
3001
    return $result;
3002
}
3003
3004
/**
3005
 * Returns the value of a setting from the web-adjustable admin config settings.
3006
 */
3007
function api_delete_settings_params($params)
3008
{
3009
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
3010
    $result = Database::delete($table, $params);
3011
3012
    return $result;
3013
}
3014
3015
/**
3016
 * Returns an escaped version of $_SERVER['PHP_SELF'] to avoid XSS injection.
3017
 *
3018
 * @return string Escaped version of $_SERVER['PHP_SELF']
3019
 */
3020
function api_get_self()
3021
{
3022
    return htmlentities($_SERVER['PHP_SELF']);
3023
}
3024
3025
/* USER PERMISSIONS */
3026
3027
/**
3028
 * Checks whether current user is a platform administrator.
3029
 *
3030
 * @param bool $allowSessionAdmins Whether session admins should be considered admins or not
3031
 * @param bool $allowDrh           Whether HR directors should be considered admins or not
3032
 *
3033
 * @return bool true if the user has platform admin rights,
3034
 *              false otherwise
3035
 *
3036
 * @see usermanager::is_admin(user_id) for a user-id specific function
3037
 */
3038
function api_is_platform_admin($allowSessionAdmins = false, $allowDrh = false)
3039
{
3040
    $currentUser = api_get_current_user();
3041
3042
    if (null === $currentUser) {
3043
        return false;
3044
    }
3045
3046
    $isAdmin = Session::read('is_platformAdmin');
3047
    if ($isAdmin) {
3048
        return true;
3049
    }
3050
    $user = api_get_user_info();
3051
3052
    return
3053
        isset($user['status']) &&
3054
        (
3055
            ($allowSessionAdmins && SESSIONADMIN == $user['status']) ||
3056
            ($allowDrh && DRH == $user['status'])
3057
        );
3058
}
3059
3060
/**
3061
 * Checks whether the user given as user id is in the admin table.
3062
 *
3063
 * @param int $user_id If none provided, will use current user
3064
 * @param int $url     URL ID. If provided, also check if the user is active on given URL
3065
 *
3066
 * @return bool True if the user is admin, false otherwise
3067
 */
3068
function api_is_platform_admin_by_id($user_id = null, $url = null)
3069
{
3070
    $user_id = (int) $user_id;
3071
    if (empty($user_id)) {
3072
        $user_id = api_get_user_id();
3073
    }
3074
    $admin_table = Database::get_main_table(TABLE_MAIN_ADMIN);
3075
    $sql = "SELECT * FROM $admin_table WHERE user_id = $user_id";
3076
    $res = Database::query($sql);
3077
    $is_admin = 1 === Database::num_rows($res);
3078
    if (!$is_admin || !isset($url)) {
3079
        return $is_admin;
3080
    }
3081
    // We get here only if $url is set
3082
    $url = (int) $url;
3083
    $url_user_table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
3084
    $sql = "SELECT * FROM $url_user_table
3085
            WHERE access_url_id = $url AND user_id = $user_id";
3086
    $res = Database::query($sql);
3087
    $result = 1 === Database::num_rows($res);
3088
3089
    return $result;
3090
}
3091
3092
/**
3093
 * Returns the user's numeric status ID from the users table.
3094
 *
3095
 * @param int $user_id If none provided, will use current user
3096
 *
3097
 * @return int User's status (1 for teacher, 5 for student, etc)
3098
 */
3099
function api_get_user_status($user_id = null)
3100
{
3101
    $user_id = (int) $user_id;
3102
    if (empty($user_id)) {
3103
        $user_id = api_get_user_id();
3104
    }
3105
    $table = Database::get_main_table(TABLE_MAIN_USER);
3106
    $sql = "SELECT status FROM $table WHERE user_id = $user_id ";
3107
    $result = Database::query($sql);
3108
    $status = null;
3109
    if (Database::num_rows($result)) {
3110
        $row = Database::fetch_array($result);
3111
        $status = $row['status'];
3112
    }
3113
3114
    return $status;
3115
}
3116
3117
/**
3118
 * Checks whether current user is allowed to create courses.
3119
 *
3120
 * @return bool true if the user has course creation rights,
3121
 *              false otherwise
3122
 */
3123
function api_is_allowed_to_create_course()
3124
{
3125
    if (api_is_platform_admin()) {
3126
        return true;
3127
    }
3128
3129
    // Teachers can only create courses
3130
    if (api_is_teacher()) {
3131
        if ('true' === api_get_setting('allow_users_to_create_courses')) {
3132
            return true;
3133
        } else {
3134
            return false;
3135
        }
3136
    }
3137
3138
    return Session::read('is_allowedCreateCourse');
3139
}
3140
3141
/**
3142
 * Checks whether the current user is a course administrator.
3143
 *
3144
 * @return bool True if current user is a course administrator
3145
 */
3146
function api_is_course_admin()
3147
{
3148
    if (api_is_platform_admin()) {
3149
        return true;
3150
    }
3151
3152
    $user = api_get_current_user();
3153
    if ($user) {
3154
        if (
3155
            $user->hasRole('ROLE_CURRENT_SESSION_COURSE_TEACHER') ||
3156
            $user->hasRole('ROLE_CURRENT_COURSE_TEACHER')
3157
        ) {
3158
            return true;
3159
        }
3160
    }
3161
3162
    return false;
3163
    //return Session::read('is_courseAdmin');
3164
}
3165
3166
/**
3167
 * Checks whether the current user is a course coach
3168
 * Based on the presence of user in session.id_coach (session general coach).
3169
 *
3170
 * @return bool True if current user is a course coach
3171
 */
3172
function api_is_session_general_coach()
3173
{
3174
    return Session::read('is_session_general_coach');
3175
}
3176
3177
/**
3178
 * Checks whether the current user is a course tutor
3179
 * Based on the presence of user in session_rel_course_rel_user.user_id with status = 2.
3180
 *
3181
 * @return bool True if current user is a course tutor
3182
 */
3183
function api_is_course_tutor()
3184
{
3185
    return Session::read('is_courseTutor');
3186
}
3187
3188
/**
3189
 * @param int $user_id
3190
 * @param int $courseId
3191
 * @param int $session_id
3192
 *
3193
 * @return bool
3194
 */
3195
function api_is_course_session_coach($user_id, $courseId, $session_id)
3196
{
3197
    $session_table = Database::get_main_table(TABLE_MAIN_SESSION);
3198
    $session_rel_course_rel_user_table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3199
3200
    $user_id = (int) $user_id;
3201
    $session_id = (int) $session_id;
3202
    $courseId = (int) $courseId;
3203
3204
    $sql = "SELECT DISTINCT session.id
3205
            FROM $session_table
3206
            INNER JOIN $session_rel_course_rel_user_table session_rc_ru
3207
            ON session.id = session_rc_ru.session_id
3208
            WHERE
3209
                session_rc_ru.user_id = '".$user_id."'  AND
3210
                session_rc_ru.c_id = '$courseId' AND
3211
                session_rc_ru.status = 2 AND
3212
                session_rc_ru.session_id = '$session_id'";
3213
    $result = Database::query($sql);
3214
3215
    return Database::num_rows($result) > 0;
3216
}
3217
3218
/**
3219
 * Checks whether the current user is a course or session coach.
3220
 *
3221
 * @param int $session_id
3222
 * @param int $courseId
3223
 * @param bool  Check whether we are in student view and, if we are, return false
3224
 *
3225
 * @return bool True if current user is a course or session coach
3226
 */
3227
function api_is_coach($session_id = 0, $courseId = null, $check_student_view = true)
3228
{
3229
    $userId = api_get_user_id();
3230
3231
    if (!empty($session_id)) {
3232
        $session_id = (int) $session_id;
3233
    } else {
3234
        $session_id = api_get_session_id();
3235
    }
3236
3237
    // The student preview was on
3238
    if ($check_student_view && api_is_student_view_active()) {
3239
        return false;
3240
    }
3241
3242
    if (!empty($courseId)) {
3243
        $courseId = (int) $courseId;
3244
    } else {
3245
        $courseId = api_get_course_int_id();
3246
    }
3247
3248
    $session_table = Database::get_main_table(TABLE_MAIN_SESSION);
3249
    $session_rel_course_rel_user_table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3250
    $sessionIsCoach = [];
3251
3252
    if (!empty($courseId)) {
3253
        $sql = "SELECT DISTINCT s.id, name, access_start_date, access_end_date
3254
                FROM $session_table s
3255
                INNER JOIN $session_rel_course_rel_user_table session_rc_ru
3256
                ON session_rc_ru.session_id = s.id AND session_rc_ru.user_id = '".$userId."'
3257
                WHERE
3258
                    session_rc_ru.c_id = '$courseId' AND
3259
                    session_rc_ru.status = 2 AND
3260
                    session_rc_ru.session_id = '$session_id'";
3261
        $result = Database::query($sql);
3262
        $sessionIsCoach = Database::store_result($result);
3263
    }
3264
3265
    if (!empty($session_id)) {
3266
        $sql = "SELECT DISTINCT id, name, access_start_date, access_end_date
3267
                FROM $session_table
3268
                WHERE session.id_coach = $userId AND id = $session_id
3269
                ORDER BY access_start_date, access_end_date, name";
3270
        $result = Database::query($sql);
3271
        if (!empty($sessionIsCoach)) {
3272
            $sessionIsCoach = array_merge(
3273
                $sessionIsCoach,
3274
                Database::store_result($result)
3275
            );
3276
        } else {
3277
            $sessionIsCoach = Database::store_result($result);
3278
        }
3279
    }
3280
3281
    return count($sessionIsCoach) > 0;
3282
}
3283
3284
/**
3285
 * Checks whether the current user is a session administrator.
3286
 *
3287
 * @return bool True if current user is a course administrator
3288
 */
3289
function api_is_session_admin()
3290
{
3291
    $user = api_get_user_info();
3292
3293
    return isset($user['status']) && SESSIONADMIN == $user['status'];
3294
}
3295
3296
/**
3297
 * Checks whether the current user is a human resources manager.
3298
 *
3299
 * @return bool True if current user is a human resources manager
3300
 */
3301
function api_is_drh()
3302
{
3303
    $user = api_get_user_info();
3304
3305
    return isset($user['status']) && DRH == $user['status'];
3306
}
3307
3308
/**
3309
 * Checks whether the current user is a student.
3310
 *
3311
 * @return bool True if current user is a human resources manager
3312
 */
3313
function api_is_student()
3314
{
3315
    $user = api_get_user_info();
3316
3317
    return isset($user['status']) && STUDENT == $user['status'];
3318
}
3319
3320
/**
3321
 * Checks whether the current user has the status 'teacher'.
3322
 *
3323
 * @return bool True if current user is a human resources manager
3324
 */
3325
function api_is_teacher()
3326
{
3327
    $user = api_get_user_info();
3328
3329
    return isset($user['status']) && COURSEMANAGER == $user['status'];
3330
}
3331
3332
/**
3333
 * Checks whether the current user is a invited user.
3334
 *
3335
 * @return bool
3336
 */
3337
function api_is_invitee()
3338
{
3339
    $user = api_get_user_info();
3340
3341
    return isset($user['status']) && INVITEE == $user['status'];
3342
}
3343
3344
/**
3345
 * This function checks whether a session is assigned into a category.
3346
 *
3347
 * @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...
3348
 * @param string    - category name
3349
 *
3350
 * @return bool - true if is found, otherwise false
3351
 */
3352
function api_is_session_in_category($session_id, $category_name)
3353
{
3354
    $session_id = (int) $session_id;
3355
    $category_name = Database::escape_string($category_name);
3356
    $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
3357
    $tbl_session_category = Database::get_main_table(TABLE_MAIN_SESSION_CATEGORY);
3358
3359
    $sql = "SELECT 1
3360
            FROM $tbl_session
3361
            WHERE $session_id IN (
3362
                SELECT s.id FROM $tbl_session s, $tbl_session_category sc
3363
                WHERE
3364
                  s.session_category_id = sc.id AND
3365
                  sc.name LIKE '%$category_name'
3366
            )";
3367
    $rs = Database::query($sql);
3368
3369
    if (Database::num_rows($rs) > 0) {
3370
        return true;
3371
    } else {
3372
        return false;
3373
    }
3374
}
3375
3376
/**
3377
 * Displays the title of a tool.
3378
 * Normal use: parameter is a string:
3379
 * api_display_tool_title("My Tool").
3380
 *
3381
 * Optionally, there can be a subtitle below
3382
 * the normal title, and / or a supra title above the normal title.
3383
 *
3384
 * e.g. supra title:
3385
 * group
3386
 * GROUP PROPERTIES
3387
 *
3388
 * e.g. subtitle:
3389
 * AGENDA
3390
 * calender & events tool
3391
 *
3392
 * @author Hugues Peeters <[email protected]>
3393
 *
3394
 * @param mixed $title_element - it could either be a string or an array
3395
 *                             containing 'supraTitle', 'mainTitle',
3396
 *                             'subTitle'
3397
 */
3398
function api_display_tool_title($title_element)
3399
{
3400
    if (is_string($title_element)) {
3401
        $tit = $title_element;
3402
        unset($title_element);
3403
        $title_element = [];
3404
        $title_element['mainTitle'] = $tit;
3405
    }
3406
    echo '<h3>';
3407
    if (!empty($title_element['supraTitle'])) {
3408
        echo '<small>'.$title_element['supraTitle'].'</small><br />';
3409
    }
3410
    if (!empty($title_element['mainTitle'])) {
3411
        echo $title_element['mainTitle'];
3412
    }
3413
    if (!empty($title_element['subTitle'])) {
3414
        echo '<br /><small>'.$title_element['subTitle'].'</small>';
3415
    }
3416
    echo '</h3>';
3417
}
3418
3419
/**
3420
 * Displays options for switching between student view and course manager view.
3421
 *
3422
 * Changes in version 1.2 (Patrick Cool)
3423
 * Student view switch now behaves as a real switch. It maintains its current state until the state
3424
 * is changed explicitly
3425
 *
3426
 * Changes in version 1.1 (Patrick Cool)
3427
 * student view now works correctly in subfolders of the document tool
3428
 * student view works correctly in the new links tool
3429
 *
3430
 * Example code for using this in your tools:
3431
 * //if ($is_courseAdmin && api_get_setting('student_view_enabled') == 'true') {
3432
 * //   display_tool_view_option($isStudentView);
3433
 * //}
3434
 * //and in later sections, use api_is_allowed_to_edit()
3435
 *
3436
 * @author Roan Embrechts
3437
 * @author Patrick Cool
3438
 * @author Julio Montoya, changes added in Chamilo
3439
 *
3440
 * @version 1.2
3441
 *
3442
 * @todo rewrite code so it is easier to understand
3443
 */
3444
function api_display_tool_view_option()
3445
{
3446
    if ('true' != api_get_setting('student_view_enabled')) {
3447
        return '';
3448
    }
3449
3450
    $sourceurl = '';
3451
    $is_framed = false;
3452
    // Exceptions apply for all multi-frames pages
3453
    if (false !== strpos($_SERVER['REQUEST_URI'], 'chat/chat_banner.php')) {
3454
        // The chat is a multiframe bit that doesn't work too well with the student_view, so do not show the link
3455
        return '';
3456
    }
3457
3458
    // Uncomment to remove student view link from document view page
3459
    if (false !== strpos($_SERVER['REQUEST_URI'], 'lp/lp_header.php')) {
3460
        if (empty($_GET['lp_id'])) {
3461
            return '';
3462
        }
3463
        $sourceurl = substr($_SERVER['REQUEST_URI'], 0, strpos($_SERVER['REQUEST_URI'], '?'));
3464
        $sourceurl = str_replace(
3465
            'lp/lp_header.php',
3466
            'lp/lp_controller.php?'.api_get_cidreq().'&action=view&lp_id='.intval($_GET['lp_id']).'&isStudentView='.('studentview' == $_SESSION['studentview'] ? 'false' : 'true'),
3467
            $sourceurl
3468
        );
3469
        //showinframes doesn't handle student view anyway...
3470
        //return '';
3471
        $is_framed = true;
3472
    }
3473
3474
    // Check whether the $_SERVER['REQUEST_URI'] contains already url parameters (thus a questionmark)
3475
    if (!$is_framed) {
3476
        if (false === strpos($_SERVER['REQUEST_URI'], '?')) {
3477
            $sourceurl = api_get_self().'?'.api_get_cidreq();
3478
        } else {
3479
            $sourceurl = $_SERVER['REQUEST_URI'];
3480
        }
3481
    }
3482
3483
    $output_string = '';
3484
    if (!empty($_SESSION['studentview'])) {
3485
        if ('studentview' == $_SESSION['studentview']) {
3486
            // We have to remove the isStudentView=true from the $sourceurl
3487
            $sourceurl = str_replace('&isStudentView=true', '', $sourceurl);
3488
            $sourceurl = str_replace('&isStudentView=false', '', $sourceurl);
3489
            $output_string .= '<a class="btn btn-primary btn-sm" href="'.$sourceurl.'&isStudentView=false" target="_self">'.
3490
                Display::returnFontAwesomeIcon('eye').' '.get_lang('Switch to teacher view').'</a>';
3491
        } elseif ('teacherview' == $_SESSION['studentview']) {
3492
            // Switching to teacherview
3493
            $sourceurl = str_replace('&isStudentView=true', '', $sourceurl);
3494
            $sourceurl = str_replace('&isStudentView=false', '', $sourceurl);
3495
            $output_string .= '<a class="btn btn-default btn-sm" href="'.$sourceurl.'&isStudentView=true" target="_self">'.
3496
                Display::returnFontAwesomeIcon('eye').' '.get_lang('Switch to student view').'</a>';
3497
        }
3498
    } else {
3499
        $output_string .= '<a class="btn btn-default btn-sm" href="'.$sourceurl.'&isStudentView=true" target="_self">'.
3500
            Display::returnFontAwesomeIcon('eye').' '.get_lang('Switch to student view').'</a>';
3501
    }
3502
    $output_string = Security::remove_XSS($output_string);
3503
    $html = Display::tag('div', $output_string, ['class' => 'view-options']);
3504
3505
    return $html;
3506
}
3507
3508
// TODO: This is for the permission section.
3509
/**
3510
 * Function that removes the need to directly use is_courseAdmin global in
3511
 * tool scripts. It returns true or false depending on the user's rights in
3512
 * this particular course.
3513
 * Optionally checking for tutor and coach roles here allows us to use the
3514
 * student_view feature altogether with these roles as well.
3515
 *
3516
 * @param bool  Whether to check if the user has the tutor role
3517
 * @param bool  Whether to check if the user has the coach role
3518
 * @param bool  Whether to check if the user has the session coach role
3519
 * @param bool  check the student view or not
3520
 *
3521
 * @author Roan Embrechts
3522
 * @author Patrick Cool
3523
 * @author Julio Montoya
3524
 *
3525
 * @version 1.1, February 2004
3526
 *
3527
 * @return bool true: the user has the rights to edit, false: he does not
3528
 */
3529
function api_is_allowed_to_edit(
3530
    $tutor = false,
3531
    $coach = false,
3532
    $session_coach = false,
3533
    $check_student_view = true
3534
) {
3535
    $allowSessionAdminEdit = true === api_get_setting('session.session_admins_edit_courses_content');
3536
    // Admins can edit anything.
3537
    if (api_is_platform_admin($allowSessionAdminEdit)) {
3538
        //The student preview was on
3539
        if ($check_student_view && api_is_student_view_active()) {
3540
            return false;
3541
        }
3542
3543
        return true;
3544
    }
3545
3546
    $sessionId = api_get_session_id();
3547
3548
    if ($sessionId && api_get_configuration_value('session_courses_read_only_mode')) {
3549
        $efv = new ExtraFieldValue('course');
3550
        $lockExrafieldField = $efv->get_values_by_handler_and_field_variable(
3551
            api_get_course_int_id(),
3552
            'session_courses_read_only_mode'
3553
        );
3554
3555
        if (!empty($lockExrafieldField['value'])) {
3556
            return false;
3557
        }
3558
    }
3559
3560
    $is_allowed_coach_to_edit = api_is_coach(null, null, $check_student_view);
3561
    $session_visibility = api_get_session_visibility($sessionId);
3562
    $is_courseAdmin = api_is_course_admin();
3563
3564
    if (!$is_courseAdmin && $tutor) {
3565
        // If we also want to check if the user is a tutor...
3566
        $is_courseAdmin = $is_courseAdmin || api_is_course_tutor();
3567
    }
3568
3569
    if (!$is_courseAdmin && $coach) {
3570
        // If we also want to check if the user is a coach...';
3571
        // Check if session visibility is read only for coaches.
3572
        if (SESSION_VISIBLE_READ_ONLY == $session_visibility) {
3573
            $is_allowed_coach_to_edit = false;
3574
        }
3575
3576
        if ('true' === api_get_setting('allow_coach_to_edit_course_session')) {
3577
            // Check if coach is allowed to edit a course.
3578
            $is_courseAdmin = $is_courseAdmin || $is_allowed_coach_to_edit;
3579
        }
3580
    }
3581
3582
    if (!$is_courseAdmin && $session_coach) {
3583
        $is_courseAdmin = $is_courseAdmin || $is_allowed_coach_to_edit;
3584
    }
3585
3586
    // Check if the student_view is enabled, and if so, if it is activated.
3587
    if ('true' === api_get_setting('student_view_enabled')) {
3588
        $studentView = api_is_student_view_active();
3589
        if (!empty($sessionId)) {
3590
            // Check if session visibility is read only for coaches.
3591
            if (SESSION_VISIBLE_READ_ONLY == $session_visibility) {
3592
                $is_allowed_coach_to_edit = false;
3593
            }
3594
3595
            $is_allowed = false;
3596
            if ('true' === api_get_setting('allow_coach_to_edit_course_session')) {
3597
                // Check if coach is allowed to edit a course.
3598
                $is_allowed = $is_allowed_coach_to_edit;
3599
            }
3600
            if ($check_student_view) {
3601
                $is_allowed = $is_allowed && false === $studentView;
3602
            }
3603
        } else {
3604
            $is_allowed = $is_courseAdmin;
3605
            if ($check_student_view) {
3606
                $is_allowed = $is_courseAdmin && false === $studentView;
3607
            }
3608
        }
3609
3610
        return $is_allowed;
3611
    } else {
3612
        return $is_courseAdmin;
3613
    }
3614
}
3615
3616
/**
3617
 * Returns true if user is a course coach of at least one course in session.
3618
 *
3619
 * @param int $sessionId
3620
 *
3621
 * @return bool
3622
 */
3623
function api_is_coach_of_course_in_session($sessionId)
3624
{
3625
    if (api_is_platform_admin()) {
3626
        return true;
3627
    }
3628
3629
    $userId = api_get_user_id();
3630
    $courseList = UserManager::get_courses_list_by_session(
3631
        $userId,
3632
        $sessionId
3633
    );
3634
3635
    // Session visibility.
3636
    $visibility = api_get_session_visibility(
3637
        $sessionId,
3638
        null,
3639
        false
3640
    );
3641
3642
    if (SESSION_VISIBLE != $visibility && !empty($courseList)) {
3643
        // Course Coach session visibility.
3644
        $blockedCourseCount = 0;
3645
        $closedVisibilityList = [
3646
            COURSE_VISIBILITY_CLOSED,
3647
            COURSE_VISIBILITY_HIDDEN,
3648
        ];
3649
3650
        foreach ($courseList as $course) {
3651
            // Checking session visibility
3652
            $sessionCourseVisibility = api_get_session_visibility(
3653
                $sessionId,
3654
                $course['real_id']
3655
            );
3656
3657
            $courseIsVisible = !in_array(
3658
                $course['visibility'],
3659
                $closedVisibilityList
3660
            );
3661
            if (false === $courseIsVisible || SESSION_INVISIBLE == $sessionCourseVisibility) {
3662
                $blockedCourseCount++;
3663
            }
3664
        }
3665
3666
        // If all courses are blocked then no show in the list.
3667
        if ($blockedCourseCount === count($courseList)) {
3668
            $visibility = SESSION_INVISIBLE;
3669
        } else {
3670
            $visibility = SESSION_VISIBLE;
3671
        }
3672
    }
3673
3674
    switch ($visibility) {
3675
        case SESSION_VISIBLE_READ_ONLY:
3676
        case SESSION_VISIBLE:
3677
        case SESSION_AVAILABLE:
3678
            return true;
3679
            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...
3680
        case SESSION_INVISIBLE:
3681
            return false;
3682
    }
3683
3684
    return false;
3685
}
3686
3687
/**
3688
 * Checks if a student can edit contents in a session depending
3689
 * on the session visibility.
3690
 *
3691
 * @param bool $tutor Whether to check if the user has the tutor role
3692
 * @param bool $coach Whether to check if the user has the coach role
3693
 *
3694
 * @return bool true: the user has the rights to edit, false: he does not
3695
 */
3696
function api_is_allowed_to_session_edit($tutor = false, $coach = false)
3697
{
3698
    if (api_is_allowed_to_edit($tutor, $coach)) {
3699
        // If I'm a teacher, I will return true in order to not affect the normal behaviour of Chamilo tools.
3700
        return true;
3701
    } else {
3702
        $sessionId = api_get_session_id();
3703
3704
        if (0 == $sessionId) {
3705
            // I'm not in a session so i will return true to not affect the normal behaviour of Chamilo tools.
3706
            return true;
3707
        } else {
3708
            // I'm in a session and I'm a student
3709
            // Get the session visibility
3710
            $session_visibility = api_get_session_visibility($sessionId);
3711
            // if 5 the session is still available
3712
            switch ($session_visibility) {
3713
                case SESSION_VISIBLE_READ_ONLY: // 1
3714
                    return false;
3715
                case SESSION_VISIBLE:           // 2
3716
                    return true;
3717
                case SESSION_INVISIBLE:         // 3
3718
                    return false;
3719
                case SESSION_AVAILABLE:         //5
3720
                    return true;
3721
            }
3722
        }
3723
    }
3724
3725
    return false;
3726
}
3727
3728
/**
3729
 * Checks whether the user is allowed in a specific tool for a specific action.
3730
 *
3731
 * @param string $tool   the tool we are checking if the user has a certain permission
3732
 * @param string $action the action we are checking (add, edit, delete, move, visibility)
3733
 *
3734
 * @return bool
3735
 *
3736
 * @author Patrick Cool <[email protected]>, Ghent University
3737
 * @author Julio Montoya
3738
 *
3739
 * @version 1.0
3740
 */
3741
function api_is_allowed($tool, $action, $task_id = 0)
3742
{
3743
    $_user = api_get_user_info();
3744
    $_course = api_get_course_info();
3745
3746
    if (api_is_course_admin()) {
3747
        return true;
3748
    }
3749
3750
    if (is_array($_course) and count($_course) > 0) {
3751
        require_once api_get_path(SYS_CODE_PATH).'permissions/permissions_functions.inc.php';
3752
3753
        // Getting the permissions of this user.
3754
        if (0 == $task_id) {
3755
            $user_permissions = get_permissions('user', $_user['user_id']);
3756
            $_SESSION['total_permissions'][$_course['code']] = $user_permissions;
3757
        }
3758
3759
        // Getting the permissions of the task.
3760
        if (0 != $task_id) {
3761
            $task_permissions = get_permissions('task', $task_id);
3762
            /* !!! */$_SESSION['total_permissions'][$_course['code']] = $task_permissions;
3763
        }
3764
    }
3765
3766
    // If the permissions are limited, we have to map the extended ones to the limited ones.
3767
    if ('limited' == api_get_setting('permissions')) {
3768
        if ('Visibility' == $action) {
3769
            $action = 'Edit';
3770
        }
3771
        if ('Move' == $action) {
3772
            $action = 'Edit';
3773
        }
3774
    }
3775
3776
    // The session that contains all the permissions already exists for this course
3777
    // so there is no need to requery everything.
3778
    //my_print_r($_SESSION['total_permissions'][$_course['code']][$tool]);
3779
    if (is_array($_SESSION['total_permissions'][$_course['code']][$tool])) {
3780
        if (in_array($action, $_SESSION['total_permissions'][$_course['code']][$tool])) {
3781
            return true;
3782
        } else {
3783
            return false;
3784
        }
3785
    }
3786
3787
    return false;
3788
}
3789
3790
/**
3791
 * Tells whether this user is an anonymous user.
3792
 *
3793
 * @param int  $user_id  User ID (optional, will take session ID if not provided)
3794
 * @param bool $db_check Whether to check in the database (true) or simply in
3795
 *                       the session (false) to see if the current user is the anonymous user
3796
 *
3797
 * @return bool true if this user is anonymous, false otherwise
3798
 */
3799
function api_is_anonymous($user_id = null, $db_check = false)
3800
{
3801
    /*if ($db_check) {
3802
        if (!isset($user_id)) {
3803
            $user_id = api_get_user_id();
3804
        }
3805
3806
        $info = api_get_user_info($user_id);
3807
3808
        if (6 == $info['status'] || 0 == $user_id || empty($info)) {
3809
            return true;
3810
        }
3811
    }*/
3812
3813
    return !Container::getAuthorizationChecker()->isGranted('IS_AUTHENTICATED_FULLY');
3814
}
3815
3816
/**
3817
 * Displays message "You are not allowed here..." and exits the entire script.
3818
 *
3819
 * @param bool   $print_headers Whether or not to print headers (default = false -> does not print them)
3820
 * @param string $message
3821
 * @param int    $responseCode
3822
 */
3823
function api_not_allowed(
3824
    $print_headers = false,
3825
    $message = null,
3826
    $responseCode = 0
3827
) {
3828
    throw new Exception('You are not allowed');
3829
}
3830
3831
/**
3832
 * Gets a UNIX timestamp from a database (MySQL) datetime format string.
3833
 *
3834
 * @param $last_post_datetime standard output date in a sql query
3835
 *
3836
 * @return int timestamp
3837
 *
3838
 * @author Toon Van Hoecke <[email protected]>
3839
 *
3840
 * @version October 2003
3841
 * @desc convert sql date to unix timestamp
3842
 */
3843
function convert_sql_date($last_post_datetime)
3844
{
3845
    [$last_post_date, $last_post_time] = explode(' ', $last_post_datetime);
3846
    [$year, $month, $day] = explode('-', $last_post_date);
3847
    [$hour, $min, $sec] = explode(':', $last_post_time);
3848
3849
    return mktime((int) $hour, (int) $min, (int) $sec, (int) $month, (int) $day, (int) $year);
3850
}
3851
3852
/**
3853
 * Delete a row in the c_item_property table.
3854
 *
3855
 * @param array  $courseInfo
3856
 * @param string $tool
3857
 * @param int    $itemId
3858
 * @param int    $userId
3859
 * @param int    $groupId    group.iid
3860
 * @param int    $sessionId
3861
 *
3862
 * @return false|null
3863
 */
3864
function api_item_property_delete(
3865
    $courseInfo,
3866
    $tool,
3867
    $itemId,
3868
    $userId,
3869
    $groupId = 0,
3870
    $sessionId = 0
3871
) {
3872
    if (empty($courseInfo)) {
3873
        return false;
3874
    }
3875
3876
    $courseId = (int) $courseInfo['real_id'];
3877
3878
    if (empty($courseId) || empty($tool) || empty($itemId)) {
3879
        return false;
3880
    }
3881
3882
    $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
3883
    $tool = Database::escape_string($tool);
3884
    $itemId = intval($itemId);
3885
    $userId = intval($userId);
3886
    $groupId = intval($groupId);
3887
    $sessionId = intval($sessionId);
3888
3889
    $groupCondition = " AND to_group_id = $groupId ";
3890
    if (empty($groupId)) {
3891
        $groupCondition = " AND (to_group_id is NULL OR to_group_id = 0) ";
3892
    }
3893
3894
    $userCondition = " AND to_user_id = $userId ";
3895
    if (empty($userId)) {
3896
        $userCondition = " AND (to_user_id is NULL OR to_user_id = 0) ";
3897
    }
3898
    $sessionCondition = api_get_session_condition($sessionId, true, false, 'session_id');
3899
    $sql = "DELETE FROM $table
3900
            WHERE
3901
                c_id = $courseId AND
3902
                tool  = '$tool' AND
3903
                ref = $itemId
3904
                $sessionCondition
3905
                $userCondition
3906
                $groupCondition
3907
            ";
3908
3909
    Database::query($sql);
3910
}
3911
3912
/**
3913
 * Gets item property by tool.
3914
 *
3915
 * @param string    course code
3916
 * @param string    tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
3917
 * @param int       id of the item itself, linked to key of every tool ('id', ...), "*" = all items of the tool
3918
 * @param int    $session_id
3919
 * @param string $tool
3920
 * @param string $course_code
3921
 *
3922
 * @return array All fields from c_item_property (all rows found) or empty array
3923
 */
3924
function api_get_item_property_by_tool($tool, $course_code, $session_id = null)
3925
{
3926
    $course_info = api_get_course_info($course_code);
3927
    $tool = Database::escape_string($tool);
3928
3929
    // Definition of tables.
3930
    $item_property_table = Database::get_course_table(TABLE_ITEM_PROPERTY);
3931
    $session_id = (int) $session_id;
3932
    $session_condition = ' AND session_id = '.$session_id;
3933
    if (empty($session_id)) {
3934
        $session_condition = " AND (session_id = 0 OR session_id IS NULL) ";
3935
    }
3936
    $course_id = $course_info['real_id'];
3937
3938
    $sql = "SELECT * FROM $item_property_table
3939
            WHERE
3940
                c_id = $course_id AND
3941
                tool = '$tool'
3942
                $session_condition ";
3943
    $rs = Database::query($sql);
3944
    $list = [];
3945
    if (Database::num_rows($rs) > 0) {
3946
        while ($row = Database::fetch_array($rs, 'ASSOC')) {
3947
            $list[] = $row;
3948
        }
3949
    }
3950
3951
    return $list;
3952
}
3953
3954
/**
3955
 * Gets item property by tool and user.
3956
 *
3957
 * @param int $userId
3958
 * @param int $tool
3959
 * @param int $courseId
3960
 * @param int $session_id
3961
 *
3962
 * @return array
3963
 */
3964
function api_get_item_property_list_by_tool_by_user(
3965
    $userId,
3966
    $tool,
3967
    $courseId,
3968
    $session_id = 0
3969
) {
3970
    $userId = intval($userId);
3971
    $tool = Database::escape_string($tool);
3972
    $session_id = intval($session_id);
3973
    $courseId = intval($courseId);
3974
3975
    // Definition of tables.
3976
    $item_property_table = Database::get_course_table(TABLE_ITEM_PROPERTY);
3977
    $session_condition = ' AND session_id = '.$session_id;
3978
    if (empty($session_id)) {
3979
        $session_condition = " AND (session_id = 0 OR session_id IS NULL) ";
3980
    }
3981
    $sql = "SELECT * FROM $item_property_table
3982
            WHERE
3983
                insert_user_id = $userId AND
3984
                c_id = $courseId AND
3985
                tool = '$tool'
3986
                $session_condition ";
3987
3988
    $rs = Database::query($sql);
3989
    $list = [];
3990
    if (Database::num_rows($rs) > 0) {
3991
        while ($row = Database::fetch_array($rs, 'ASSOC')) {
3992
            $list[] = $row;
3993
        }
3994
    }
3995
3996
    return $list;
3997
}
3998
3999
/**
4000
 * Gets item property id from tool of a course.
4001
 *
4002
 * @param string $course_code course code
4003
 * @param string $tool        tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4004
 * @param int    $ref         id of the item itself, linked to key of every tool ('id', ...), "*" = all items of the tool
4005
 * @param int    $sessionId   Session ID (optional)
4006
 *
4007
 * @return int
4008
 */
4009
function api_get_item_property_id($course_code, $tool, $ref, $sessionId = 0)
4010
{
4011
    $course_info = api_get_course_info($course_code);
4012
    $tool = Database::escape_string($tool);
4013
    $ref = (int) $ref;
4014
4015
    // Definition of tables.
4016
    $tableItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
4017
    $course_id = $course_info['real_id'];
4018
    $sessionId = (int) $sessionId;
4019
    $sessionCondition = " AND session_id = $sessionId ";
4020
    if (empty($sessionId)) {
4021
        $sessionCondition = ' AND (session_id = 0 OR session_id IS NULL) ';
4022
    }
4023
    $sql = "SELECT id FROM $tableItemProperty
4024
            WHERE
4025
                c_id = $course_id AND
4026
                tool = '$tool' AND
4027
                ref = $ref
4028
                $sessionCondition";
4029
    $rs = Database::query($sql);
4030
    $item_property_id = '';
4031
    if (Database::num_rows($rs) > 0) {
4032
        $row = Database::fetch_array($rs);
4033
        $item_property_id = $row['id'];
4034
    }
4035
4036
    return $item_property_id;
4037
}
4038
4039
/**
4040
 * Inserts a record in the track_e_item_property table (No update).
4041
 *
4042
 * @param string $tool
4043
 * @param int    $ref
4044
 * @param string $title
4045
 * @param string $content
4046
 * @param int    $progress
4047
 *
4048
 * @return bool|int
4049
 */
4050
function api_track_item_property_update($tool, $ref, $title, $content, $progress)
4051
{
4052
    $tbl_stats_item_property = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ITEM_PROPERTY);
4053
    $course_id = api_get_course_int_id(); //numeric
4054
    $course_code = api_get_course_id(); //alphanumeric
4055
    $item_property_id = api_get_item_property_id($course_code, $tool, $ref);
4056
    if (!empty($item_property_id)) {
4057
        $sql = "INSERT IGNORE INTO $tbl_stats_item_property SET
4058
                course_id           = '$course_id',
4059
                item_property_id    = '$item_property_id',
4060
                title               = '".Database::escape_string($title)."',
4061
                content             = '".Database::escape_string($content)."',
4062
                progress            = '".intval($progress)."',
4063
                lastedit_date       = '".api_get_utc_datetime()."',
4064
                lastedit_user_id    = '".api_get_user_id()."',
4065
                session_id          = '".api_get_session_id()."'";
4066
        $result = Database::query($sql);
4067
        $affected_rows = Database::affected_rows($result);
4068
4069
        return $affected_rows;
4070
    }
4071
4072
    return false;
4073
}
4074
4075
/**
4076
 * @param string $tool
4077
 * @param int    $ref
4078
 *
4079
 * @return array|resource
4080
 */
4081
function api_get_track_item_property_history($tool, $ref)
4082
{
4083
    $tbl_stats_item_property = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ITEM_PROPERTY);
4084
    $course_id = api_get_course_int_id(); //numeric
4085
    $course_code = api_get_course_id(); //alphanumeric
4086
    $item_property_id = api_get_item_property_id($course_code, $tool, $ref);
4087
    $sql = "SELECT * FROM $tbl_stats_item_property
4088
            WHERE item_property_id = $item_property_id AND course_id = $course_id
4089
            ORDER BY lastedit_date DESC";
4090
    $result = Database::query($sql);
4091
    if (false === $result or null === $result) {
4092
        $result = [];
4093
    } else {
4094
        $result = Database::store_result($result, 'ASSOC');
4095
    }
4096
4097
    return $result;
4098
}
4099
4100
/**
4101
 * Gets item property data from tool of a course id.
4102
 *
4103
 * @deprecated
4104
 *
4105
 * @param int    $course_id
4106
 * @param string $tool       tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4107
 * @param int    $ref        id of the item itself, linked to key of every tool ('id', ...), "*" = all items of the tool
4108
 * @param int    $session_id
4109
 * @param int    $groupId
4110
 *
4111
 * @return array with all fields from c_item_property, empty array if not found or false if course could not be found
4112
 */
4113
function api_get_item_property_info($course_id, $tool, $ref, $session_id = 0, $groupId = 0)
4114
{
4115
    $courseInfo = api_get_course_info_by_id($course_id);
4116
4117
    if (empty($courseInfo)) {
4118
        return false;
4119
    }
4120
4121
    $tool = Database::escape_string($tool);
4122
    $course_id = $courseInfo['real_id'];
4123
    $ref = (int) $ref;
4124
    $session_id = (int) $session_id;
4125
4126
    $sessionCondition = " session_id = $session_id";
4127
    if (empty($session_id)) {
4128
        $sessionCondition = ' (session_id = 0 OR session_id IS NULL) ';
4129
    }
4130
4131
    // Definition of tables.
4132
    $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4133
4134
    $sql = "SELECT * FROM $table
4135
            WHERE
4136
                c_id = $course_id AND
4137
                tool = '$tool' AND
4138
                ref = $ref AND
4139
                $sessionCondition ";
4140
4141
    if (!empty($groupId)) {
4142
        $groupId = (int) $groupId;
4143
        $sql .= " AND to_group_id = $groupId ";
4144
    }
4145
4146
    $rs = Database::query($sql);
4147
    $row = [];
4148
    if (Database::num_rows($rs) > 0) {
4149
        $row = Database::fetch_array($rs, 'ASSOC');
4150
    }
4151
4152
    return $row;
4153
}
4154
4155
/**
4156
 * Displays a combo box so the user can select his/her preferred language.
4157
 *
4158
 * @param string The desired name= value for the select
4159
 * @param bool Whether we use the JQuery Chozen library or not
4160
 * (in some cases, like the indexing language picker, it can alter the presentation)
4161
 *
4162
 * @deprecated
4163
 *
4164
 * @return string
4165
 */
4166
function api_get_languages_combo($name = 'language')
4167
{
4168
    $ret = '';
4169
    $platformLanguage = api_get_setting('platformLanguage');
4170
4171
    // Retrieve a complete list of all the languages.
4172
    $language_list = api_get_languages();
4173
4174
    if (count($language_list) < 2) {
4175
        return $ret;
4176
    }
4177
4178
    // The the current language of the user so that his/her language occurs as selected in the dropdown menu.
4179
    if (isset($_SESSION['user_language_choice'])) {
4180
        $default = $_SESSION['user_language_choice'];
4181
    } else {
4182
        $default = $platformLanguage;
4183
    }
4184
4185
    $ret .= '<select name="'.$name.'" id="language_chosen" class="selectpicker show-tick form-control">';
4186
    foreach ($language_list as $key => $value) {
4187
        if ($key == $default) {
4188
            $selected = ' selected="selected"';
4189
        } else {
4190
            $selected = '';
4191
        }
4192
        $ret .= sprintf('<option value=%s" %s>%s</option>', $key, $selected, $value);
4193
    }
4194
    $ret .= '</select>';
4195
4196
    return $ret;
4197
}
4198
4199
/**
4200
 * Displays a form (drop down menu) so the user can select his/her preferred language.
4201
 * The form works with or without javascript.
4202
 *
4203
 * @param  bool Hide form if only one language available (defaults to false = show the box anyway)
4204
 * @param bool $showAsButton
4205
 *
4206
 * @return string|null Display the box directly
4207
 */
4208
function api_display_language_form($hide_if_no_choice = false, $showAsButton = false)
4209
{
4210
    // Retrieve a complete list of all the languages.
4211
    $language_list = api_get_languages();
4212
    if (count($language_list['name']) <= 1 && $hide_if_no_choice) {
4213
        return; //don't show any form
4214
    }
4215
4216
    // The the current language of the user so that his/her language occurs as selected in the dropdown menu.
4217
    if (isset($_SESSION['user_language_choice'])) {
4218
        $user_selected_language = $_SESSION['user_language_choice'];
4219
    }
4220
    if (empty($user_selected_language)) {
4221
        $user_selected_language = api_get_setting('platformLanguage');
4222
    }
4223
4224
    $currentLanguageId = api_get_language_id($user_selected_language);
4225
    $currentLanguageInfo = api_get_language_info($currentLanguageId);
4226
    $countryCode = languageToCountryIsoCode($currentLanguageInfo['isocode']);
4227
    $url = api_get_self();
4228
    if ($showAsButton) {
4229
        $html = '<div class="btn-group">
4230
              <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
4231
                <span class="flag-icon flag-icon-'.$countryCode.'"></span>
4232
                '.$currentLanguageInfo['original_name'].'
4233
                <span class="caret">
4234
                </span>
4235
              </button>';
4236
    } else {
4237
        $html = '
4238
            <a href="'.$url.'" class="dropdown-toggle" data-toggle="dropdown" role="button">
4239
                <span class="flag-icon flag-icon-'.$countryCode.'"></span>
4240
                '.$currentLanguageInfo['original_name'].'
4241
                <span class="caret"></span>
4242
            </a>
4243
            ';
4244
    }
4245
4246
    $html .= '<ul class="dropdown-menu" role="menu">';
4247
    foreach ($language_list['all'] as $key => $data) {
4248
        $urlLink = $url.'?language='.$data['english_name'];
4249
        $html .= '<li><a href="'.$urlLink.'"><span class="flag-icon flag-icon-'.languageToCountryIsoCode($data['isocode']).'"></span> '.$data['original_name'].'</a></li>';
4250
    }
4251
    $html .= '</ul>';
4252
4253
    if ($showAsButton) {
4254
        $html .= '</div>';
4255
    }
4256
4257
    return $html;
4258
}
4259
4260
/**
4261
 * @param string $languageIsoCode
4262
 *
4263
 * @return string
4264
 */
4265
function languageToCountryIsoCode($languageIsoCode)
4266
{
4267
    $allow = api_get_configuration_value('language_flags_by_country');
4268
4269
    // @todo save in DB
4270
    switch ($languageIsoCode) {
4271
        case 'ar':
4272
            $country = 'ae';
4273
            break;
4274
        case 'bs':
4275
            $country = 'ba';
4276
            break;
4277
        case 'ca':
4278
            $country = 'es';
4279
            if ($allow) {
4280
                $country = 'catalan';
4281
            }
4282
            break;
4283
        case 'cs':
4284
            $country = 'cz';
4285
            break;
4286
        case 'da':
4287
            $country = 'dk';
4288
            break;
4289
        case 'el':
4290
            $country = 'ae';
4291
            break;
4292
        case 'en':
4293
            $country = 'gb';
4294
            break;
4295
        case 'eu': // Euskera
4296
            $country = 'es';
4297
            if ($allow) {
4298
                $country = 'basque';
4299
            }
4300
            break;
4301
        case 'gl': // galego
4302
            $country = 'es';
4303
            if ($allow) {
4304
                $country = 'galician';
4305
            }
4306
            break;
4307
        case 'he':
4308
            $country = 'il';
4309
            break;
4310
        case 'ja':
4311
            $country = 'jp';
4312
            break;
4313
        case 'ka':
4314
            $country = 'ge';
4315
            break;
4316
        case 'ko':
4317
            $country = 'kr';
4318
            break;
4319
        case 'ms':
4320
            $country = 'my';
4321
            break;
4322
        case 'pt-BR':
4323
            $country = 'br';
4324
            break;
4325
        case 'qu':
4326
            $country = 'pe';
4327
            break;
4328
        case 'sl':
4329
            $country = 'si';
4330
            break;
4331
        case 'sv':
4332
            $country = 'se';
4333
            break;
4334
        case 'uk': // Ukraine
4335
            $country = 'ua';
4336
            break;
4337
        case 'zh-TW':
4338
        case 'zh':
4339
            $country = 'cn';
4340
            break;
4341
        default:
4342
            $country = $languageIsoCode;
4343
            break;
4344
    }
4345
    $country = strtolower($country);
4346
4347
    return $country;
4348
}
4349
4350
/**
4351
 * Returns a list of all the languages that are made available by the admin.
4352
 *
4353
 * @return array An array with all languages. Structure of the array is
4354
 *               array['name'] = An array with the name of every language
4355
 *               array['folder'] = An array with the corresponding names of the language-folders in the filesystem
4356
 */
4357
function api_get_languages()
4358
{
4359
    $table = Database::get_main_table(TABLE_MAIN_LANGUAGE);
4360
    $sql = "SELECT * FROM $table WHERE available='1'
4361
            ORDER BY original_name ASC";
4362
    $result = Database::query($sql);
4363
    $languages = [];
4364
    while ($row = Database::fetch_array($result, 'ASSOC')) {
4365
        $languages[$row['isocode']] = $row['original_name'];
4366
    }
4367
4368
    return $languages;
4369
}
4370
4371
/**
4372
 * Returns a list of all the languages that are made available by the admin.
4373
 *
4374
 * @return array
4375
 */
4376
function api_get_languages_to_array()
4377
{
4378
    $tbl_language = Database::get_main_table(TABLE_MAIN_LANGUAGE);
4379
    $sql = "SELECT * FROM $tbl_language WHERE available='1' ORDER BY original_name ASC";
4380
    $result = Database::query($sql);
4381
    $languages = [];
4382
    while ($row = Database::fetch_array($result)) {
4383
        $languages[$row['dokeos_folder']] = $row['original_name'];
4384
    }
4385
4386
    return $languages;
4387
}
4388
4389
/**
4390
 * Returns the id (the database id) of a language.
4391
 *
4392
 * @param   string  language name (the corresponding name of the language-folder in the filesystem)
4393
 *
4394
 * @return int id of the language
4395
 */
4396
function api_get_language_id($language)
4397
{
4398
    $tbl_language = Database::get_main_table(TABLE_MAIN_LANGUAGE);
4399
    if (empty($language)) {
4400
        return null;
4401
    }
4402
    $language = Database::escape_string($language);
4403
    $sql = "SELECT id FROM $tbl_language
4404
            WHERE dokeos_folder = '$language' LIMIT 1";
4405
    $result = Database::query($sql);
4406
    $row = Database::fetch_array($result);
4407
4408
    return $row['id'];
4409
}
4410
4411
/**
4412
 * Get the language information by its id.
4413
 *
4414
 * @param int $languageId
4415
 *
4416
 * @throws Exception
4417
 *
4418
 * @return array
4419
 */
4420
function api_get_language_info($languageId)
4421
{
4422
    if (empty($languageId)) {
4423
        return [];
4424
    }
4425
4426
    $language = Database::getManager()->find(Language::class, $languageId);
4427
4428
    if (!$language) {
4429
        return [];
4430
    }
4431
4432
    return [
4433
        'id' => $language->getId(),
4434
        'original_name' => $language->getOriginalName(),
4435
        'english_name' => $language->getEnglishName(),
4436
        'isocode' => $language->getIsocode(),
4437
        'dokeos_folder' => $language->getDokeosFolder(),
4438
        'available' => $language->getAvailable(),
4439
        'parent_id' => $language->getParent() ? $language->getParent()->getId() : null,
4440
    ];
4441
}
4442
4443
/**
4444
 * @param string $code
4445
 *
4446
 * @return Language
4447
 */
4448
function api_get_language_from_iso($code)
4449
{
4450
    $em = Database::getManager();
4451
4452
    return $em->getRepository(Language::class)->findOneBy(['isocode' => $code]);
4453
}
4454
4455
/**
4456
 * Returns the name of the visual (CSS) theme to be applied on the current page.
4457
 * The returned name depends on the platform, course or user -wide settings.
4458
 *
4459
 * @return string The visual theme's name, it is the name of a folder inside web/css/themes
4460
 */
4461
function api_get_visual_theme()
4462
{
4463
    static $visual_theme;
4464
    if (!isset($visual_theme)) {
4465
        // Get style directly from DB
4466
        /*$styleFromDatabase = api_get_settings_params_simple(
4467
            [
4468
                'variable = ? AND access_url = ?' => [
4469
                    'stylesheets',
4470
                    api_get_current_access_url_id(),
4471
                ],
4472
            ]
4473
        );
4474
4475
        if ($styleFromDatabase) {
4476
            $platform_theme = $styleFromDatabase['selected_value'];
4477
        } else {
4478
            $platform_theme = api_get_setting('stylesheets');
4479
        }*/
4480
        $platform_theme = api_get_setting('stylesheets');
4481
4482
        // Platform's theme.
4483
        $visual_theme = $platform_theme;
4484
        if ('true' == api_get_setting('user_selected_theme')) {
4485
            $user_info = api_get_user_info();
4486
            if (isset($user_info['theme'])) {
4487
                $user_theme = $user_info['theme'];
4488
4489
                if (!empty($user_theme)) {
4490
                    $visual_theme = $user_theme;
4491
                    // User's theme.
4492
                }
4493
            }
4494
        }
4495
4496
        $course_id = api_get_course_id();
4497
        if (!empty($course_id)) {
4498
            if ('true' == api_get_setting('allow_course_theme')) {
4499
                $course_theme = api_get_course_setting('course_theme', $course_id);
4500
4501
                if (!empty($course_theme) && -1 != $course_theme) {
4502
                    if (!empty($course_theme)) {
4503
                        // Course's theme.
4504
                        $visual_theme = $course_theme;
4505
                    }
4506
                }
4507
4508
                $allow_lp_theme = api_get_course_setting('allow_learning_path_theme');
4509
                if (1 == $allow_lp_theme) {
4510
                    /*global $lp_theme_css, $lp_theme_config;
4511
                    // These variables come from the file lp_controller.php.
4512
                    if (!$lp_theme_config) {
4513
                        if (!empty($lp_theme_css)) {
4514
                            // LP's theme.
4515
                            $visual_theme = $lp_theme_css;
4516
                        }
4517
                    }*/
4518
                }
4519
            }
4520
        }
4521
4522
        if (empty($visual_theme)) {
4523
            $visual_theme = 'chamilo';
4524
        }
4525
4526
        /*global $lp_theme_log;
4527
        if ($lp_theme_log) {
4528
            $visual_theme = $platform_theme;
4529
        }*/
4530
    }
4531
4532
    return $visual_theme;
4533
}
4534
4535
/**
4536
 * Returns a list of CSS themes currently available in the CSS folder
4537
 * The folder must have a default.css file.
4538
 *
4539
 * @param bool $getOnlyThemeFromVirtualInstance Used by the vchamilo plugin
4540
 *
4541
 * @return array list of themes directories from the css folder
4542
 *               Note: Directory names (names of themes) in the file system should contain ASCII-characters only
4543
 */
4544
function api_get_themes($getOnlyThemeFromVirtualInstance = false)
4545
{
4546
    // This configuration value is set by the vchamilo plugin
4547
    $virtualTheme = api_get_configuration_value('virtual_css_theme_folder');
4548
4549
    $readCssFolder = function ($dir) use ($virtualTheme) {
4550
        $finder = new Finder();
4551
        $themes = $finder->directories()->in($dir)->depth(0)->sortByName();
4552
        $list = [];
4553
        /** @var Symfony\Component\Finder\SplFileInfo $theme */
4554
        foreach ($themes as $theme) {
4555
            $folder = $theme->getFilename();
4556
            // A theme folder is consider if there's a default.css file
4557
            if (!file_exists($theme->getPathname().'/default.css')) {
4558
                continue;
4559
            }
4560
            $name = ucwords(str_replace('_', ' ', $folder));
4561
            if ($folder == $virtualTheme) {
4562
                continue;
4563
            }
4564
            $list[$folder] = $name;
4565
        }
4566
4567
        return $list;
4568
    };
4569
4570
    $dir = api_get_path(SYS_CSS_PATH).'themes/';
4571
    $list = $readCssFolder($dir);
4572
4573
    if (!empty($virtualTheme)) {
4574
        $newList = $readCssFolder($dir.'/'.$virtualTheme);
4575
        if ($getOnlyThemeFromVirtualInstance) {
4576
            return $newList;
4577
        }
4578
        $list = $list + $newList;
4579
        asort($list);
4580
    }
4581
4582
    return $list;
4583
}
4584
4585
/**
4586
 * Find the largest sort value in a given user_course_category
4587
 * This function is used when we are moving a course to a different category
4588
 * and also when a user subscribes to courses (the new course is added at the end of the main category.
4589
 *
4590
 * @author Patrick Cool <[email protected]>, Ghent University
4591
 *
4592
 * @param int $user_course_category the id of the user_course_category
4593
 * @param int $user_id
4594
 *
4595
 * @return int the value of the highest sort of the user_course_category
4596
 */
4597
function api_max_sort_value($user_course_category, $user_id)
4598
{
4599
    $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4600
    $sql = "SELECT max(sort) as max_sort FROM $tbl_course_user
4601
            WHERE
4602
                user_id='".intval($user_id)."' AND
4603
                relation_type<>".COURSE_RELATION_TYPE_RRHH." AND
4604
                user_course_cat='".intval($user_course_category)."'";
4605
    $result_max = Database::query($sql);
4606
    if (1 == Database::num_rows($result_max)) {
4607
        $row_max = Database::fetch_array($result_max);
4608
4609
        return $row_max['max_sort'];
4610
    }
4611
4612
    return 0;
4613
}
4614
4615
/**
4616
 * Transforms a number of seconds in hh:mm:ss format.
4617
 *
4618
 * @author Julian Prud'homme
4619
 *
4620
 * @param int    $seconds      number of seconds
4621
 * @param string $space
4622
 * @param bool   $showSeconds
4623
 * @param bool   $roundMinutes
4624
 *
4625
 * @return string the formatted time
4626
 */
4627
function api_time_to_hms($seconds, $space = ':', $showSeconds = true, $roundMinutes = false)
4628
{
4629
    // $seconds = -1 means that we have wrong data in the db.
4630
    if (-1 == $seconds) {
4631
        return
4632
            get_lang('Unknown').
4633
            Display::return_icon(
4634
                'info2.gif',
4635
                get_lang('The datas about this user were registered when the calculation of time spent on the platform wasn\'t possible.'),
4636
                ['align' => 'absmiddle', 'hspace' => '3px']
4637
            );
4638
    }
4639
4640
    // How many hours ?
4641
    $hours = floor($seconds / 3600);
4642
4643
    // How many minutes ?
4644
    $min = floor(($seconds - ($hours * 3600)) / 60);
4645
4646
    if ($roundMinutes) {
4647
        if ($min >= 45) {
4648
            $min = 45;
4649
        }
4650
4651
        if ($min >= 30 && $min <= 44) {
4652
            $min = 30;
4653
        }
4654
4655
        if ($min >= 15 && $min <= 29) {
4656
            $min = 15;
4657
        }
4658
4659
        if ($min >= 0 && $min <= 14) {
4660
            $min = 0;
4661
        }
4662
    }
4663
4664
    // How many seconds
4665
    $sec = floor($seconds - ($hours * 3600) - ($min * 60));
4666
4667
    if ($hours < 10) {
4668
        $hours = "0$hours";
4669
    }
4670
4671
    if ($sec < 10) {
4672
        $sec = "0$sec";
4673
    }
4674
4675
    if ($min < 10) {
4676
        $min = "0$min";
4677
    }
4678
4679
    $seconds = '';
4680
    if ($showSeconds) {
4681
        $seconds = $space.$sec;
4682
    }
4683
4684
    return $hours.$space.$min.$seconds;
4685
}
4686
4687
/* FILE SYSTEM RELATED FUNCTIONS */
4688
4689
/**
4690
 * Returns the permissions to be assigned to every newly created directory by the web-server.
4691
 * The return value is based on the platform administrator's setting
4692
 * "Administration > Configuration settings > Security > Permissions for new directories".
4693
 *
4694
 * @return int returns the permissions in the format "Owner-Group-Others, Read-Write-Execute", as an integer value
4695
 */
4696
function api_get_permissions_for_new_directories()
4697
{
4698
    static $permissions;
4699
    if (!isset($permissions)) {
4700
        $permissions = trim(api_get_setting('permissions_for_new_directories'));
4701
        // The default value 0777 is according to that in the platform administration panel after fresh system installation.
4702
        $permissions = octdec(!empty($permissions) ? $permissions : '0777');
4703
    }
4704
4705
    return $permissions;
4706
}
4707
4708
/**
4709
 * Returns the permissions to be assigned to every newly created directory by the web-server.
4710
 * The return value is based on the platform administrator's setting
4711
 * "Administration > Configuration settings > Security > Permissions for new files".
4712
 *
4713
 * @return int returns the permissions in the format
4714
 *             "Owner-Group-Others, Read-Write-Execute", as an integer value
4715
 */
4716
function api_get_permissions_for_new_files()
4717
{
4718
    static $permissions;
4719
    if (!isset($permissions)) {
4720
        $permissions = trim(api_get_setting('permissions_for_new_files'));
4721
        // The default value 0666 is according to that in the platform
4722
        // administration panel after fresh system installation.
4723
        $permissions = octdec(!empty($permissions) ? $permissions : '0666');
4724
    }
4725
4726
    return $permissions;
4727
}
4728
4729
/**
4730
 * Deletes a file, or a folder and its contents.
4731
 *
4732
 * @author      Aidan Lister <[email protected]>
4733
 *
4734
 * @version     1.0.3
4735
 *
4736
 * @param string $dirname Directory to delete
4737
 * @param       bool     Deletes only the content or not
4738
 * @param bool $strict if one folder/file fails stop the loop
4739
 *
4740
 * @return bool Returns TRUE on success, FALSE on failure
4741
 *
4742
 * @see http://aidanlister.com/2004/04/recursively-deleting-a-folder-in-php/
4743
 *
4744
 * @author      Yannick Warnier, adaptation for the Chamilo LMS, April, 2008
4745
 * @author      Ivan Tcholakov, a sanity check about Directory class creation has been added, September, 2009
4746
 */
4747
function rmdirr($dirname, $delete_only_content_in_folder = false, $strict = false)
4748
{
4749
    $res = true;
4750
    // A sanity check.
4751
    if (!file_exists($dirname)) {
4752
        return false;
4753
    }
4754
    $php_errormsg = '';
4755
    // Simple delete for a file.
4756
    if (is_file($dirname) || is_link($dirname)) {
4757
        $res = unlink($dirname);
4758
        if (false === $res) {
4759
            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);
4760
        }
4761
4762
        return $res;
4763
    }
4764
4765
    // Loop through the folder.
4766
    $dir = dir($dirname);
4767
    // A sanity check.
4768
    $is_object_dir = is_object($dir);
4769
    if ($is_object_dir) {
4770
        while (false !== $entry = $dir->read()) {
4771
            // Skip pointers.
4772
            if ('.' == $entry || '..' == $entry) {
4773
                continue;
4774
            }
4775
4776
            // Recurse.
4777
            if ($strict) {
4778
                $result = rmdirr("$dirname/$entry");
4779
                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...
4780
                    $res = false;
4781
                    break;
4782
                }
4783
            } else {
4784
                rmdirr("$dirname/$entry");
4785
            }
4786
        }
4787
    }
4788
4789
    // Clean up.
4790
    if ($is_object_dir) {
4791
        $dir->close();
4792
    }
4793
4794
    if (false == $delete_only_content_in_folder) {
4795
        $res = rmdir($dirname);
4796
        if (false === $res) {
4797
            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);
4798
        }
4799
    }
4800
4801
    return $res;
4802
}
4803
4804
// TODO: This function is to be simplified. File access modes to be implemented.
4805
/**
4806
 * function adapted from a php.net comment
4807
 * copy recursively a folder.
4808
 *
4809
 * @param the source folder
4810
 * @param the dest folder
4811
 * @param an array of excluded file_name (without extension)
4812
 * @param copied_files the returned array of copied files
4813
 * @param string $source
4814
 * @param string $dest
4815
 */
4816
function copyr($source, $dest, $exclude = [], $copied_files = [])
4817
{
4818
    if (empty($dest)) {
4819
        return false;
4820
    }
4821
    // Simple copy for a file
4822
    if (is_file($source)) {
4823
        $path_info = pathinfo($source);
4824
        if (!in_array($path_info['filename'], $exclude)) {
4825
            copy($source, $dest);
4826
        }
4827
4828
        return true;
4829
    } elseif (!is_dir($source)) {
4830
        //then source is not a dir nor a file, return
4831
        return false;
4832
    }
4833
4834
    // Make destination directory.
4835
    if (!is_dir($dest)) {
4836
        mkdir($dest, api_get_permissions_for_new_directories());
4837
    }
4838
4839
    // Loop through the folder.
4840
    $dir = dir($source);
4841
    while (false !== $entry = $dir->read()) {
4842
        // Skip pointers
4843
        if ('.' == $entry || '..' == $entry) {
4844
            continue;
4845
        }
4846
4847
        // Deep copy directories.
4848
        if ($dest !== "$source/$entry") {
4849
            $files = copyr("$source/$entry", "$dest/$entry", $exclude, $copied_files);
4850
        }
4851
    }
4852
    // Clean up.
4853
    $dir->close();
4854
4855
    return true;
4856
}
4857
4858
/**
4859
 * @todo: Using DIRECTORY_SEPARATOR is not recommended, this is an obsolete approach.
4860
 * Documentation header to be added here.
4861
 *
4862
 * @param string $pathname
4863
 * @param string $base_path_document
4864
 * @param int    $session_id
4865
 *
4866
 * @return mixed True if directory already exists, false if a file already exists at
4867
 *               the destination and null if everything goes according to plan
4868
 */
4869
function copy_folder_course_session(
4870
    $pathname,
4871
    $base_path_document,
4872
    $session_id,
4873
    $course_info,
4874
    $document,
4875
    $source_course_id
4876
) {
4877
    $table = Database::get_course_table(TABLE_DOCUMENT);
4878
    $session_id = intval($session_id);
4879
    $source_course_id = intval($source_course_id);
4880
4881
    // Check whether directory already exists.
4882
    if (is_dir($pathname) || empty($pathname)) {
4883
        return true;
4884
    }
4885
4886
    // Ensure that a file with the same name does not already exist.
4887
    if (is_file($pathname)) {
4888
        trigger_error('copy_folder_course_session(): File exists', E_USER_WARNING);
4889
4890
        return false;
4891
    }
4892
4893
    $course_id = $course_info['real_id'];
4894
    $folders = explode(DIRECTORY_SEPARATOR, str_replace($base_path_document.DIRECTORY_SEPARATOR, '', $pathname));
4895
    $new_pathname = $base_path_document;
4896
    $path = '';
4897
4898
    foreach ($folders as $folder) {
4899
        $new_pathname .= DIRECTORY_SEPARATOR.$folder;
4900
        $path .= DIRECTORY_SEPARATOR.$folder;
4901
4902
        if (!file_exists($new_pathname)) {
4903
            $path = Database::escape_string($path);
4904
4905
            $sql = "SELECT * FROM $table
4906
                    WHERE
4907
                        c_id = $source_course_id AND
4908
                        path = '$path' AND
4909
                        filetype = 'folder' AND
4910
                        session_id = '$session_id'";
4911
            $rs1 = Database::query($sql);
4912
            $num_rows = Database::num_rows($rs1);
4913
4914
            if (0 == $num_rows) {
4915
                mkdir($new_pathname, api_get_permissions_for_new_directories());
4916
4917
                // Insert new folder with destination session_id.
4918
                $params = [
4919
                    'c_id' => $course_id,
4920
                    'path' => $path,
4921
                    'comment' => $document->comment,
4922
                    'title' => basename($new_pathname),
4923
                    'filetype' => 'folder',
4924
                    'size' => '0',
4925
                    'session_id' => $session_id,
4926
                ];
4927
                $document_id = Database::insert($table, $params);
4928
                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...
4929
                    /*api_item_property_update(
4930
                        $course_info,
4931
                        TOOL_DOCUMENT,
4932
                        $document_id,
4933
                        'FolderCreated',
4934
                        api_get_user_id(),
4935
                        0,
4936
                        0,
4937
                        null,
4938
                        null,
4939
                        $session_id
4940
                    );*/
4941
                }
4942
            }
4943
        }
4944
    } // en foreach
4945
}
4946
4947
// TODO: chmodr() is a better name. Some corrections are needed. Documentation header to be added here.
4948
/**
4949
 * @param string $path
4950
 */
4951
function api_chmod_R($path, $filemode)
4952
{
4953
    if (!is_dir($path)) {
4954
        return chmod($path, $filemode);
4955
    }
4956
4957
    $handler = opendir($path);
4958
    while ($file = readdir($handler)) {
4959
        if ('.' != $file && '..' != $file) {
4960
            $fullpath = "$path/$file";
4961
            if (!is_dir($fullpath)) {
4962
                if (!chmod($fullpath, $filemode)) {
4963
                    return false;
4964
                }
4965
            } else {
4966
                if (!api_chmod_R($fullpath, $filemode)) {
4967
                    return false;
4968
                }
4969
            }
4970
        }
4971
    }
4972
4973
    closedir($handler);
4974
4975
    return chmod($path, $filemode);
4976
}
4977
4978
// TODO: Where the following function has been copy/pased from? There is no information about author and license. Style, coding conventions...
4979
/**
4980
 * Parse info file format. (e.g: file.info).
4981
 *
4982
 * Files should use an ini-like format to specify values.
4983
 * White-space generally doesn't matter, except inside values.
4984
 * e.g.
4985
 *
4986
 * @verbatim
4987
 *   key = value
4988
 *   key = "value"
4989
 *   key = 'value'
4990
 *   key = "multi-line
4991
 *
4992
 *   value"
4993
 *   key = 'multi-line
4994
 *
4995
 *   value'
4996
 *   key
4997
 *   =
4998
 *   'value'
4999
 * @endverbatim
5000
 *
5001
 * Arrays are created using a GET-like syntax:
5002
 *
5003
 * @verbatim
5004
 *   key[] = "numeric array"
5005
 *   key[index] = "associative array"
5006
 *   key[index][] = "nested numeric array"
5007
 *   key[index][index] = "nested associative array"
5008
 * @endverbatim
5009
 *
5010
 * PHP constants are substituted in, but only when used as the entire value:
5011
 *
5012
 * Comments should start with a semi-colon at the beginning of a line.
5013
 *
5014
 * This function is NOT for placing arbitrary module-specific settings. Use
5015
 * variable_get() and variable_set() for that.
5016
 *
5017
 * Information stored in the module.info file:
5018
 * - name: The real name of the module for display purposes.
5019
 * - description: A brief description of the module.
5020
 * - dependencies: An array of shortnames of other modules this module depends on.
5021
 * - package: The name of the package of modules this module belongs to.
5022
 *
5023
 * Example of .info file:
5024
 * <code>
5025
 * @verbatim
5026
 *   name = Forum
5027
 *   description = Enables threaded discussions about general topics.
5028
 *   dependencies[] = taxonomy
5029
 *   dependencies[] = comment
5030
 *   package = Core - optional
5031
 *   version = VERSION
5032
 * @endverbatim
5033
 * </code>
5034
 *
5035
 * @param string $filename
5036
 *                         The file we are parsing. Accepts file with relative or absolute path.
5037
 *
5038
 * @return
5039
 *   The info array
5040
 */
5041
function api_parse_info_file($filename)
5042
{
5043
    $info = [];
5044
5045
    if (!file_exists($filename)) {
5046
        return $info;
5047
    }
5048
5049
    $data = file_get_contents($filename);
5050
    if (preg_match_all('
5051
        @^\s*                           # Start at the beginning of a line, ignoring leading whitespace
5052
        ((?:
5053
          [^=;\[\]]|                    # Key names cannot contain equal signs, semi-colons or square brackets,
5054
          \[[^\[\]]*\]                  # unless they are balanced and not nested
5055
        )+?)
5056
        \s*=\s*                         # Key/value pairs are separated by equal signs (ignoring white-space)
5057
        (?:
5058
          ("(?:[^"]|(?<=\\\\)")*")|     # Double-quoted string, which may contain slash-escaped quotes/slashes
5059
          (\'(?:[^\']|(?<=\\\\)\')*\')| # Single-quoted string, which may contain slash-escaped quotes/slashes
5060
          ([^\r\n]*?)                   # Non-quoted string
5061
        )\s*$                           # Stop at the next end of a line, ignoring trailing whitespace
5062
        @msx', $data, $matches, PREG_SET_ORDER)) {
5063
        $key = $value1 = $value2 = $value3 = '';
5064
        foreach ($matches as $match) {
5065
            // Fetch the key and value string.
5066
            $i = 0;
5067
            foreach (['key', 'value1', 'value2', 'value3'] as $var) {
5068
                $$var = isset($match[++$i]) ? $match[$i] : '';
5069
            }
5070
            $value = stripslashes(substr($value1, 1, -1)).stripslashes(substr($value2, 1, -1)).$value3;
5071
5072
            // Parse array syntax.
5073
            $keys = preg_split('/\]?\[/', rtrim($key, ']'));
5074
            $last = array_pop($keys);
5075
            $parent = &$info;
5076
5077
            // Create nested arrays.
5078
            foreach ($keys as $key) {
5079
                if ('' == $key) {
5080
                    $key = count($parent);
5081
                }
5082
                if (!isset($parent[$key]) || !is_array($parent[$key])) {
5083
                    $parent[$key] = [];
5084
                }
5085
                $parent = &$parent[$key];
5086
            }
5087
5088
            // Handle PHP constants.
5089
            if (defined($value)) {
5090
                $value = constant($value);
5091
            }
5092
5093
            // Insert actual value.
5094
            if ('' == $last) {
5095
                $last = count($parent);
5096
            }
5097
            $parent[$last] = $value;
5098
        }
5099
    }
5100
5101
    return $info;
5102
}
5103
5104
/**
5105
 * Gets Chamilo version from the configuration files.
5106
 *
5107
 * @return string A string of type "1.8.4", or an empty string if the version could not be found
5108
 */
5109
function api_get_version()
5110
{
5111
    return (string) api_get_configuration_value('system_version');
5112
}
5113
5114
/**
5115
 * Gets the software name (the name/brand of the Chamilo-based customized system).
5116
 *
5117
 * @return string
5118
 */
5119
function api_get_software_name()
5120
{
5121
    $name = api_get_configuration_value('software_name');
5122
    if (!empty($name)) {
5123
        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...
5124
    } else {
5125
        return 'Chamilo';
5126
    }
5127
}
5128
5129
function api_get_status_list()
5130
{
5131
    $list = [];
5132
    // Table of status
5133
    $list[COURSEMANAGER] = 'teacher'; // 1
5134
    $list[SESSIONADMIN] = 'session_admin'; // 3
5135
    $list[DRH] = 'drh'; // 4
5136
    $list[STUDENT] = 'user'; // 5
5137
    $list[ANONYMOUS] = 'anonymous'; // 6
5138
    $list[INVITEE] = 'invited'; // 20
5139
5140
    return $list;
5141
}
5142
5143
/**
5144
 * Checks whether status given in parameter exists in the platform.
5145
 *
5146
 * @param mixed the status (can be either int either string)
5147
 *
5148
 * @return bool if the status exists, else returns false
5149
 */
5150
function api_status_exists($status_asked)
5151
{
5152
    $list = api_get_status_list();
5153
5154
    return in_array($status_asked, $list) ? true : isset($list[$status_asked]);
5155
}
5156
5157
/**
5158
 * Checks whether status given in parameter exists in the platform. The function
5159
 * returns the status ID or false if it does not exist, but given the fact there
5160
 * is no "0" status, the return value can be checked against
5161
 * if(api_status_key()) to know if it exists.
5162
 *
5163
 * @param   mixed   The status (can be either int or string)
5164
 *
5165
 * @return mixed Status ID if exists, false otherwise
5166
 */
5167
function api_status_key($status)
5168
{
5169
    $list = api_get_status_list();
5170
5171
    return isset($list[$status]) ? $status : array_search($status, $list);
5172
}
5173
5174
/**
5175
 * Gets the status langvars list.
5176
 *
5177
 * @return string[] the list of status with their translations
5178
 */
5179
function api_get_status_langvars()
5180
{
5181
    return [
5182
        COURSEMANAGER => get_lang('Teacher'),
5183
        SESSIONADMIN => get_lang('SessionsAdmin'),
5184
        DRH => get_lang('Human Resources Manager'),
5185
        STUDENT => get_lang('Learner'),
5186
        ANONYMOUS => get_lang('Anonymous'),
5187
        STUDENT_BOSS => get_lang('RoleStudentBoss'),
5188
        INVITEE => get_lang('Invited'),
5189
    ];
5190
}
5191
5192
/**
5193
 * The function that retrieves all the possible settings for a certain config setting.
5194
 *
5195
 * @author Patrick Cool <[email protected]>, Ghent University
5196
 */
5197
function api_get_settings_options($var)
5198
{
5199
    $table_settings_options = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
5200
    $var = Database::escape_string($var);
5201
    $sql = "SELECT * FROM $table_settings_options
5202
            WHERE variable = '$var'
5203
            ORDER BY id";
5204
    $result = Database::query($sql);
5205
    $settings_options_array = [];
5206
    while ($row = Database::fetch_array($result, 'ASSOC')) {
5207
        $settings_options_array[] = $row;
5208
    }
5209
5210
    return $settings_options_array;
5211
}
5212
5213
/**
5214
 * @param array $params
5215
 */
5216
function api_set_setting_option($params)
5217
{
5218
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
5219
    if (empty($params['id'])) {
5220
        Database::insert($table, $params);
5221
    } else {
5222
        Database::update($table, $params, ['id = ? ' => $params['id']]);
5223
    }
5224
}
5225
5226
/**
5227
 * @param array $params
5228
 */
5229
function api_set_setting_simple($params)
5230
{
5231
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5232
    $url_id = api_get_current_access_url_id();
5233
5234
    if (empty($params['id'])) {
5235
        $params['access_url'] = $url_id;
5236
        Database::insert($table, $params);
5237
    } else {
5238
        Database::update($table, $params, ['id = ? ' => [$params['id']]]);
5239
    }
5240
}
5241
5242
/**
5243
 * @param int $id
5244
 */
5245
function api_delete_setting_option($id)
5246
{
5247
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
5248
    if (!empty($id)) {
5249
        Database::delete($table, ['id = ? ' => $id]);
5250
    }
5251
}
5252
5253
/**
5254
 * Sets a platform configuration setting to a given value.
5255
 *
5256
 * @param string    The variable we want to update
5257
 * @param string    The value we want to record
5258
 * @param string    The sub-variable if any (in most cases, this will remain null)
5259
 * @param string    The category if any (in most cases, this will remain null)
5260
 * @param int       The access_url for which this parameter is valid
5261
 * @param string $cat
5262
 *
5263
 * @return bool|null
5264
 */
5265
function api_set_setting($var, $value, $subvar = null, $cat = null, $access_url = 1)
5266
{
5267
    if (empty($var)) {
5268
        return false;
5269
    }
5270
    $t_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5271
    $var = Database::escape_string($var);
5272
    $value = Database::escape_string($value);
5273
    $access_url = (int) $access_url;
5274
    if (empty($access_url)) {
5275
        $access_url = 1;
5276
    }
5277
    $select = "SELECT id FROM $t_settings WHERE variable = '$var' ";
5278
    if (!empty($subvar)) {
5279
        $subvar = Database::escape_string($subvar);
5280
        $select .= " AND subkey = '$subvar'";
5281
    }
5282
    if (!empty($cat)) {
5283
        $cat = Database::escape_string($cat);
5284
        $select .= " AND category = '$cat'";
5285
    }
5286
    if ($access_url > 1) {
5287
        $select .= " AND access_url = $access_url";
5288
    } else {
5289
        $select .= " AND access_url = 1 ";
5290
    }
5291
5292
    $res = Database::query($select);
5293
    if (Database::num_rows($res) > 0) {
5294
        // Found item for this access_url.
5295
        $row = Database::fetch_array($res);
5296
        $sql = "UPDATE $t_settings SET selected_value = '$value'
5297
                WHERE id = ".$row['id'];
5298
        Database::query($sql);
5299
    } else {
5300
        // Item not found for this access_url, we have to check if it exist with access_url = 1
5301
        $select = "SELECT * FROM $t_settings
5302
                   WHERE variable = '$var' AND access_url = 1 ";
5303
        // Just in case
5304
        if (1 == $access_url) {
5305
            if (!empty($subvar)) {
5306
                $select .= " AND subkey = '$subvar'";
5307
            }
5308
            if (!empty($cat)) {
5309
                $select .= " AND category = '$cat'";
5310
            }
5311
            $res = Database::query($select);
5312
            if (Database::num_rows($res) > 0) {
5313
                // We have a setting for access_url 1, but none for the current one, so create one.
5314
                $row = Database::fetch_array($res);
5315
                $insert = "INSERT INTO $t_settings (variable, subkey, type,category, selected_value, title, comment, scope, subkeytext, access_url)
5316
                        VALUES
5317
                        ('".$row['variable']."',".(!empty($row['subkey']) ? "'".$row['subkey']."'" : "NULL").",".
5318
                    "'".$row['type']."','".$row['category']."',".
5319
                    "'$value','".$row['title']."',".
5320
                    "".(!empty($row['comment']) ? "'".$row['comment']."'" : "NULL").",".(!empty($row['scope']) ? "'".$row['scope']."'" : "NULL").",".
5321
                    "".(!empty($row['subkeytext']) ? "'".$row['subkeytext']."'" : "NULL").",$access_url)";
5322
                Database::query($insert);
5323
            } else {
5324
                // Such a setting does not exist.
5325
                //error_log(__FILE__.':'.__LINE__.': Attempting to update setting '.$var.' ('.$subvar.') which does not exist at all', 0);
5326
            }
5327
        } else {
5328
            // Other access url.
5329
            if (!empty($subvar)) {
5330
                $select .= " AND subkey = '$subvar'";
5331
            }
5332
            if (!empty($cat)) {
5333
                $select .= " AND category = '$cat'";
5334
            }
5335
            $res = Database::query($select);
5336
5337
            if (Database::num_rows($res) > 0) {
5338
                // We have a setting for access_url 1, but none for the current one, so create one.
5339
                $row = Database::fetch_array($res);
5340
                if (1 == $row['access_url_changeable']) {
5341
                    $insert = "INSERT INTO $t_settings (variable,subkey, type,category, selected_value,title, comment,scope, subkeytext,access_url, access_url_changeable) VALUES
5342
                            ('".$row['variable']."',".
5343
                        (!empty($row['subkey']) ? "'".$row['subkey']."'" : "NULL").",".
5344
                        "'".$row['type']."','".$row['category']."',".
5345
                        "'$value','".$row['title']."',".
5346
                        "".(!empty($row['comment']) ? "'".$row['comment']."'" : "NULL").",".
5347
                        (!empty($row['scope']) ? "'".$row['scope']."'" : "NULL").",".
5348
                        "".(!empty($row['subkeytext']) ? "'".$row['subkeytext']."'" : "NULL").",$access_url,".$row['access_url_changeable'].")";
5349
                    Database::query($insert);
5350
                }
5351
            } else { // Such a setting does not exist.
5352
                //error_log(__FILE__.':'.__LINE__.': Attempting to update setting '.$var.' ('.$subvar.') which does not exist at all. The access_url is: '.$access_url.' ',0);
5353
            }
5354
        }
5355
    }
5356
}
5357
5358
/**
5359
 * Sets a whole category of settings to one specific value.
5360
 *
5361
 * @param string    Category
5362
 * @param string    Value
5363
 * @param int       Access URL. Optional. Defaults to 1
5364
 * @param array     Optional array of filters on field type
5365
 * @param string $category
5366
 * @param string $value
5367
 *
5368
 * @return bool
5369
 */
5370
function api_set_settings_category($category, $value = null, $access_url = 1, $fieldtype = [])
5371
{
5372
    if (empty($category)) {
5373
        return false;
5374
    }
5375
    $category = Database::escape_string($category);
5376
    $t_s = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5377
    $access_url = (int) $access_url;
5378
    if (empty($access_url)) {
5379
        $access_url = 1;
5380
    }
5381
    if (isset($value)) {
5382
        $value = Database::escape_string($value);
5383
        $sql = "UPDATE $t_s SET selected_value = '$value'
5384
                WHERE category = '$category' AND access_url = $access_url";
5385
        if (is_array($fieldtype) && count($fieldtype) > 0) {
5386
            $sql .= " AND ( ";
5387
            $i = 0;
5388
            foreach ($fieldtype as $type) {
5389
                if ($i > 0) {
5390
                    $sql .= ' OR ';
5391
                }
5392
                $type = Database::escape_string($type);
5393
                $sql .= " type='".$type."' ";
5394
                $i++;
5395
            }
5396
            $sql .= ")";
5397
        }
5398
        $res = Database::query($sql);
5399
5400
        return false !== $res;
5401
    } else {
5402
        $sql = "UPDATE $t_s SET selected_value = NULL
5403
                WHERE category = '$category' AND access_url = $access_url";
5404
        if (is_array($fieldtype) && count($fieldtype) > 0) {
5405
            $sql .= " AND ( ";
5406
            $i = 0;
5407
            foreach ($fieldtype as $type) {
5408
                if ($i > 0) {
5409
                    $sql .= ' OR ';
5410
                }
5411
                $type = Database::escape_string($type);
5412
                $sql .= " type='".$type."' ";
5413
                $i++;
5414
            }
5415
            $sql .= ")";
5416
        }
5417
        $res = Database::query($sql);
5418
5419
        return false !== $res;
5420
    }
5421
}
5422
5423
/**
5424
 * Gets all available access urls in an array (as in the database).
5425
 *
5426
 * @return array An array of database records
5427
 */
5428
function api_get_access_urls($from = 0, $to = 1000000, $order = 'url', $direction = 'ASC')
5429
{
5430
    $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5431
    $from = (int) $from;
5432
    $to = (int) $to;
5433
    $order = Database::escape_string($order, null, false);
5434
    $direction = Database::escape_string($direction, null, false);
5435
    $sql = "SELECT id, url, description, active, created_by, tms
5436
            FROM $table
5437
            ORDER BY $order $direction
5438
            LIMIT $to OFFSET $from";
5439
    $res = Database::query($sql);
5440
5441
    return Database::store_result($res);
5442
}
5443
5444
/**
5445
 * Gets the access url info in an array.
5446
 *
5447
 * @param int  $id            Id of the access url
5448
 * @param bool $returnDefault Set to false if you want the real URL if URL 1 is still 'http://localhost/'
5449
 *
5450
 * @return array All the info (url, description, active, created_by, tms)
5451
 *               from the access_url table
5452
 *
5453
 * @author Julio Montoya
5454
 */
5455
function api_get_access_url($id, $returnDefault = true)
5456
{
5457
    static $staticResult;
5458
    $id = (int) $id;
5459
5460
    if (isset($staticResult[$id])) {
5461
        $result = $staticResult[$id];
5462
    } else {
5463
        // Calling the Database:: library dont work this is handmade.
5464
        $table_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5465
        $sql = "SELECT url, description, active, created_by, tms
5466
                FROM $table_access_url WHERE id = '$id' ";
5467
        $res = Database::query($sql);
5468
        $result = @Database::fetch_array($res);
5469
        $staticResult[$id] = $result;
5470
    }
5471
5472
    // If the result url is 'http://localhost/' (the default) and the root_web
5473
    // (=current url) is different, and the $id is = 1 (which might mean
5474
    // api_get_current_access_url_id() returned 1 by default), then return the
5475
    // root_web setting instead of the current URL
5476
    // This is provided as an option to avoid breaking the storage of URL-specific
5477
    // homepages in home/localhost/
5478
    if (1 === $id && false === $returnDefault) {
5479
        $currentUrl = api_get_current_access_url_id();
5480
        // only do this if we are on the main URL (=1), otherwise we could get
5481
        // information on another URL instead of the one asked as parameter
5482
        if (1 === $currentUrl) {
5483
            $rootWeb = api_get_path(WEB_PATH);
5484
            $default = 'http://localhost/';
5485
            if ($result['url'] === $default && $rootWeb != $default) {
5486
                $result['url'] = $rootWeb;
5487
            }
5488
        }
5489
    }
5490
5491
    return $result;
5492
}
5493
5494
/**
5495
 * Gets all the current settings for a specific access url.
5496
 *
5497
 * @param string    The category, if any, that we want to get
5498
 * @param string    Whether we want a simple list (display a category) or
5499
 * a grouped list (group by variable as in settings.php default). Values: 'list' or 'group'
5500
 * @param int       Access URL's ID. Optional. Uses 1 by default, which is the unique URL
5501
 *
5502
 * @return array Array of database results for the current settings of the current access URL
5503
 */
5504
function &api_get_settings($cat = null, $ordering = 'list', $access_url = 1, $url_changeable = 0)
5505
{
5506
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5507
    $access_url = (int) $access_url;
5508
    $where_condition = '';
5509
    if (1 == $url_changeable) {
5510
        $where_condition = " AND access_url_changeable= '1' ";
5511
    }
5512
    if (empty($access_url) || -1 == $access_url) {
5513
        $access_url = 1;
5514
    }
5515
    $sql = "SELECT * FROM $table
5516
            WHERE access_url = $access_url  $where_condition ";
5517
5518
    if (!empty($cat)) {
5519
        $cat = Database::escape_string($cat);
5520
        $sql .= " AND category='$cat' ";
5521
    }
5522
    if ('group' == $ordering) {
5523
        $sql .= " ORDER BY id ASC";
5524
    } else {
5525
        $sql .= " ORDER BY 1,2 ASC";
5526
    }
5527
    $result = Database::query($sql);
5528
    if (null === $result) {
5529
        return [];
5530
    }
5531
    $result = Database::store_result($result, 'ASSOC');
5532
5533
    return $result;
5534
}
5535
5536
/**
5537
 * @param string $value       The value we want to record
5538
 * @param string $variable    The variable name we want to insert
5539
 * @param string $subKey      The subkey for the variable we want to insert
5540
 * @param string $type        The type for the variable we want to insert
5541
 * @param string $category    The category for the variable we want to insert
5542
 * @param string $title       The title
5543
 * @param string $comment     The comment
5544
 * @param string $scope       The scope
5545
 * @param string $subKeyText  The subkey text
5546
 * @param int    $accessUrlId The access_url for which this parameter is valid
5547
 * @param int    $visibility  The changeability of this setting for non-master urls
5548
 *
5549
 * @return int The setting ID
5550
 */
5551
function api_add_setting(
5552
    $value,
5553
    $variable,
5554
    $subKey = '',
5555
    $type = 'textfield',
5556
    $category = '',
5557
    $title = '',
5558
    $comment = '',
5559
    $scope = '',
5560
    $subKeyText = '',
5561
    $accessUrlId = 1,
5562
    $visibility = 0
5563
) {
5564
    $em = Database::getManager();
5565
5566
    $settingRepo = $em->getRepository(SettingsCurrent::class);
5567
    $accessUrlId = (int) $accessUrlId ?: 1;
5568
5569
    if (is_array($value)) {
5570
        $value = serialize($value);
5571
    } else {
5572
        $value = trim($value);
5573
    }
5574
5575
    $criteria = ['variable' => $variable, 'url' => $accessUrlId];
5576
5577
    if (!empty($subKey)) {
5578
        $criteria['subkey'] = $subKey;
5579
    }
5580
5581
    // Check if this variable doesn't exist already
5582
    /** @var SettingsCurrent $setting */
5583
    $setting = $settingRepo->findOneBy($criteria);
5584
5585
    if ($setting) {
0 ignored issues
show
introduced by
$setting is of type Chamilo\CoreBundle\Entity\SettingsCurrent, thus it always evaluated to true.
Loading history...
5586
        $setting->setSelectedValue($value);
5587
5588
        $em->persist($setting);
5589
        $em->flush();
5590
5591
        return $setting->getId();
5592
    }
5593
5594
    // Item not found for this access_url, we have to check if the whole thing is missing
5595
    // (in which case we ignore the insert) or if there *is* a record but just for access_url = 1
5596
    $setting = new SettingsCurrent();
5597
    $url = api_get_url_entity();
5598
5599
    $setting
5600
        ->setVariable($variable)
5601
        ->setSelectedValue($value)
5602
        ->setType($type)
5603
        ->setCategory($category)
5604
        ->setSubkey($subKey)
5605
        ->setTitle($title)
5606
        ->setComment($comment)
5607
        ->setScope($scope)
5608
        ->setSubkeytext($subKeyText)
5609
        ->setUrl(api_get_url_entity())
5610
        ->setAccessUrlChangeable($visibility);
5611
5612
    $em->persist($setting);
5613
    $em->flush();
5614
5615
    return $setting->getId();
5616
}
5617
5618
/**
5619
 * Checks wether a user can or can't view the contents of a course.
5620
 *
5621
 * @deprecated use CourseManager::is_user_subscribed_in_course
5622
 *
5623
 * @param int $userid User id or NULL to get it from $_SESSION
5624
 * @param int $cid    course id to check whether the user is allowed
5625
 *
5626
 * @return bool
5627
 */
5628
function api_is_course_visible_for_user($userid = null, $cid = null)
5629
{
5630
    if (null === $userid) {
5631
        $userid = api_get_user_id();
5632
    }
5633
    if (empty($userid) || strval(intval($userid)) != $userid) {
5634
        if (api_is_anonymous()) {
5635
            $userid = api_get_anonymous_id();
5636
        } else {
5637
            return false;
5638
        }
5639
    }
5640
    $cid = Database::escape_string($cid);
5641
5642
    $courseInfo = api_get_course_info($cid);
5643
    $courseId = $courseInfo['real_id'];
5644
    $is_platformAdmin = api_is_platform_admin();
5645
5646
    $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
5647
    $course_cat_table = Database::get_main_table(TABLE_MAIN_CATEGORY);
5648
5649
    $sql = "SELECT
5650
                $course_cat_table.code AS category_code,
5651
                $course_table.visibility,
5652
                $course_table.code,
5653
                $course_cat_table.code
5654
            FROM $course_table
5655
            LEFT JOIN $course_cat_table
5656
                ON $course_table.category_id = $course_cat_table.id
5657
            WHERE
5658
                $course_table.code = '$cid'
5659
            LIMIT 1";
5660
5661
    $result = Database::query($sql);
5662
5663
    if (Database::num_rows($result) > 0) {
5664
        $visibility = Database::fetch_array($result);
5665
        $visibility = $visibility['visibility'];
5666
    } else {
5667
        $visibility = 0;
5668
    }
5669
    // Shortcut permissions in case the visibility is "open to the world".
5670
    if (COURSE_VISIBILITY_OPEN_WORLD === $visibility) {
5671
        return true;
5672
    }
5673
5674
    $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
5675
5676
    $sql = "SELECT
5677
                is_tutor, status
5678
            FROM $tbl_course_user
5679
            WHERE
5680
                user_id  = '$userid' AND
5681
                relation_type <> '".COURSE_RELATION_TYPE_RRHH."' AND
5682
                c_id = $courseId
5683
            LIMIT 1";
5684
5685
    $result = Database::query($sql);
5686
5687
    if (Database::num_rows($result) > 0) {
5688
        // This user has got a recorded state for this course.
5689
        $cuData = Database::fetch_array($result);
5690
        $is_courseMember = true;
5691
        $is_courseAdmin = (1 == $cuData['status']);
5692
    }
5693
5694
    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...
5695
        // This user has no status related to this course.
5696
        // Is it the session coach or the session admin?
5697
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
5698
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
5699
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
5700
5701
        $sql = "SELECT
5702
                    session.id_coach, session_admin_id, session.id
5703
                FROM
5704
                    $tbl_session as session
5705
                INNER JOIN $tbl_session_course
5706
                    ON session_rel_course.session_id = session.id
5707
                    AND session_rel_course.c_id = '$courseId'
5708
                LIMIT 1";
5709
5710
        $result = Database::query($sql);
5711
        $row = Database::store_result($result);
5712
5713
        if ($row[0]['id_coach'] == $userid) {
5714
            $is_courseMember = true;
5715
            $is_courseAdmin = false;
5716
        } elseif ($row[0]['session_admin_id'] == $userid) {
5717
            $is_courseMember = false;
5718
            $is_courseAdmin = false;
5719
        } else {
5720
            // Check if the current user is the course coach.
5721
            $sql = "SELECT 1
5722
                    FROM $tbl_session_course
5723
                    WHERE session_rel_course.c_id = '$courseId'
5724
                    AND session_rel_course.id_coach = '$userid'
5725
                    LIMIT 1";
5726
5727
            $result = Database::query($sql);
5728
5729
            //if ($row = Database::fetch_array($result)) {
5730
            if (Database::num_rows($result) > 0) {
5731
                $is_courseMember = true;
5732
                $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
5733
5734
                $sql = "SELECT status FROM $tbl_user
5735
                        WHERE user_id = $userid
5736
                        LIMIT 1";
5737
5738
                $result = Database::query($sql);
5739
5740
                if (1 == Database::result($result, 0, 0)) {
5741
                    $is_courseAdmin = true;
5742
                } else {
5743
                    $is_courseAdmin = false;
5744
                }
5745
            } else {
5746
                // Check if the user is a student is this session.
5747
                $sql = "SELECT  id
5748
                        FROM $tbl_session_course_user
5749
                        WHERE
5750
                            user_id  = '$userid' AND
5751
                            c_id = '$courseId'
5752
                        LIMIT 1";
5753
5754
                if (Database::num_rows($result) > 0) {
5755
                    // This user haa got a recorded state for this course.
5756
                    while ($row = Database::fetch_array($result)) {
5757
                        $is_courseMember = true;
5758
                        $is_courseAdmin = false;
5759
                    }
5760
                }
5761
            }
5762
        }
5763
    }
5764
5765
    switch ($visibility) {
5766
        case COURSE_VISIBILITY_OPEN_WORLD:
5767
            return true;
5768
        case COURSE_VISIBILITY_OPEN_PLATFORM:
5769
            return isset($userid);
5770
        case COURSE_VISIBILITY_REGISTERED:
5771
        case COURSE_VISIBILITY_CLOSED:
5772
            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...
5773
        case COURSE_VISIBILITY_HIDDEN:
5774
            return $is_platformAdmin;
5775
    }
5776
5777
    return false;
5778
}
5779
5780
/**
5781
 * Returns whether an element (forum, message, survey ...) belongs to a session or not.
5782
 *
5783
 * @param string the tool of the element
5784
 * @param int the element id in database
5785
 * @param int the session_id to compare with element session id
5786
 *
5787
 * @return bool true if the element is in the session, false else
5788
 */
5789
function api_is_element_in_the_session($tool, $element_id, $session_id = null)
5790
{
5791
    if (is_null($session_id)) {
5792
        $session_id = api_get_session_id();
5793
    }
5794
5795
    $element_id = (int) $element_id;
5796
5797
    if (empty($element_id)) {
5798
        return false;
5799
    }
5800
5801
    // Get information to build query depending of the tool.
5802
    switch ($tool) {
5803
        case TOOL_SURVEY:
5804
            $table_tool = Database::get_course_table(TABLE_SURVEY);
5805
            $key_field = 'survey_id';
5806
            break;
5807
        case TOOL_ANNOUNCEMENT:
5808
            $table_tool = Database::get_course_table(TABLE_ANNOUNCEMENT);
5809
            $key_field = 'id';
5810
            break;
5811
        case TOOL_AGENDA:
5812
            $table_tool = Database::get_course_table(TABLE_AGENDA);
5813
            $key_field = 'id';
5814
            break;
5815
        case TOOL_GROUP:
5816
            $table_tool = Database::get_course_table(TABLE_GROUP);
5817
            $key_field = 'id';
5818
            break;
5819
        default:
5820
            return false;
5821
    }
5822
    $course_id = api_get_course_int_id();
5823
5824
    $sql = "SELECT session_id FROM $table_tool
5825
            WHERE c_id = $course_id AND $key_field =  ".$element_id;
5826
    $rs = Database::query($sql);
5827
    if ($element_session_id = Database::result($rs, 0, 0)) {
5828
        if ($element_session_id == intval($session_id)) {
5829
            // The element belongs to the session.
5830
            return true;
5831
        }
5832
    }
5833
5834
    return false;
5835
}
5836
5837
/**
5838
 * Replaces "forbidden" characters in a filename string.
5839
 *
5840
 * @param string $filename
5841
 * @param bool   $treat_spaces_as_hyphens
5842
 *
5843
 * @return string
5844
 */
5845
function api_replace_dangerous_char($filename, $treat_spaces_as_hyphens = true)
5846
{
5847
    // Some non-properly encoded file names can cause the whole file to be
5848
    // skipped when uploaded. Avoid this by detecting the encoding and
5849
    // converting to UTF-8, setting the source as ASCII (a reasonably
5850
    // limited characters set) if nothing could be found (BT#
5851
    $encoding = api_detect_encoding($filename);
5852
    if (empty($encoding)) {
5853
        $encoding = 'ASCII';
5854
        if (!api_is_valid_ascii($filename)) {
5855
            // try iconv and try non standard ASCII a.k.a CP437
5856
            // see BT#15022
5857
            if (function_exists('iconv')) {
5858
                $result = iconv('CP437', 'UTF-8', $filename);
5859
                if (api_is_valid_utf8($result)) {
5860
                    $filename = $result;
5861
                    $encoding = 'UTF-8';
5862
                }
5863
            }
5864
        }
5865
    }
5866
5867
    $filename = api_to_system_encoding($filename, $encoding);
5868
5869
    $url = URLify::filter(
5870
        $filename,
5871
        250,
5872
        '',
5873
        true,
5874
        false,
5875
        false,
5876
        false
5877
    );
5878
5879
    return $url;
5880
}
5881
5882
/**
5883
 * Fixes the $_SERVER['REQUEST_URI'] that is empty in IIS6.
5884
 *
5885
 * @author Ivan Tcholakov, 28-JUN-2006.
5886
 */
5887
function api_request_uri()
5888
{
5889
    if (!empty($_SERVER['REQUEST_URI'])) {
5890
        return $_SERVER['REQUEST_URI'];
5891
    }
5892
    $uri = $_SERVER['SCRIPT_NAME'];
5893
    if (!empty($_SERVER['QUERY_STRING'])) {
5894
        $uri .= '?'.$_SERVER['QUERY_STRING'];
5895
    }
5896
    $_SERVER['REQUEST_URI'] = $uri;
5897
5898
    return $uri;
5899
}
5900
5901
/** Gets the current access_url id of the Chamilo Platform.
5902
 * @author Julio Montoya <[email protected]>
5903
 *
5904
 * @return int access_url_id of the current Chamilo Installation
5905
 */
5906
function api_get_current_access_url_id()
5907
{
5908
    if (false === api_get_multiple_access_url()) {
5909
        return 1;
5910
    }
5911
5912
    static $id;
5913
    if (!empty($id)) {
5914
        return $id;
5915
    }
5916
5917
    $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5918
    $path = Database::escape_string(api_get_path(WEB_PATH));
5919
    $sql = "SELECT id FROM $table WHERE url = '".$path."'";
5920
    $result = Database::query($sql);
5921
    if (Database::num_rows($result) > 0) {
5922
        $id = Database::result($result, 0, 0);
5923
        if (false === $id) {
5924
            return -1;
5925
        }
5926
5927
        return (int) $id;
5928
    }
5929
5930
    $id = 1;
5931
5932
    //if the url in WEB_PATH was not found, it can only mean that there is
5933
    // either a configuration problem or the first URL has not been defined yet
5934
    // (by default it is http://localhost/). Thus the more sensible thing we can
5935
    // do is return 1 (the main URL) as the user cannot hack this value anyway
5936
    return 1;
5937
}
5938
5939
/**
5940
 * Gets the registered urls from a given user id.
5941
 *
5942
 * @author Julio Montoya <[email protected]>
5943
 *
5944
 * @param int $user_id
5945
 *
5946
 * @return array
5947
 */
5948
function api_get_access_url_from_user($user_id)
5949
{
5950
    $user_id = (int) $user_id;
5951
    $table_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
5952
    $table_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5953
    $sql = "SELECT access_url_id
5954
            FROM $table_url_rel_user url_rel_user
5955
            INNER JOIN $table_url u
5956
            ON (url_rel_user.access_url_id = u.id)
5957
            WHERE user_id = ".$user_id;
5958
    $result = Database::query($sql);
5959
    $list = [];
5960
    while ($row = Database::fetch_array($result, 'ASSOC')) {
5961
        $list[] = $row['access_url_id'];
5962
    }
5963
5964
    return $list;
5965
}
5966
5967
/**
5968
 * Checks whether the curent user is in a group or not.
5969
 *
5970
 * @param string        The group id - optional (takes it from session if not given)
5971
 * @param string        The course code - optional (no additional check by course if course code is not given)
5972
 *
5973
 * @return bool
5974
 *
5975
 * @author Ivan Tcholakov
5976
 */
5977
function api_is_in_group($groupIdParam = null, $courseCodeParam = null)
5978
{
5979
    if (!empty($courseCodeParam)) {
5980
        $courseCode = api_get_course_id();
5981
        if (!empty($courseCode)) {
5982
            if ($courseCodeParam != $courseCode) {
5983
                return false;
5984
            }
5985
        } else {
5986
            return false;
5987
        }
5988
    }
5989
5990
    $groupId = api_get_group_id();
5991
5992
    if (isset($groupId) && '' != $groupId) {
5993
        if (!empty($groupIdParam)) {
5994
            return $groupIdParam == $groupId;
5995
        } else {
5996
            return true;
5997
        }
5998
    }
5999
6000
    return false;
6001
}
6002
6003
/**
6004
 * Checks whether a secret key is valid.
6005
 *
6006
 * @param string $original_key_secret - secret key from (webservice) client
6007
 * @param string $security_key        - security key from Chamilo
6008
 *
6009
 * @return bool - true if secret key is valid, false otherwise
6010
 */
6011
function api_is_valid_secret_key($original_key_secret, $security_key)
6012
{
6013
    return $original_key_secret == sha1($security_key);
6014
}
6015
6016
/**
6017
 * Checks whether a user is into course.
6018
 *
6019
 * @param int $course_id - the course id
6020
 * @param int $user_id   - the user id
6021
 *
6022
 * @return bool
6023
 */
6024
function api_is_user_of_course($course_id, $user_id)
6025
{
6026
    $tbl_course_rel_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
6027
    $sql = 'SELECT user_id FROM '.$tbl_course_rel_user.'
6028
            WHERE
6029
                c_id ="'.intval($course_id).'" AND
6030
                user_id = "'.intval($user_id).'" AND
6031
                relation_type <> '.COURSE_RELATION_TYPE_RRHH.' ';
6032
    $result = Database::query($sql);
6033
6034
    return 1 == Database::num_rows($result);
6035
}
6036
6037
/**
6038
 * Checks whether the server's operating system is Windows (TM).
6039
 *
6040
 * @return bool - true if the operating system is Windows, false otherwise
6041
 */
6042
function api_is_windows_os()
6043
{
6044
    if (function_exists('php_uname')) {
6045
        // php_uname() exists as of PHP 4.0.2, according to the documentation.
6046
        // We expect that this function will always work for Chamilo 1.8.x.
6047
        $os = php_uname();
6048
    }
6049
    // The following methods are not needed, but let them stay, just in case.
6050
    elseif (isset($_ENV['OS'])) {
6051
        // Sometimes $_ENV['OS'] may not be present (bugs?)
6052
        $os = $_ENV['OS'];
6053
    } elseif (defined('PHP_OS')) {
6054
        // PHP_OS means on which OS PHP was compiled, this is why
6055
        // using PHP_OS is the last choice for detection.
6056
        $os = PHP_OS;
6057
    } else {
6058
        return false;
6059
    }
6060
6061
    return 'win' == strtolower(substr((string) $os, 0, 3));
6062
}
6063
6064
/**
6065
 * This function informs whether the sent request is XMLHttpRequest.
6066
 */
6067
function api_is_xml_http_request()
6068
{
6069
    return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && 'xmlhttprequest' == strtolower($_SERVER['HTTP_X_REQUESTED_WITH']);
6070
}
6071
6072
/**
6073
 * This wrapper function has been implemented for avoiding some known problems about the function getimagesize().
6074
 *
6075
 * @see http://php.net/manual/en/function.getimagesize.php
6076
 * @see http://www.dokeos.com/forum/viewtopic.php?t=12345
6077
 * @see http://www.dokeos.com/forum/viewtopic.php?t=16355
6078
 *
6079
 * @return int
6080
 */
6081
function api_getimagesize($path)
6082
{
6083
    $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

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

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