Completed
Push — master ( 24096d...e49e51 )
by Julito
08:45
created

api_get_user_info_from_entity()   F

Complexity

Conditions 28
Paths > 20000

Size

Total Lines 230
Code Lines 122

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 28
eloc 122
nc 89859
nop 7
dl 0
loc 230
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

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

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

1266
function api_get_user_courses($userId, /** @scrutinizer ignore-unused */ $fetch_session = true)

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

Loading history...
1267
{
1268
    // Get out if not integer
1269
    if ($userId != strval(intval($userId))) {
1270
        return [];
1271
    }
1272
1273
    $t_course = Database::get_main_table(TABLE_MAIN_COURSE);
1274
    $t_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
1275
1276
    $sql = "SELECT cc.id as real_id, cc.code code, cc.directory dir, cu.status status
1277
            FROM $t_course cc, $t_course_user cu
1278
            WHERE
1279
                cc.id = cu.c_id AND
1280
                cu.user_id = $userId AND
1281
                cu.relation_type <> ".COURSE_RELATION_TYPE_RRHH;
1282
    $result = Database::query($sql);
1283
    if (false === $result) {
1284
        return [];
1285
    }
1286
1287
    $courses = [];
1288
    while ($row = Database::fetch_array($result)) {
1289
        // we only need the database name of the course
1290
        $courses[] = $row;
1291
    }
1292
1293
    return $courses;
1294
}
1295
1296
/**
1297
 * Formats user information into a standard array
1298
 * This function should be only used inside api_get_user_info().
1299
 *
1300
 * @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...
1301
 * @param bool $add_password
1302
 * @param bool $loadAvatars  turn off to improve performance
1303
 *
1304
 * @return array Standard user array
1305
 */
1306
function _api_format_user($user, $add_password = false, $loadAvatars = true)
1307
{
1308
    $result = [];
1309
1310
    if (!isset($user['user_id'])) {
1311
        return [];
1312
    }
1313
1314
    $result['firstname'] = null;
1315
    $result['lastname'] = null;
1316
1317
    if (isset($user['firstname']) && isset($user['lastname'])) {
1318
        // with only lowercase
1319
        $result['firstname'] = $user['firstname'];
1320
        $result['lastname'] = $user['lastname'];
1321
    } elseif (isset($user['firstName']) && isset($user['lastName'])) {
1322
        // with uppercase letters
1323
        $result['firstname'] = isset($user['firstName']) ? $user['firstName'] : null;
1324
        $result['lastname'] = isset($user['lastName']) ? $user['lastName'] : null;
1325
    }
1326
1327
    if (isset($user['email'])) {
1328
        $result['mail'] = isset($user['email']) ? $user['email'] : null;
1329
        $result['email'] = isset($user['email']) ? $user['email'] : null;
1330
    } else {
1331
        $result['mail'] = isset($user['mail']) ? $user['mail'] : null;
1332
        $result['email'] = isset($user['mail']) ? $user['mail'] : null;
1333
    }
1334
1335
    $result['complete_name'] = api_get_person_name($result['firstname'], $result['lastname']);
1336
    $result['complete_name_with_username'] = $result['complete_name'];
1337
1338
    if (!empty($user['username']) && 'false' === api_get_setting('profile.hide_username_with_complete_name')) {
1339
        $result['complete_name_with_username'] = $result['complete_name'].' ('.$user['username'].')';
1340
    }
1341
1342
    $showEmail = 'true' === api_get_setting('show_email_addresses');
1343
    if (!empty($user['email'])) {
1344
        $result['complete_name_with_email_forced'] = $result['complete_name'].' ('.$user['email'].')';
1345
        if ($showEmail) {
1346
            $result['complete_name_with_email'] = $result['complete_name'].' ('.$user['email'].')';
1347
        }
1348
    } else {
1349
        $result['complete_name_with_email'] = $result['complete_name'];
1350
        $result['complete_name_with_email_forced'] = $result['complete_name'];
1351
    }
1352
1353
    // Kept for historical reasons
1354
    $result['firstName'] = $result['firstname'];
1355
    $result['lastName'] = $result['lastname'];
1356
1357
    $attributes = [
1358
        'phone',
1359
        'address',
1360
        'picture_uri',
1361
        'official_code',
1362
        'status',
1363
        'active',
1364
        'auth_source',
1365
        'username',
1366
        'theme',
1367
        'language',
1368
        'creator_id',
1369
        'registration_date',
1370
        'hr_dept_id',
1371
        'expiration_date',
1372
        'last_login',
1373
        'user_is_online',
1374
    ];
1375
1376
    if ('true' === api_get_setting('extended_profile')) {
1377
        $attributes[] = 'competences';
1378
        $attributes[] = 'diplomas';
1379
        $attributes[] = 'teach';
1380
        $attributes[] = 'openarea';
1381
    }
1382
1383
    foreach ($attributes as $attribute) {
1384
        $result[$attribute] = isset($user[$attribute]) ? $user[$attribute] : null;
1385
    }
1386
1387
    $user_id = (int) $user['user_id'];
1388
    // Maintain the user_id index for backwards compatibility
1389
    $result['user_id'] = $result['id'] = $user_id;
1390
1391
    $hasCertificates = Certificate::getCertificateByUser($user_id);
1392
    $result['has_certificates'] = 0;
1393
    if (!empty($hasCertificates)) {
1394
        $result['has_certificates'] = 1;
1395
    }
1396
1397
    $result['icon_status'] = '';
1398
    $result['icon_status_medium'] = '';
1399
    $result['is_admin'] = UserManager::is_admin($user_id);
1400
1401
    // Getting user avatar.
1402
    if ($loadAvatars) {
1403
        $result['avatar'] = '';
1404
        $result['avatar_no_query'] = '';
1405
        $result['avatar_small'] = '';
1406
        $result['avatar_medium'] = '';
1407
1408
        /*if (!isset($user['avatar'])) {
1409
            $originalFile = UserManager::getUserPicture(
1410
                $user_id,
1411
                USER_IMAGE_SIZE_ORIGINAL,
1412
                null,
1413
                $result
1414
            );
1415
            $result['avatar'] = $originalFile;
1416
            $avatarString = explode('?', $result['avatar']);
1417
            $result['avatar_no_query'] = reset($avatarString);
1418
        } else {
1419
            $result['avatar'] = $user['avatar'];
1420
            $avatarString = explode('?', $user['avatar']);
1421
            $result['avatar_no_query'] = reset($avatarString);
1422
        }
1423
1424
        if (!isset($user['avatar_small'])) {
1425
            $smallFile = UserManager::getUserPicture(
1426
                $user_id,
1427
                USER_IMAGE_SIZE_SMALL,
1428
                null,
1429
                $result
1430
            );
1431
            $result['avatar_small'] = $smallFile;
1432
        } else {
1433
            $result['avatar_small'] = $user['avatar_small'];
1434
        }
1435
1436
        if (!isset($user['avatar_medium'])) {
1437
            $mediumFile = UserManager::getUserPicture(
1438
                $user_id,
1439
                USER_IMAGE_SIZE_MEDIUM,
1440
                null,
1441
                $result
1442
            );
1443
            $result['avatar_medium'] = $mediumFile;
1444
        } else {
1445
            $result['avatar_medium'] = $user['avatar_medium'];
1446
        }*/
1447
1448
        $urlImg = api_get_path(WEB_IMG_PATH);
1449
        $iconStatus = '';
1450
        $iconStatusMedium = '';
1451
1452
        switch ($result['status']) {
1453
            case STUDENT:
1454
                if ($result['has_certificates']) {
1455
                    $iconStatus = $urlImg.'icons/svg/identifier_graduated.svg';
1456
                } else {
1457
                    $iconStatus = $urlImg.'icons/svg/identifier_student.svg';
1458
                }
1459
                break;
1460
            case COURSEMANAGER:
1461
                if ($result['is_admin']) {
1462
                    $iconStatus = $urlImg.'icons/svg/identifier_admin.svg';
1463
                } else {
1464
                    $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1465
                }
1466
                break;
1467
            case STUDENT_BOSS:
1468
                $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1469
                break;
1470
        }
1471
1472
        if (!empty($iconStatus)) {
1473
            $iconStatusMedium = '<img src="'.$iconStatus.'" width="32px" height="32px">';
1474
            $iconStatus = '<img src="'.$iconStatus.'" width="22px" height="22px">';
1475
        }
1476
1477
        $result['icon_status'] = $iconStatus;
1478
        $result['icon_status_medium'] = $iconStatusMedium;
1479
    }
1480
1481
    if (isset($user['user_is_online'])) {
1482
        $result['user_is_online'] = true == $user['user_is_online'] ? 1 : 0;
1483
    }
1484
    if (isset($user['user_is_online_in_chat'])) {
1485
        $result['user_is_online_in_chat'] = (int) $user['user_is_online_in_chat'];
1486
    }
1487
1488
    if ($add_password) {
1489
        $result['password'] = $user['password'];
1490
    }
1491
1492
    if (isset($result['profile_completed'])) {
1493
        $result['profile_completed'] = $user['profile_completed'];
1494
    }
1495
1496
    $result['profile_url'] = api_get_path(WEB_CODE_PATH).'social/profile.php?u='.$user_id;
1497
1498
    // Send message link
1499
    $sendMessage = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&user_id='.$user_id;
1500
    $result['complete_name_with_message_link'] = Display::url(
1501
        $result['complete_name_with_username'],
1502
        $sendMessage,
1503
        ['class' => 'ajax']
1504
    );
1505
1506
    if (isset($user['extra'])) {
1507
        $result['extra'] = $user['extra'];
1508
    }
1509
1510
    return $result;
1511
}
1512
1513
/**
1514
 * Finds all the information about a user.
1515
 * If no parameter is passed you find all the information about the current user.
1516
 *
1517
 * @param int  $user_id
1518
 * @param bool $checkIfUserOnline
1519
 * @param bool $showPassword
1520
 * @param bool $loadExtraData
1521
 * @param bool $loadOnlyVisibleExtraData Get the user extra fields that are visible
1522
 * @param bool $loadAvatars              turn off to improve performance and if avatars are not needed
1523
 * @param bool $updateCache              update apc cache if exists
1524
 *
1525
 * @return mixed $user_info user_id, lastname, firstname, username, email, etc or false on error
1526
 *
1527
 * @author Patrick Cool <[email protected]>
1528
 * @author Julio Montoya
1529
 *
1530
 * @version 21 September 2004
1531
 */
1532
function api_get_user_info(
1533
    $user_id = 0,
1534
    $checkIfUserOnline = false,
1535
    $showPassword = false,
1536
    $loadExtraData = false,
1537
    $loadOnlyVisibleExtraData = false,
1538
    $loadAvatars = true,
1539
    $updateCache = false
0 ignored issues
show
Unused Code introduced by
The parameter $updateCache is not used and could be removed. ( Ignorable by Annotation )

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

1539
    /** @scrutinizer ignore-unused */ $updateCache = false

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

Loading history...
1540
) {
1541
    // Make sure user_id is safe
1542
    $user_id = (int) $user_id;
1543
    $user = false;
1544
1545
    if (empty($user_id)) {
1546
        $userFromSession = Session::read('_user');
1547
1548
        if (isset($userFromSession) && !empty($userFromSession)) {
1549
            return $userFromSession;
1550
            /*
1551
            return _api_format_user(
1552
                $userFromSession,
1553
                $showPassword,
1554
                $loadAvatars
1555
            );*/
1556
        }
1557
1558
        return false;
1559
    }
1560
1561
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1562
            WHERE id = $user_id";
1563
    $result = Database::query($sql);
1564
    if (Database::num_rows($result) > 0) {
1565
        $result_array = Database::fetch_array($result);
1566
        $result_array['user_is_online_in_chat'] = 0;
1567
        if ($checkIfUserOnline) {
1568
            $use_status_in_platform = user_is_online($user_id);
1569
            $result_array['user_is_online'] = $use_status_in_platform;
1570
            $user_online_in_chat = 0;
1571
            if ($use_status_in_platform) {
1572
                $user_status = UserManager::get_extra_user_data_by_field(
1573
                    $user_id,
1574
                    'user_chat_status',
1575
                    false,
1576
                    true
1577
                );
1578
                if (1 == (int) $user_status['user_chat_status']) {
1579
                    $user_online_in_chat = 1;
1580
                }
1581
            }
1582
            $result_array['user_is_online_in_chat'] = $user_online_in_chat;
1583
        }
1584
1585
        if ($loadExtraData) {
1586
            $fieldValue = new ExtraFieldValue('user');
1587
            $result_array['extra'] = $fieldValue->getAllValuesForAnItem(
1588
                $user_id,
1589
                $loadOnlyVisibleExtraData
1590
            );
1591
        }
1592
        $user = _api_format_user($result_array, $showPassword, $loadAvatars);
1593
    }
1594
1595
    return $user;
1596
}
1597
1598
function api_get_user_info_from_entity(
1599
    User $user,
1600
    $checkIfUserOnline = false,
1601
    $showPassword = false,
1602
    $loadExtraData = false,
1603
    $loadOnlyVisibleExtraData = false,
1604
    $loadAvatars = true,
1605
    $loadCertificate = false
1606
) {
1607
    if (!$user instanceof UserInterface) {
1608
        return false;
1609
    }
1610
1611
    // Make sure user_id is safe
1612
    $user_id = (int) $user->getId();
1613
1614
    if (empty($user_id)) {
1615
        $userFromSession = Session::read('_user');
1616
1617
        if (isset($userFromSession) && !empty($userFromSession)) {
1618
            return $userFromSession;
1619
        }
1620
1621
        return false;
1622
    }
1623
1624
    $result = [];
1625
    $result['user_is_online_in_chat'] = 0;
1626
    if ($checkIfUserOnline) {
1627
        $use_status_in_platform = user_is_online($user_id);
1628
        $result['user_is_online'] = $use_status_in_platform;
1629
        $user_online_in_chat = 0;
1630
        if ($use_status_in_platform) {
1631
            $user_status = UserManager::get_extra_user_data_by_field(
1632
                $user_id,
1633
                'user_chat_status',
1634
                false,
1635
                true
1636
            );
1637
            if (1 == (int) $user_status['user_chat_status']) {
1638
                $user_online_in_chat = 1;
1639
            }
1640
        }
1641
        $result['user_is_online_in_chat'] = $user_online_in_chat;
1642
    }
1643
1644
    if ($loadExtraData) {
1645
        $fieldValue = new ExtraFieldValue('user');
1646
        $result['extra'] = $fieldValue->getAllValuesForAnItem(
1647
            $user_id,
1648
            $loadOnlyVisibleExtraData
1649
        );
1650
    }
1651
1652
    $result['username'] = $user->getUsername();
1653
    $result['firstname'] = $user->getFirstname();
1654
    $result['lastname'] = $user->getLastname();
1655
    $result['email'] = $result['mail'] = $user->getEmail();
1656
    $result['complete_name'] = api_get_person_name($result['firstname'], $result['lastname']);
1657
    $result['complete_name_with_username'] = $result['complete_name'];
1658
1659
    if (!empty($result['username']) && 'false' === api_get_setting('profile.hide_username_with_complete_name')) {
1660
        $result['complete_name_with_username'] = $result['complete_name'].' ('.$result['username'].')';
1661
    }
1662
1663
    $showEmail = 'true' === api_get_setting('show_email_addresses');
1664
    if (!empty($result['email'])) {
1665
        $result['complete_name_with_email_forced'] = $result['complete_name'].' ('.$result['email'].')';
1666
        if ($showEmail) {
1667
            $result['complete_name_with_email'] = $result['complete_name'].' ('.$result['email'].')';
1668
        }
1669
    } else {
1670
        $result['complete_name_with_email'] = $result['complete_name'];
1671
        $result['complete_name_with_email_forced'] = $result['complete_name'];
1672
    }
1673
1674
    // Kept for historical reasons
1675
    $result['firstName'] = $result['firstname'];
1676
    $result['lastName'] = $result['lastname'];
1677
1678
    $attributes = [
1679
        'picture_uri',
1680
        'last_login',
1681
        'user_is_online',
1682
    ];
1683
1684
    $result['phone'] = $user->getPhone();
1685
    $result['address'] = $user->getAddress();
1686
    $result['official_code'] = $user->getOfficialCode();
1687
    $result['active'] = $user->getActive();
1688
    $result['auth_source'] = $user->getAuthSource();
1689
    $result['language'] = $user->getLanguage();
1690
    $result['creator_id'] = $user->getCreatorId();
1691
    $result['registration_date'] = $user->getRegistrationDate()->format('Y-m-d H:i:s');
1692
    $result['hr_dept_id'] = $user->getHrDeptId();
1693
    $result['expiration_date'] = $user->getExpirationDate()->format('Y-m-d H:i:s');
1694
    $result['last_login'] = $user->getLastLogin()->format('Y-m-d H:i:s');
1695
    $result['competences'] = $user->getCompetences();
1696
    $result['diplomas'] = $user->getDiplomas();
1697
    $result['teach'] = $user->getTeach();
1698
    $result['openarea'] = $user->getOpenarea();
1699
    $user_id = (int) $user->getId();
1700
1701
    // Maintain the user_id index for backwards compatibility
1702
    $result['user_id'] = $result['id'] = $user_id;
1703
1704
    if ($loadCertificate) {
1705
        $hasCertificates = Certificate::getCertificateByUser($user_id);
1706
        $result['has_certificates'] = 0;
1707
        if (!empty($hasCertificates)) {
1708
            $result['has_certificates'] = 1;
1709
        }
1710
    }
1711
1712
    $result['icon_status'] = '';
1713
    $result['icon_status_medium'] = '';
1714
    $result['is_admin'] = UserManager::is_admin($user_id);
1715
1716
    // Getting user avatar.
1717
    if ($loadAvatars) {
1718
        $result['avatar'] = '';
1719
        $result['avatar_no_query'] = '';
1720
        $result['avatar_small'] = '';
1721
        $result['avatar_medium'] = '';
1722
1723
        /*if (!isset($user['avatar'])) {
1724
            $originalFile = UserManager::getUserPicture(
1725
                $user_id,
1726
                USER_IMAGE_SIZE_ORIGINAL,
1727
                null,
1728
                $result
1729
            );
1730
            $result['avatar'] = $originalFile;
1731
            $avatarString = explode('?', $result['avatar']);
1732
            $result['avatar_no_query'] = reset($avatarString);
1733
        } else {
1734
            $result['avatar'] = $user['avatar'];
1735
            $avatarString = explode('?', $user['avatar']);
1736
            $result['avatar_no_query'] = reset($avatarString);
1737
        }
1738
1739
        if (!isset($user['avatar_small'])) {
1740
            $smallFile = UserManager::getUserPicture(
1741
                $user_id,
1742
                USER_IMAGE_SIZE_SMALL,
1743
                null,
1744
                $result
1745
            );
1746
            $result['avatar_small'] = $smallFile;
1747
        } else {
1748
            $result['avatar_small'] = $user['avatar_small'];
1749
        }
1750
1751
        if (!isset($user['avatar_medium'])) {
1752
            $mediumFile = UserManager::getUserPicture(
1753
                $user_id,
1754
                USER_IMAGE_SIZE_MEDIUM,
1755
                null,
1756
                $result
1757
            );
1758
            $result['avatar_medium'] = $mediumFile;
1759
        } else {
1760
            $result['avatar_medium'] = $user['avatar_medium'];
1761
        }*/
1762
1763
        //$urlImg = api_get_path(WEB_IMG_PATH);
1764
        $urlImg = '/';
1765
        $iconStatus = '';
1766
        $iconStatusMedium = '';
1767
1768
        switch ($user->getStatus()) {
1769
            case STUDENT:
1770
                if ($result['has_certificates']) {
1771
                    $iconStatus = $urlImg.'icons/svg/identifier_graduated.svg';
1772
                } else {
1773
                    $iconStatus = $urlImg.'icons/svg/identifier_student.svg';
1774
                }
1775
                break;
1776
            case COURSEMANAGER:
1777
                if ($result['is_admin']) {
1778
                    $iconStatus = $urlImg.'icons/svg/identifier_admin.svg';
1779
                } else {
1780
                    $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1781
                }
1782
                break;
1783
            case STUDENT_BOSS:
1784
                $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1785
                break;
1786
        }
1787
1788
        if (!empty($iconStatus)) {
1789
            $iconStatusMedium = '<img src="'.$iconStatus.'" width="32px" height="32px">';
1790
            $iconStatus = '<img src="'.$iconStatus.'" width="22px" height="22px">';
1791
        }
1792
1793
        $result['icon_status'] = $iconStatus;
1794
        $result['icon_status_medium'] = $iconStatusMedium;
1795
    }
1796
1797
    if (isset($result['user_is_online'])) {
1798
        $result['user_is_online'] = true == $result['user_is_online'] ? 1 : 0;
1799
    }
1800
    if (isset($result['user_is_online_in_chat'])) {
1801
        $result['user_is_online_in_chat'] = (int) $result['user_is_online_in_chat'];
1802
    }
1803
1804
    $result['password'] = '';
1805
    if ($showPassword) {
1806
        $result['password'] = $user->getPassword();
1807
    }
1808
1809
    if (isset($result['profile_completed'])) {
1810
        $result['profile_completed'] = $result['profile_completed'];
1811
    }
1812
1813
    $result['profile_url'] = api_get_path(WEB_CODE_PATH).'social/profile.php?u='.$user_id;
1814
1815
    // Send message link
1816
    $sendMessage = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&user_id='.$user_id;
1817
    $result['complete_name_with_message_link'] = Display::url(
1818
        $result['complete_name_with_username'],
1819
        $sendMessage,
1820
        ['class' => 'ajax']
1821
    );
1822
1823
    if (isset($result['extra'])) {
1824
        $result['extra'] = $result['extra'];
1825
    }
1826
1827
    return $result;
1828
}
1829
1830
/**
1831
 * @param int $userId
1832
 *
1833
 * @return User
1834
 */
1835
function api_get_user_entity($userId)
1836
{
1837
    $userId = (int) $userId;
1838
    $repo = UserManager::getRepository();
1839
1840
    /** @var User $user */
1841
    $user = $repo->find($userId);
1842
1843
    return $user;
1844
}
1845
1846
/**
1847
 * @return User|null
1848
 */
1849
function api_get_current_user()
1850
{
1851
    $isLoggedIn = Container::$container->get('security.authorization_checker')->isGranted('IS_AUTHENTICATED_REMEMBERED');
1852
    if (false === $isLoggedIn) {
1853
        return null;
1854
    }
1855
1856
    $token = Container::$container->get('security.token_storage')->getToken();
1857
1858
    if (null !== $token) {
1859
        return $token->getUser();
1860
    }
1861
1862
    return null;
1863
}
1864
1865
/**
1866
 * Finds all the information about a user from username instead of user id.
1867
 *
1868
 * @param string $username
1869
 *
1870
 * @return mixed $user_info array user_id, lastname, firstname, username, email or false on error
1871
 *
1872
 * @author Yannick Warnier <[email protected]>
1873
 */
1874
function api_get_user_info_from_username($username = '')
1875
{
1876
    if (empty($username)) {
1877
        return false;
1878
    }
1879
    $username = trim($username);
1880
1881
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1882
            WHERE username='".Database::escape_string($username)."'";
1883
    $result = Database::query($sql);
1884
    if (Database::num_rows($result) > 0) {
1885
        $resultArray = Database::fetch_array($result);
1886
1887
        return _api_format_user($resultArray);
1888
    }
1889
1890
    return false;
1891
}
1892
1893
/**
1894
 * Get first user with an email.
1895
 *
1896
 * @param string $email
1897
 *
1898
 * @return array|bool
1899
 */
1900
function api_get_user_info_from_email($email = '')
1901
{
1902
    if (empty($email)) {
1903
        return false;
1904
    }
1905
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1906
            WHERE email ='".Database::escape_string($email)."' LIMIT 1";
1907
    $result = Database::query($sql);
1908
    if (Database::num_rows($result) > 0) {
1909
        $resultArray = Database::fetch_array($result);
1910
1911
        return _api_format_user($resultArray);
1912
    }
1913
1914
    return false;
1915
}
1916
1917
/**
1918
 * @return string
1919
 */
1920
function api_get_course_id()
1921
{
1922
    return Session::read('_cid', null);
1923
}
1924
1925
/**
1926
 * Returns the current course id (integer).
1927
 *
1928
 * @param string $code Optional course code
1929
 *
1930
 * @return int
1931
 */
1932
function api_get_course_int_id($code = null)
1933
{
1934
    if (!empty($code)) {
1935
        $code = Database::escape_string($code);
1936
        $row = Database::select(
1937
            'id',
1938
            Database::get_main_table(TABLE_MAIN_COURSE),
1939
            ['where' => ['code = ?' => [$code]]],
1940
            'first'
1941
        );
1942
1943
        if (is_array($row) && isset($row['id'])) {
1944
            return $row['id'];
1945
        } else {
1946
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type integer.
Loading history...
1947
        }
1948
    }
1949
1950
    return Session::read('_real_cid', 0);
1951
}
1952
1953
/**
1954
 * Returns the current course directory.
1955
 *
1956
 * This function relies on api_get_course_info()
1957
 *
1958
 * @param string    The course code - optional (takes it from session if not given)
1959
 *
1960
 * @return string The directory where the course is located inside the Chamilo "courses" directory
1961
 *
1962
 * @author Yannick Warnier <[email protected]>
1963
 */
1964
function api_get_course_path($course_code = null)
1965
{
1966
    $info = !empty($course_code) ? api_get_course_info($course_code) : api_get_course_info();
1967
1968
    return $info['path'];
1969
}
1970
1971
/**
1972
 * Gets a course setting from the current course_setting table. Try always using integer values.
1973
 *
1974
 * @param string $settingName The name of the setting we want from the table
1975
 * @param array  $courseInfo
1976
 * @param bool   $force       force checking the value in the database
1977
 *
1978
 * @return mixed The value of that setting in that table. Return -1 if not found.
1979
 */
1980
function api_get_course_setting($settingName, $courseInfo = [], $force = false)
1981
{
1982
    if (empty($courseInfo)) {
1983
        $courseInfo = api_get_course_info();
1984
    }
1985
1986
    if (empty($courseInfo) || empty($settingName)) {
1987
        return -1;
1988
    }
1989
1990
    $courseId = isset($courseInfo['real_id']) && !empty($courseInfo['real_id']) ? $courseInfo['real_id'] : 0;
1991
1992
    if (empty($courseId)) {
1993
        return -1;
1994
    }
1995
1996
    static $courseSettingInfo = [];
1997
1998
    if ($force) {
1999
        $courseSettingInfo = [];
2000
    }
2001
2002
    if (!isset($courseSettingInfo[$courseId])) {
2003
        $table = Database::get_course_table(TABLE_COURSE_SETTING);
2004
        $settingName = Database::escape_string($settingName);
2005
2006
        $sql = "SELECT variable, value FROM $table
2007
                WHERE c_id = $courseId ";
2008
        $res = Database::query($sql);
2009
        if (Database::num_rows($res) > 0) {
2010
            $result = Database::store_result($res, 'ASSOC');
2011
            $courseSettingInfo[$courseId] = array_column($result, 'value', 'variable');
2012
2013
            if (isset($courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'])) {
2014
                $value = $courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'];
2015
                if (!is_null($value)) {
2016
                    $result = explode(',', $value);
2017
                    $courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'] = $result;
2018
                }
2019
            }
2020
        }
2021
    }
2022
2023
    if (isset($courseSettingInfo[$courseId]) && isset($courseSettingInfo[$courseId][$settingName])) {
2024
        return $courseSettingInfo[$courseId][$settingName];
2025
    }
2026
2027
    return -1;
2028
}
2029
2030
/**
2031
 * Gets an anonymous user ID.
2032
 *
2033
 * For some tools that need tracking, like the learnpath tool, it is necessary
2034
 * to have a usable user-id to enable some kind of tracking, even if not
2035
 * perfect. An anonymous ID is taken from the users table by looking for a
2036
 * status of "6" (anonymous).
2037
 *
2038
 * @return int User ID of the anonymous user, or O if no anonymous user found
2039
 */
2040
function api_get_anonymous_id()
2041
{
2042
    // Find if another anon is connected now
2043
    $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
2044
    $tableU = Database::get_main_table(TABLE_MAIN_USER);
2045
    $ip = Database::escape_string(api_get_real_ip());
2046
    $max = (int) api_get_configuration_value('max_anonymous_users');
2047
    if ($max >= 2) {
2048
        $sql = "SELECT * FROM $table as TEL
2049
                JOIN $tableU as U
2050
                ON U.user_id = TEL.login_user_id
2051
                WHERE TEL.user_ip = '$ip'
2052
                    AND U.status = ".ANONYMOUS."
2053
                    AND U.user_id != 2 ";
2054
2055
        $result = Database::query($sql);
2056
        if (empty(Database::num_rows($result))) {
2057
            $login = uniqid('anon_');
2058
            $anonList = UserManager::get_user_list(['status' => ANONYMOUS], ['registration_date ASC']);
2059
            if (count($anonList) >= $max) {
2060
                foreach ($anonList as $userToDelete) {
2061
                    UserManager::delete_user($userToDelete['user_id']);
2062
                    break;
2063
                }
2064
            }
2065
            $userId = UserManager::create_user(
2066
                $login,
2067
                'anon',
2068
                ANONYMOUS,
2069
                ' anonymous@localhost',
2070
                $login,
2071
                $login
2072
            );
2073
2074
            return $userId;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $userId returns the type false which is incompatible with the documented return type integer.
Loading history...
2075
        } else {
2076
            $row = Database::fetch_array($result, 'ASSOC');
2077
2078
            return $row['user_id'];
2079
        }
2080
    }
2081
2082
    $table = Database::get_main_table(TABLE_MAIN_USER);
2083
    $sql = "SELECT user_id
2084
            FROM $table
2085
            WHERE status = ".ANONYMOUS." ";
2086
    $res = Database::query($sql);
2087
    if (Database::num_rows($res) > 0) {
2088
        $row = Database::fetch_array($res, 'ASSOC');
2089
2090
        return $row['user_id'];
2091
    }
2092
2093
    // No anonymous user was found.
2094
    return 0;
2095
}
2096
2097
/**
2098
 * @param string $courseCode
2099
 * @param int    $sessionId
2100
 * @param int    $groupId
2101
 *
2102
 * @return string
2103
 */
2104
function api_get_cidreq_params($courseCode, $sessionId = 0, $groupId = 0)
2105
{
2106
    $courseCode = !empty($courseCode) ? htmlspecialchars($courseCode) : '';
2107
    $sessionId = !empty($sessionId) ? (int) $sessionId : 0;
2108
    $groupId = !empty($groupId) ? (int) $groupId : 0;
2109
2110
    $url = 'cidReq='.$courseCode;
2111
    $url .= '&id_session='.$sessionId;
2112
    $url .= '&gidReq='.$groupId;
2113
2114
    return $url;
2115
}
2116
2117
/**
2118
 * Returns the current course url part including session, group, and gradebook params.
2119
 *
2120
 * @param bool   $addSessionId
2121
 * @param bool   $addGroupId
2122
 * @param string $origin
2123
 *
2124
 * @return string Course & session references to add to a URL
2125
 */
2126
function api_get_cidreq($addSessionId = true, $addGroupId = true, $origin = '')
2127
{
2128
    $courseId = api_get_course_int_id();
2129
    $url = empty($courseId) ? '' : 'cid='.$courseId;
2130
    $origin = empty($origin) ? api_get_origin() : Security::remove_XSS($origin);
2131
2132
    if ($addSessionId) {
2133
        if (!empty($url)) {
2134
            $url .= 0 == api_get_session_id() ? '&sid=0' : '&sid='.api_get_session_id();
2135
        }
2136
    }
2137
2138
    if ($addGroupId) {
2139
        if (!empty($url)) {
2140
            $url .= 0 == api_get_group_id() ? '&gid=0' : '&gid='.api_get_group_id();
2141
        }
2142
    }
2143
2144
    if (!empty($url)) {
2145
        $url .= '&gradebook='.(int) api_is_in_gradebook();
2146
        $url .= '&origin='.$origin;
2147
    }
2148
2149
    return $url;
2150
}
2151
2152
/**
2153
 * Get if we visited a gradebook page.
2154
 *
2155
 * @return bool
2156
 */
2157
function api_is_in_gradebook()
2158
{
2159
    return Session::read('in_gradebook', false);
2160
}
2161
2162
/**
2163
 * Set that we are in a page inside a gradebook.
2164
 */
2165
function api_set_in_gradebook()
2166
{
2167
    Session::write('in_gradebook', true);
2168
}
2169
2170
/**
2171
 * Remove gradebook session.
2172
 */
2173
function api_remove_in_gradebook()
2174
{
2175
    Session::erase('in_gradebook');
2176
}
2177
2178
/**
2179
 * Returns the current course info array see api_format_course_array()
2180
 * If the course_code is given, the returned array gives info about that
2181
 * particular course, if none given it gets the course info from the session.
2182
 *
2183
 * @param string $course_code
2184
 *
2185
 * @return array
2186
 */
2187
function api_get_course_info($course_code = null)
2188
{
2189
    if (!empty($course_code)) {
2190
        $course = Container::getCourseRepository()->findOneByCode($course_code);
2191
        if (empty($course)) {
2192
            return [];
2193
        }
2194
2195
        $courseInfo = api_format_course_array($course);
2196
2197
        return $courseInfo;
2198
    }
2199
2200
    /*$course_code = Database::escape_string($course_code);
2201
    $courseId = api_get_course_int_id($course_code);
2202
    if (empty($courseId)) {
2203
        return [];
2204
    }
2205
2206
    $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
2207
    $course_cat_table = Database::get_main_table(TABLE_MAIN_CATEGORY);
2208
    $sql = "SELECT
2209
                course.*,
2210
                course_category.code faCode,
2211
                course_category.name faName
2212
            FROM $course_table
2213
            LEFT JOIN $course_cat_table
2214
            ON course.category_code = course_category.code
2215
            WHERE course.id = $courseId";
2216
    $result = Database::query($sql);
2217
    $courseInfo = [];
2218
    if (Database::num_rows($result) > 0) {
2219
        $data = Database::fetch_array($result);
2220
        $courseInfo = api_format_course_array($data);
2221
    }
2222
2223
    return $courseInfo;*/
2224
2225
    $course = Session::read('_course');
2226
    if ('-1' == $course) {
2227
        $course = [];
2228
    }
2229
2230
    return $course;
2231
}
2232
2233
/**
2234
 * @param int $courseId
2235
 *
2236
 * @return Course
2237
 */
2238
function api_get_course_entity($courseId = 0)
2239
{
2240
    if (empty($courseId)) {
2241
        $courseId = api_get_course_int_id();
2242
    }
2243
2244
    return CourseManager::getManager()->find($courseId);
0 ignored issues
show
Deprecated Code introduced by
The function CourseManager::getManager() 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

2244
    return /** @scrutinizer ignore-deprecated */ CourseManager::getManager()->find($courseId);
Loading history...
2245
}
2246
2247
/**
2248
 * @param int $id
2249
 *
2250
 * @return SessionEntity|null
2251
 */
2252
function api_get_session_entity($id = 0)
2253
{
2254
    if (empty($id)) {
2255
        $id = api_get_session_id();
2256
    }
2257
2258
    if (empty($id)) {
2259
        return null;
2260
    }
2261
2262
    return Database::getManager()->getRepository('ChamiloCoreBundle:Session')->find($id);
2263
}
2264
2265
/**
2266
 * @param int $id
2267
 *
2268
 * @return CGroupInfo
2269
 */
2270
function api_get_group_entity($id = 0)
2271
{
2272
    if (empty($id)) {
2273
        $id = api_get_group_id();
2274
    }
2275
2276
    return Database::getManager()->getRepository('ChamiloCourseBundle:CGroupInfo')->find($id);
2277
}
2278
2279
/**
2280
 * @param int $id
2281
 *
2282
 * @return AccessUrl
2283
 */
2284
function api_get_url_entity($id = 0)
2285
{
2286
    if (empty($id)) {
2287
        $id = api_get_current_access_url_id();
2288
    }
2289
2290
    return Container::getAccessUrlRepository()->find($id);
2291
}
2292
2293
/**
2294
 * Returns the current course info array.
2295
2296
 * Now if the course_code is given, the returned array gives info about that
2297
 * particular course, not specially the current one.
2298
 *
2299
 * @param int $id Numeric ID of the course
2300
 *
2301
 * @return array The course info as an array formatted by api_format_course_array, including category.name
2302
 */
2303
function api_get_course_info_by_id($id = 0)
2304
{
2305
    $id = (int) $id;
2306
    if (empty($id)) {
2307
        $course = Session::read('_course', []);
2308
2309
        return $course;
2310
    }
2311
2312
    $course = Container::getCourseRepository()->find($id);
2313
    if (empty($course)) {
2314
        return [];
2315
    }
2316
2317
    return api_format_course_array($course);
2318
}
2319
2320
/**
2321
 * Reformat the course array (output by api_get_course_info()) in order, mostly,
2322
 * to switch from 'code' to 'id' in the array.
2323
 *
2324
 * @return array
2325
 *
2326
 * @todo eradicate the false "id"=code field of the $_course array and use the int id
2327
 */
2328
function api_format_course_array(Course $course)
2329
{
2330
    if (empty($course)) {
2331
        return [];
2332
    }
2333
2334
    $category = $course->getCategory();
2335
2336
    $courseData = [];
2337
    $courseData['categoryCode'] = '';
2338
    $courseData['categoryName'] = '';
2339
    $courseData['category_id'] = 0;
2340
    if ($category) {
0 ignored issues
show
introduced by
$category is of type Chamilo\CoreBundle\Entity\CourseCategory, thus it always evaluated to true.
Loading history...
2341
        $courseData['categoryCode'] = $category->getCode();
2342
        $courseData['categoryName'] = $category->getName();
2343
        $courseData['category_id'] = $category->getId();
2344
    }
2345
2346
    $courseData['id'] = $courseData['real_id'] = $course->getId();
2347
2348
    // Added
2349
    $courseData['code'] = $courseData['sysCode'] = $course->getCode();
2350
    $courseData['name'] = $courseData['title'] = $course->getTitle();
2351
    $courseData['official_code'] = $courseData['visual_code'] = $course->getVisualCode();
2352
    $courseData['path'] = $courseData['directory'] = $course->getDirectory(); // Use as key in path.
2353
    $courseData['creation_date'] = $course->getCreationDate()->format('Y-m-d H:i:s');
2354
    $courseData['titular'] = $course->getTutorName();
2355
    $courseData['language'] = $courseData['course_language'] = $course->getCourseLanguage();
2356
    $courseData['extLink']['url'] = $courseData['department_url'] = $course->getDepartmentUrl();
2357
    $courseData['extLink']['name'] = $courseData['department_name'] = $course->getDepartmentName();
2358
2359
    $courseData['visibility'] = $course->getVisibility();
2360
    $courseData['subscribe_allowed'] = $courseData['subscribe'] = $course->getSubscribe();
2361
    $courseData['unsubscribe'] = $course->getUnsubscribe();
2362
    $courseData['activate_legal'] = $course->getActivateLegal();
2363
    $courseData['legal'] = $course->getLegal();
2364
    $courseData['show_score'] = $course->getShowScore(); //used in the work tool
2365
2366
    $coursePath = api_get_path(WEB_COURSE_PATH);
2367
    $webCourseHome = $coursePath.$courseData['real_id'].'/home';
2368
2369
    // Course password
2370
    $courseData['registration_code'] = $course->getRegistrationCode();
2371
    $courseData['disk_quota'] = $course->getDiskQuota();
2372
    $courseData['course_public_url'] = $webCourseHome;
2373
    $courseData['about_url'] = $coursePath.$courseData['real_id'].'/about';
2374
    $courseData['add_teachers_to_sessions_courses'] = $course->isAddTeachersToSessionsCourses();
2375
    $courseData['entity'] = $course;
2376
2377
    $image = Display::return_icon(
2378
        'course.png',
2379
        null,
2380
        null,
2381
        ICON_SIZE_BIG,
2382
        null,
2383
        true,
2384
        false
2385
    );
2386
2387
    $illustration = Container::getIllustrationRepository()->getIllustrationUrl($course);
2388
    if (!empty($illustration)) {
2389
        $image = $illustration;
2390
    }
2391
2392
    $courseData['course_image'] = $image.'?filter=course_picture_small';
2393
2394
    // Course large image
2395
    /*$courseData['course_image_large_source'] = '';
2396
    if (file_exists($courseSys.'/course-pic.png')) {
2397
        $url_image = $webCourseHome.'/course-pic.png';
2398
        $courseData['course_image_large_source'] = $courseSys.'/course-pic.png';
2399
    } else {
2400
        $url_image = Display::return_icon(
2401
            'session_default.png',
2402
            null,
2403
            null,
2404
            null,
2405
            null,
2406
            true,
2407
            true
2408
        );
2409
    }*/
2410
2411
    $courseData['course_image_large'] = $image.'?filter=course_picture_medium';
2412
2413
    return $courseData;
2414
}
2415
2416
/**
2417
 * Returns a difficult to guess password.
2418
 *
2419
 * @param int $length the length of the password
2420
 *
2421
 * @return string the generated password
2422
 */
2423
function api_generate_password($length = 8)
2424
{
2425
    if ($length < 2) {
2426
        $length = 2;
2427
    }
2428
2429
    $charactersLowerCase = 'abcdefghijkmnopqrstuvwxyz';
2430
    $charactersUpperCase = 'ABCDEFGHJKLMNPQRSTUVWXYZ';
2431
    $minNumbers = 2;
2432
    $length = $length - $minNumbers;
2433
    $minLowerCase = round($length / 2);
2434
    $minUpperCase = $length - $minLowerCase;
2435
2436
    $password = '';
2437
    $passwordRequirements = api_get_configuration_value('password_requirements');
2438
2439
    $factory = new RandomLib\Factory();
2440
    $generator = $factory->getGenerator(new SecurityLib\Strength(SecurityLib\Strength::MEDIUM));
2441
2442
    if (!empty($passwordRequirements)) {
2443
        $length = $passwordRequirements['min']['length'];
2444
        $minNumbers = $passwordRequirements['min']['numeric'];
2445
        $minLowerCase = $passwordRequirements['min']['lowercase'];
2446
        $minUpperCase = $passwordRequirements['min']['uppercase'];
2447
2448
        $rest = $length - $minNumbers - $minLowerCase - $minUpperCase;
2449
        // Add the rest to fill the length requirement
2450
        if ($rest > 0) {
2451
            $password .= $generator->generateString($rest, $charactersLowerCase.$charactersUpperCase);
2452
        }
2453
    }
2454
2455
    // Min digits default 2
2456
    for ($i = 0; $i < $minNumbers; $i++) {
2457
        $password .= $generator->generateInt(2, 9);
2458
    }
2459
2460
    // Min lowercase
2461
    $password .= $generator->generateString($minLowerCase, $charactersLowerCase);
2462
2463
    // Min uppercase
2464
    $password .= $generator->generateString($minUpperCase, $charactersUpperCase);
2465
    $password = str_shuffle($password);
2466
2467
    return $password;
2468
}
2469
2470
/**
2471
 * Checks a password to see wether it is OK to use.
2472
 *
2473
 * @param string $password
2474
 *
2475
 * @return bool if the password is acceptable, false otherwise
2476
 *              Notes about what a password "OK to use" is:
2477
 *              1. The password should be at least 5 characters long.
2478
 *              2. Only English letters (uppercase or lowercase, it doesn't matter) and digits are allowed.
2479
 *              3. The password should contain at least 3 letters.
2480
 *              4. It should contain at least 2 digits.
2481
 *              Settings will change if the configuration value is set: password_requirements
2482
 */
2483
function api_check_password($password)
2484
{
2485
    $passwordRequirements = Security::getPasswordRequirements();
2486
2487
    $minLength = $passwordRequirements['min']['length'];
2488
    $minNumbers = $passwordRequirements['min']['numeric'];
2489
    // Optional
2490
    $minLowerCase = $passwordRequirements['min']['lowercase'];
2491
    $minUpperCase = $passwordRequirements['min']['uppercase'];
2492
2493
    $minLetters = $minLowerCase + $minUpperCase;
2494
    $passwordLength = api_strlen($password);
2495
2496
    $conditions = [
2497
        'min_length' => $passwordLength >= $minLength,
2498
    ];
2499
2500
    $digits = 0;
2501
    $lowerCase = 0;
2502
    $upperCase = 0;
2503
2504
    for ($i = 0; $i < $passwordLength; $i++) {
2505
        $currentCharacterCode = api_ord(api_substr($password, $i, 1));
2506
        if ($currentCharacterCode >= 65 && $currentCharacterCode <= 90) {
2507
            $upperCase++;
2508
        }
2509
2510
        if ($currentCharacterCode >= 97 && $currentCharacterCode <= 122) {
2511
            $lowerCase++;
2512
        }
2513
        if ($currentCharacterCode >= 48 && $currentCharacterCode <= 57) {
2514
            $digits++;
2515
        }
2516
    }
2517
2518
    // Min number of digits
2519
    $conditions['min_numeric'] = $digits >= $minNumbers;
2520
2521
    if (!empty($minUpperCase)) {
2522
        // Uppercase
2523
        $conditions['min_uppercase'] = $upperCase >= $minUpperCase;
2524
    }
2525
2526
    if (!empty($minLowerCase)) {
2527
        // Lowercase
2528
        $conditions['min_lowercase'] = $upperCase >= $minLowerCase;
2529
    }
2530
2531
    // Min letters
2532
    $letters = $upperCase + $lowerCase;
2533
    $conditions['min_letters'] = $letters >= $minLetters;
2534
2535
    $isPasswordOk = true;
2536
    foreach ($conditions as $condition) {
2537
        if (false === $condition) {
2538
            $isPasswordOk = false;
2539
            break;
2540
        }
2541
    }
2542
2543
    if (false === $isPasswordOk) {
2544
        $output = get_lang('The new password does not match the minimum security requirements').'<br />';
2545
        $output .= Security::getPasswordRequirementsToString($conditions);
2546
2547
        Display::addFlash(Display::return_message($output, 'warning', false));
2548
    }
2549
2550
    return $isPasswordOk;
2551
}
2552
2553
/**
2554
 * Returns the status string corresponding to the status code.
2555
 *
2556
 * @author Noel Dieschburg
2557
 *
2558
 * @param the int status code
2559
 *
2560
 * @return string
2561
 */
2562
function get_status_from_code($status_code)
2563
{
2564
    switch ($status_code) {
2565
        case STUDENT:
2566
            return get_lang('Student', '');
2567
        case COURSEMANAGER:
2568
            return get_lang('Teacher', '');
2569
        case SESSIONADMIN:
2570
            return get_lang('SessionsAdmin', '');
2571
        case DRH:
2572
            return get_lang('Drh', '');
2573
    }
2574
}
2575
2576
/**
2577
 * Gets the current Chamilo (not PHP/cookie) session ID.
2578
 *
2579
 * @return int O if no active session, the session ID otherwise
2580
 */
2581
function api_get_session_id()
2582
{
2583
    return (int) Session::read('sid', 0);
2584
}
2585
2586
/**
2587
 * Gets the current Chamilo (not social network) group ID.
2588
 *
2589
 * @return int O if no active session, the session ID otherwise
2590
 */
2591
function api_get_group_id()
2592
{
2593
    return Session::read('gid', 0);
2594
}
2595
2596
/**
2597
 * Gets the current or given session name.
2598
 *
2599
 * @param   int     Session ID (optional)
2600
 *
2601
 * @return string The session name, or null if not found
2602
 */
2603
function api_get_session_name($session_id = 0)
2604
{
2605
    if (empty($session_id)) {
2606
        $session_id = api_get_session_id();
2607
        if (empty($session_id)) {
2608
            return null;
2609
        }
2610
    }
2611
    $t = Database::get_main_table(TABLE_MAIN_SESSION);
2612
    $s = "SELECT name FROM $t WHERE id = ".(int) $session_id;
2613
    $r = Database::query($s);
2614
    $c = Database::num_rows($r);
2615
    if ($c > 0) {
2616
        //technically, there can be only one, but anyway we take the first
2617
        $rec = Database::fetch_array($r);
2618
2619
        return $rec['name'];
2620
    }
2621
2622
    return null;
2623
}
2624
2625
/**
2626
 * Gets the session info by id.
2627
 *
2628
 * @param int $id Session ID
2629
 *
2630
 * @return array information of the session
2631
 */
2632
function api_get_session_info($id)
2633
{
2634
    return SessionManager::fetch($id);
2635
}
2636
2637
/**
2638
 * Gets the session visibility by session id.
2639
 *
2640
 * @param int  $session_id
2641
 * @param int  $courseId
2642
 * @param bool $ignore_visibility_for_admins
2643
 *
2644
 * @return int
2645
 *             0 = session still available,
2646
 *             SESSION_VISIBLE_READ_ONLY = 1,
2647
 *             SESSION_VISIBLE = 2,
2648
 *             SESSION_INVISIBLE = 3
2649
 */
2650
function api_get_session_visibility(
2651
    $session_id,
2652
    $courseId = null,
2653
    $ignore_visibility_for_admins = true
2654
) {
2655
    if (api_is_platform_admin()) {
2656
        if ($ignore_visibility_for_admins) {
2657
            return SESSION_AVAILABLE;
2658
        }
2659
    }
2660
2661
    $now = time();
2662
    if (empty($session_id)) {
2663
        return 0; // Means that the session is still available.
2664
    }
2665
2666
    $session_id = (int) $session_id;
2667
    $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
2668
2669
    $result = Database::query("SELECT * FROM $tbl_session WHERE id = $session_id");
2670
2671
    if (Database::num_rows($result) <= 0) {
2672
        return SESSION_INVISIBLE;
2673
    }
2674
2675
    $row = Database::fetch_array($result, 'ASSOC');
2676
    $visibility = $original_visibility = $row['visibility'];
2677
2678
    // I don't care the session visibility.
2679
    if (empty($row['access_start_date']) && empty($row['access_end_date'])) {
2680
        // Session duration per student.
2681
        if (isset($row['duration']) && !empty($row['duration'])) {
2682
            $duration = $row['duration'] * 24 * 60 * 60;
2683
            $courseAccess = CourseManager::getFirstCourseAccessPerSessionAndUser($session_id, api_get_user_id());
2684
2685
            // If there is a session duration but there is no previous
2686
            // access by the user, then the session is still available
2687
            if (0 == count($courseAccess)) {
2688
                return SESSION_AVAILABLE;
2689
            }
2690
2691
            $currentTime = time();
2692
            $firstAccess = isset($courseAccess['login_course_date'])
2693
                ? api_strtotime($courseAccess['login_course_date'], 'UTC')
2694
                : 0;
2695
            $userDurationData = SessionManager::getUserSession(
2696
                api_get_user_id(),
2697
                $session_id
2698
            );
2699
            $userDuration = isset($userDurationData['duration'])
2700
                ? (intval($userDurationData['duration']) * 24 * 60 * 60)
2701
                : 0;
2702
2703
            $totalDuration = $firstAccess + $duration + $userDuration;
2704
2705
            return $totalDuration > $currentTime ? SESSION_AVAILABLE : SESSION_VISIBLE_READ_ONLY;
2706
        }
2707
2708
        return SESSION_AVAILABLE;
2709
    }
2710
2711
    // If start date was set.
2712
    if (!empty($row['access_start_date'])) {
2713
        $visibility = $now > api_strtotime($row['access_start_date'], 'UTC') ? SESSION_AVAILABLE : SESSION_INVISIBLE;
2714
    }
2715
2716
    // If the end date was set.
2717
    if (!empty($row['access_end_date'])) {
2718
        // Only if date_start said that it was ok
2719
        if (SESSION_AVAILABLE === $visibility) {
2720
            $visibility = $now < api_strtotime($row['access_end_date'], 'UTC')
2721
                ? SESSION_AVAILABLE // Date still available
2722
                : $row['visibility']; // Session ends
2723
        }
2724
    }
2725
2726
    // If I'm a coach the visibility can change in my favor depending in the coach dates.
2727
    $isCoach = api_is_coach($session_id, $courseId);
2728
2729
    if ($isCoach) {
2730
        // Test start date.
2731
        if (!empty($row['coach_access_start_date'])) {
2732
            $start = api_strtotime($row['coach_access_start_date'], 'UTC');
2733
            $visibility = $start < $now ? SESSION_AVAILABLE : SESSION_INVISIBLE;
2734
        }
2735
2736
        // Test end date.
2737
        if (!empty($row['coach_access_end_date'])) {
2738
            if (SESSION_AVAILABLE === $visibility) {
2739
                $endDateCoach = api_strtotime($row['coach_access_end_date'], 'UTC');
2740
                $visibility = $endDateCoach >= $now ? SESSION_AVAILABLE : $row['visibility'];
2741
            }
2742
        }
2743
    }
2744
2745
    return $visibility;
2746
}
2747
2748
/**
2749
 * This function returns a (star) session icon if the session is not null and
2750
 * the user is not a student.
2751
 *
2752
 * @param int $sessionId
2753
 * @param int $statusId  User status id - if 5 (student), will return empty
2754
 *
2755
 * @return string Session icon
2756
 */
2757
function api_get_session_image($sessionId, $statusId)
2758
{
2759
    $sessionId = (int) $sessionId;
2760
    $image = '';
2761
    if (STUDENT != $statusId) {
2762
        // Check whether is not a student
2763
        if ($sessionId > 0) {
2764
            $image = '&nbsp;&nbsp;'.Display::return_icon(
2765
                'star.png',
2766
                get_lang('Session-specific resource'),
2767
                ['align' => 'absmiddle'],
2768
                ICON_SIZE_SMALL
2769
            );
2770
        }
2771
    }
2772
2773
    return $image;
2774
}
2775
2776
/**
2777
 * This function add an additional condition according to the session of the course.
2778
 *
2779
 * @param int    $session_id        session id
2780
 * @param bool   $and               optional, true if more than one condition false if the only condition in the query
2781
 * @param bool   $with_base_content optional, true to accept content with session=0 as well,
2782
 *                                  false for strict session condition
2783
 * @param string $session_field
2784
 *
2785
 * @return string condition of the session
2786
 */
2787
function api_get_session_condition(
2788
    $session_id,
2789
    $and = true,
2790
    $with_base_content = false,
2791
    $session_field = 'session_id'
2792
) {
2793
    $session_id = (int) $session_id;
2794
2795
    if (empty($session_field)) {
2796
        $session_field = 'session_id';
2797
    }
2798
    // Condition to show resources by session
2799
    $condition_add = $and ? ' AND ' : ' WHERE ';
2800
2801
    if ($with_base_content) {
2802
        $condition_session = $condition_add." ( $session_field = $session_id OR $session_field = 0 OR $session_field IS NULL) ";
2803
    } else {
2804
        if (empty($session_id)) {
2805
            $condition_session = $condition_add." ($session_field = $session_id OR $session_field IS NULL)";
2806
        } else {
2807
            $condition_session = $condition_add." $session_field = $session_id ";
2808
        }
2809
    }
2810
2811
    return $condition_session;
2812
}
2813
2814
/**
2815
 * Returns the value of a setting from the web-adjustable admin config settings.
2816
 *
2817
 * WARNING true/false are stored as string, so when comparing you need to check e.g.
2818
 * if (api_get_setting('show_navigation_menu') == 'true') //CORRECT
2819
 * instead of
2820
 * if (api_get_setting('show_navigation_menu') == true) //INCORRECT
2821
 *
2822
 * @param string $variable The variable name
2823
 *
2824
 * @return string
2825
 */
2826
function api_get_setting($variable)
2827
{
2828
    $settingsManager = Container::getSettingsManager();
2829
    if (empty($settingsManager)) {
2830
        return '';
2831
    }
2832
    $variable = trim($variable);
2833
2834
    switch ($variable) {
2835
        /*case 'header_extra_content':
2836
            $filename = api_get_path(SYS_PATH).api_get_home_path().'header_extra_content.txt';
2837
            if (file_exists($filename)) {
2838
                $value = file_get_contents($filename);
2839
2840
                return $value;
2841
            } else {
2842
                return '';
2843
            }
2844
            break;
2845
        case 'footer_extra_content':
2846
            $filename = api_get_path(SYS_PATH).api_get_home_path().'footer_extra_content.txt';
2847
            if (file_exists($filename)) {
2848
                $value = file_get_contents($filename);
2849
2850
                return $value;
2851
            } else {
2852
                return '';
2853
            }
2854
            break;*/
2855
        case 'server_type':
2856
            $test = ['dev', 'test'];
2857
            $environment = Container::getEnvironment();
2858
            if (in_array($environment, $test)) {
2859
                return 'test';
2860
            }
2861
2862
            return 'prod';
2863
        case 'stylesheets':
2864
            $variable = 'platform.theme';
2865
        // deprecated settings
2866
        // no break
2867
        case 'openid_authentication':
2868
        case 'service_ppt2lp':
2869
        case 'formLogin_hide_unhide_label':
2870
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type string.
Loading history...
2871
            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...
2872
        case 'tool_visible_by_default_at_creation':
2873
            $values = $settingsManager->getSetting($variable);
2874
            $newResult = [];
2875
            foreach ($values as $parameter) {
2876
                $newResult[$parameter] = 'true';
2877
            }
2878
2879
            return $newResult;
2880
            break;
2881
        default:
2882
            return $settingsManager->getSetting($variable);
2883
            break;
2884
    }
2885
2886
    global $_setting;
0 ignored issues
show
Unused Code introduced by
GlobalNode is not reachable.

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

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

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

    return false;
}

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

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

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

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

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

Loading history...
3848
    $message = null,
0 ignored issues
show
Unused Code introduced by
The parameter $message is not used and could be removed. ( Ignorable by Annotation )

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

3848
    /** @scrutinizer ignore-unused */ $message = null,

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

Loading history...
3849
    $responseCode = 0
0 ignored issues
show
Unused Code introduced by
The parameter $responseCode is not used and could be removed. ( Ignorable by Annotation )

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

3849
    /** @scrutinizer ignore-unused */ $responseCode = 0

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

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

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

5281
            $files = copyr("$source/$entry", "$dest/$entry", $exclude, /** @scrutinizer ignore-type */ $copied_files);
Loading history...
5282
        }
5283
    }
5284
    // Clean up.
5285
    $dir->close();
5286
5287
    return true;
5288
}
5289
5290
/**
5291
 * @todo: Using DIRECTORY_SEPARATOR is not recommended, this is an obsolete approach.
5292
 * Documentation header to be added here.
5293
 *
5294
 * @param string $pathname
5295
 * @param string $base_path_document
5296
 * @param int    $session_id
5297
 *
5298
 * @return mixed True if directory already exists, false if a file already exists at
5299
 *               the destination and null if everything goes according to plan
5300
 */
5301
function copy_folder_course_session(
5302
    $pathname,
5303
    $base_path_document,
5304
    $session_id,
5305
    $course_info,
5306
    $document,
5307
    $source_course_id
5308
) {
5309
    $table = Database::get_course_table(TABLE_DOCUMENT);
5310
    $session_id = intval($session_id);
5311
    $source_course_id = intval($source_course_id);
5312
5313
    // Check whether directory already exists.
5314
    if (is_dir($pathname) || empty($pathname)) {
5315
        return true;
5316
    }
5317
5318
    // Ensure that a file with the same name does not already exist.
5319
    if (is_file($pathname)) {
5320
        trigger_error('copy_folder_course_session(): File exists', E_USER_WARNING);
5321
5322
        return false;
5323
    }
5324
5325
    $course_id = $course_info['real_id'];
5326
    $folders = explode(DIRECTORY_SEPARATOR, str_replace($base_path_document.DIRECTORY_SEPARATOR, '', $pathname));
5327
    $new_pathname = $base_path_document;
5328
    $path = '';
5329
5330
    foreach ($folders as $folder) {
5331
        $new_pathname .= DIRECTORY_SEPARATOR.$folder;
5332
        $path .= DIRECTORY_SEPARATOR.$folder;
5333
5334
        if (!file_exists($new_pathname)) {
5335
            $path = Database::escape_string($path);
5336
5337
            $sql = "SELECT * FROM $table
5338
                    WHERE
5339
                        c_id = $source_course_id AND
5340
                        path = '$path' AND
5341
                        filetype = 'folder' AND
5342
                        session_id = '$session_id'";
5343
            $rs1 = Database::query($sql);
5344
            $num_rows = Database::num_rows($rs1);
5345
5346
            if (0 == $num_rows) {
5347
                mkdir($new_pathname, api_get_permissions_for_new_directories());
5348
5349
                // Insert new folder with destination session_id.
5350
                $params = [
5351
                    'c_id' => $course_id,
5352
                    'path' => $path,
5353
                    'comment' => $document->comment,
5354
                    'title' => basename($new_pathname),
5355
                    'filetype' => 'folder',
5356
                    'size' => '0',
5357
                    'session_id' => $session_id,
5358
                ];
5359
                $document_id = Database::insert($table, $params);
5360
                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...
5361
                    $sql = "UPDATE $table SET id = iid WHERE iid = $document_id";
5362
                    Database::query($sql);
5363
5364
                    api_item_property_update(
5365
                        $course_info,
5366
                        TOOL_DOCUMENT,
5367
                        $document_id,
5368
                        'FolderCreated',
5369
                        api_get_user_id(),
5370
                        0,
5371
                        0,
5372
                        null,
5373
                        null,
5374
                        $session_id
5375
                    );
5376
                }
5377
            }
5378
        }
5379
    } // en foreach
5380
}
5381
5382
// TODO: chmodr() is a better name. Some corrections are needed. Documentation header to be added here.
5383
/**
5384
 * @param string $path
5385
 */
5386
function api_chmod_R($path, $filemode)
5387
{
5388
    if (!is_dir($path)) {
5389
        return chmod($path, $filemode);
5390
    }
5391
5392
    $handler = opendir($path);
5393
    while ($file = readdir($handler)) {
0 ignored issues
show
Bug introduced by
It seems like $handler can also be of type false; however, parameter $dir_handle of readdir() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

5393
    while ($file = readdir(/** @scrutinizer ignore-type */ $handler)) {
Loading history...
5394
        if ('.' != $file && '..' != $file) {
5395
            $fullpath = "$path/$file";
5396
            if (!is_dir($fullpath)) {
5397
                if (!chmod($fullpath, $filemode)) {
5398
                    return false;
5399
                }
5400
            } else {
5401
                if (!api_chmod_R($fullpath, $filemode)) {
5402
                    return false;
5403
                }
5404
            }
5405
        }
5406
    }
5407
5408
    closedir($handler);
0 ignored issues
show
Bug introduced by
It seems like $handler can also be of type false; however, parameter $dir_handle of closedir() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

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

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

5509
            $last = array_pop(/** @scrutinizer ignore-type */ $keys);
Loading history...
5510
            $parent = &$info;
5511
5512
            // Create nested arrays.
5513
            foreach ($keys as $key) {
5514
                if ('' == $key) {
5515
                    $key = count($parent);
5516
                }
5517
                if (!isset($parent[$key]) || !is_array($parent[$key])) {
5518
                    $parent[$key] = [];
5519
                }
5520
                $parent = &$parent[$key];
5521
            }
5522
5523
            // Handle PHP constants.
5524
            if (defined($value)) {
5525
                $value = constant($value);
5526
            }
5527
5528
            // Insert actual value.
5529
            if ('' == $last) {
5530
                $last = count($parent);
5531
            }
5532
            $parent[$last] = $value;
5533
        }
5534
    }
5535
5536
    return $info;
5537
}
5538
5539
/**
5540
 * Gets Chamilo version from the configuration files.
5541
 *
5542
 * @return string A string of type "1.8.4", or an empty string if the version could not be found
5543
 */
5544
function api_get_version()
5545
{
5546
    return (string) api_get_configuration_value('system_version');
5547
}
5548
5549
/**
5550
 * Gets the software name (the name/brand of the Chamilo-based customized system).
5551
 *
5552
 * @return string
5553
 */
5554
function api_get_software_name()
5555
{
5556
    $name = api_get_configuration_value('software_name');
5557
    if (!empty($name)) {
5558
        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...
5559
    } else {
5560
        return 'Chamilo';
5561
    }
5562
}
5563
5564
function api_get_status_list()
5565
{
5566
    $list = [];
5567
    // Table of status
5568
    $list[COURSEMANAGER] = 'teacher'; // 1
5569
    $list[SESSIONADMIN] = 'session_admin'; // 3
5570
    $list[DRH] = 'drh'; // 4
5571
    $list[STUDENT] = 'user'; // 5
5572
    $list[ANONYMOUS] = 'anonymous'; // 6
5573
    $list[INVITEE] = 'invited'; // 20
5574
5575
    return $list;
5576
}
5577
5578
/**
5579
 * Checks whether status given in parameter exists in the platform.
5580
 *
5581
 * @param mixed the status (can be either int either string)
5582
 *
5583
 * @return bool if the status exists, else returns false
5584
 */
5585
function api_status_exists($status_asked)
5586
{
5587
    $list = api_get_status_list();
5588
5589
    return in_array($status_asked, $list) ? true : isset($list[$status_asked]);
5590
}
5591
5592
/**
5593
 * Checks whether status given in parameter exists in the platform. The function
5594
 * returns the status ID or false if it does not exist, but given the fact there
5595
 * is no "0" status, the return value can be checked against
5596
 * if(api_status_key()) to know if it exists.
5597
 *
5598
 * @param   mixed   The status (can be either int or string)
5599
 *
5600
 * @return mixed Status ID if exists, false otherwise
5601
 */
5602
function api_status_key($status)
5603
{
5604
    $list = api_get_status_list();
5605
5606
    return isset($list[$status]) ? $status : array_search($status, $list);
5607
}
5608
5609
/**
5610
 * Gets the status langvars list.
5611
 *
5612
 * @return string[] the list of status with their translations
5613
 */
5614
function api_get_status_langvars()
5615
{
5616
    return [
5617
        COURSEMANAGER => get_lang('Teacher'),
5618
        SESSIONADMIN => get_lang('SessionsAdmin'),
5619
        DRH => get_lang('Human Resources Manager'),
5620
        STUDENT => get_lang('Learner'),
5621
        ANONYMOUS => get_lang('Anonymous'),
5622
        STUDENT_BOSS => get_lang('RoleStudentBoss'),
5623
        INVITEE => get_lang('Invited'),
5624
    ];
5625
}
5626
5627
/**
5628
 * The function that retrieves all the possible settings for a certain config setting.
5629
 *
5630
 * @author Patrick Cool <[email protected]>, Ghent University
5631
 */
5632
function api_get_settings_options($var)
5633
{
5634
    $table_settings_options = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
5635
    $var = Database::escape_string($var);
5636
    $sql = "SELECT * FROM $table_settings_options
5637
            WHERE variable = '$var'
5638
            ORDER BY id";
5639
    $result = Database::query($sql);
5640
    $settings_options_array = [];
5641
    while ($row = Database::fetch_array($result, 'ASSOC')) {
5642
        $settings_options_array[] = $row;
5643
    }
5644
5645
    return $settings_options_array;
5646
}
5647
5648
/**
5649
 * @param array $params
5650
 */
5651
function api_set_setting_option($params)
5652
{
5653
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
5654
    if (empty($params['id'])) {
5655
        Database::insert($table, $params);
5656
    } else {
5657
        Database::update($table, $params, ['id = ? ' => $params['id']]);
5658
    }
5659
}
5660
5661
/**
5662
 * @param array $params
5663
 */
5664
function api_set_setting_simple($params)
5665
{
5666
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5667
    $url_id = api_get_current_access_url_id();
5668
5669
    if (empty($params['id'])) {
5670
        $params['access_url'] = $url_id;
5671
        Database::insert($table, $params);
5672
    } else {
5673
        Database::update($table, $params, ['id = ? ' => [$params['id']]]);
5674
    }
5675
}
5676
5677
/**
5678
 * @param int $id
5679
 */
5680
function api_delete_setting_option($id)
5681
{
5682
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
5683
    if (!empty($id)) {
5684
        Database::delete($table, ['id = ? ' => $id]);
5685
    }
5686
}
5687
5688
/**
5689
 * Sets a platform configuration setting to a given value.
5690
 *
5691
 * @param string    The variable we want to update
5692
 * @param string    The value we want to record
5693
 * @param string    The sub-variable if any (in most cases, this will remain null)
5694
 * @param string    The category if any (in most cases, this will remain null)
5695
 * @param int       The access_url for which this parameter is valid
5696
 * @param string $cat
5697
 *
5698
 * @return bool|null
5699
 */
5700
function api_set_setting($var, $value, $subvar = null, $cat = null, $access_url = 1)
5701
{
5702
    if (empty($var)) {
5703
        return false;
5704
    }
5705
    $t_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5706
    $var = Database::escape_string($var);
5707
    $value = Database::escape_string($value);
5708
    $access_url = (int) $access_url;
5709
    if (empty($access_url)) {
5710
        $access_url = 1;
5711
    }
5712
    $select = "SELECT id FROM $t_settings WHERE variable = '$var' ";
5713
    if (!empty($subvar)) {
5714
        $subvar = Database::escape_string($subvar);
5715
        $select .= " AND subkey = '$subvar'";
5716
    }
5717
    if (!empty($cat)) {
5718
        $cat = Database::escape_string($cat);
5719
        $select .= " AND category = '$cat'";
5720
    }
5721
    if ($access_url > 1) {
5722
        $select .= " AND access_url = $access_url";
5723
    } else {
5724
        $select .= " AND access_url = 1 ";
5725
    }
5726
5727
    $res = Database::query($select);
5728
    if (Database::num_rows($res) > 0) {
5729
        // Found item for this access_url.
5730
        $row = Database::fetch_array($res);
5731
        $sql = "UPDATE $t_settings SET selected_value = '$value'
5732
                WHERE id = ".$row['id'];
5733
        Database::query($sql);
5734
    } else {
5735
        // Item not found for this access_url, we have to check if it exist with access_url = 1
5736
        $select = "SELECT * FROM $t_settings
5737
                   WHERE variable = '$var' AND access_url = 1 ";
5738
        // Just in case
5739
        if (1 == $access_url) {
5740
            if (!empty($subvar)) {
5741
                $select .= " AND subkey = '$subvar'";
5742
            }
5743
            if (!empty($cat)) {
5744
                $select .= " AND category = '$cat'";
5745
            }
5746
            $res = Database::query($select);
5747
            if (Database::num_rows($res) > 0) {
5748
                // We have a setting for access_url 1, but none for the current one, so create one.
5749
                $row = Database::fetch_array($res);
5750
                $insert = "INSERT INTO $t_settings (variable, subkey, type,category, selected_value, title, comment, scope, subkeytext, access_url)
5751
                        VALUES
5752
                        ('".$row['variable']."',".(!empty($row['subkey']) ? "'".$row['subkey']."'" : "NULL").",".
5753
                    "'".$row['type']."','".$row['category']."',".
5754
                    "'$value','".$row['title']."',".
5755
                    "".(!empty($row['comment']) ? "'".$row['comment']."'" : "NULL").",".(!empty($row['scope']) ? "'".$row['scope']."'" : "NULL").",".
5756
                    "".(!empty($row['subkeytext']) ? "'".$row['subkeytext']."'" : "NULL").",$access_url)";
5757
                Database::query($insert);
5758
            } else {
5759
                // Such a setting does not exist.
5760
                //error_log(__FILE__.':'.__LINE__.': Attempting to update setting '.$var.' ('.$subvar.') which does not exist at all', 0);
5761
            }
5762
        } else {
5763
            // Other access url.
5764
            if (!empty($subvar)) {
5765
                $select .= " AND subkey = '$subvar'";
5766
            }
5767
            if (!empty($cat)) {
5768
                $select .= " AND category = '$cat'";
5769
            }
5770
            $res = Database::query($select);
5771
5772
            if (Database::num_rows($res) > 0) {
5773
                // We have a setting for access_url 1, but none for the current one, so create one.
5774
                $row = Database::fetch_array($res);
5775
                if (1 == $row['access_url_changeable']) {
5776
                    $insert = "INSERT INTO $t_settings (variable,subkey, type,category, selected_value,title, comment,scope, subkeytext,access_url, access_url_changeable) VALUES
5777
                            ('".$row['variable']."',".
5778
                        (!empty($row['subkey']) ? "'".$row['subkey']."'" : "NULL").",".
5779
                        "'".$row['type']."','".$row['category']."',".
5780
                        "'$value','".$row['title']."',".
5781
                        "".(!empty($row['comment']) ? "'".$row['comment']."'" : "NULL").",".
5782
                        (!empty($row['scope']) ? "'".$row['scope']."'" : "NULL").",".
5783
                        "".(!empty($row['subkeytext']) ? "'".$row['subkeytext']."'" : "NULL").",$access_url,".$row['access_url_changeable'].")";
5784
                    Database::query($insert);
5785
                }
5786
            } else { // Such a setting does not exist.
5787
                //error_log(__FILE__.':'.__LINE__.': Attempting to update setting '.$var.' ('.$subvar.') which does not exist at all. The access_url is: '.$access_url.' ',0);
5788
            }
5789
        }
5790
    }
5791
}
5792
5793
/**
5794
 * Sets a whole category of settings to one specific value.
5795
 *
5796
 * @param string    Category
5797
 * @param string    Value
5798
 * @param int       Access URL. Optional. Defaults to 1
5799
 * @param array     Optional array of filters on field type
5800
 * @param string $category
5801
 * @param string $value
5802
 *
5803
 * @return bool
5804
 */
5805
function api_set_settings_category($category, $value = null, $access_url = 1, $fieldtype = [])
5806
{
5807
    if (empty($category)) {
5808
        return false;
5809
    }
5810
    $category = Database::escape_string($category);
5811
    $t_s = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5812
    $access_url = (int) $access_url;
5813
    if (empty($access_url)) {
5814
        $access_url = 1;
5815
    }
5816
    if (isset($value)) {
5817
        $value = Database::escape_string($value);
5818
        $sql = "UPDATE $t_s SET selected_value = '$value'
5819
                WHERE category = '$category' AND access_url = $access_url";
5820
        if (is_array($fieldtype) && count($fieldtype) > 0) {
5821
            $sql .= " AND ( ";
5822
            $i = 0;
5823
            foreach ($fieldtype as $type) {
5824
                if ($i > 0) {
5825
                    $sql .= ' OR ';
5826
                }
5827
                $type = Database::escape_string($type);
5828
                $sql .= " type='".$type."' ";
5829
                $i++;
5830
            }
5831
            $sql .= ")";
5832
        }
5833
        $res = Database::query($sql);
5834
5835
        return false !== $res;
5836
    } else {
5837
        $sql = "UPDATE $t_s SET selected_value = NULL
5838
                WHERE category = '$category' AND access_url = $access_url";
5839
        if (is_array($fieldtype) && count($fieldtype) > 0) {
5840
            $sql .= " AND ( ";
5841
            $i = 0;
5842
            foreach ($fieldtype as $type) {
5843
                if ($i > 0) {
5844
                    $sql .= ' OR ';
5845
                }
5846
                $type = Database::escape_string($type);
5847
                $sql .= " type='".$type."' ";
5848
                $i++;
5849
            }
5850
            $sql .= ")";
5851
        }
5852
        $res = Database::query($sql);
5853
5854
        return false !== $res;
5855
    }
5856
}
5857
5858
/**
5859
 * Gets all available access urls in an array (as in the database).
5860
 *
5861
 * @return array An array of database records
5862
 */
5863
function api_get_access_urls($from = 0, $to = 1000000, $order = 'url', $direction = 'ASC')
5864
{
5865
    $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5866
    $from = (int) $from;
5867
    $to = (int) $to;
5868
    $order = Database::escape_string($order, null, false);
5869
    $direction = Database::escape_string($direction, null, false);
5870
    $sql = "SELECT id, url, description, active, created_by, tms
5871
            FROM $table
5872
            ORDER BY $order $direction
5873
            LIMIT $to OFFSET $from";
5874
    $res = Database::query($sql);
5875
5876
    return Database::store_result($res);
5877
}
5878
5879
/**
5880
 * Gets the access url info in an array.
5881
 *
5882
 * @param int  $id            Id of the access url
5883
 * @param bool $returnDefault Set to false if you want the real URL if URL 1 is still 'http://localhost/'
5884
 *
5885
 * @return array All the info (url, description, active, created_by, tms)
5886
 *               from the access_url table
5887
 *
5888
 * @author Julio Montoya
5889
 */
5890
function api_get_access_url($id, $returnDefault = true)
5891
{
5892
    static $staticResult;
5893
    $id = (int) $id;
5894
5895
    if (isset($staticResult[$id])) {
5896
        $result = $staticResult[$id];
5897
    } else {
5898
        // Calling the Database:: library dont work this is handmade.
5899
        $table_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5900
        $sql = "SELECT url, description, active, created_by, tms
5901
                FROM $table_access_url WHERE id = '$id' ";
5902
        $res = Database::query($sql);
5903
        $result = @Database::fetch_array($res);
5904
        $staticResult[$id] = $result;
5905
    }
5906
5907
    // If the result url is 'http://localhost/' (the default) and the root_web
5908
    // (=current url) is different, and the $id is = 1 (which might mean
5909
    // api_get_current_access_url_id() returned 1 by default), then return the
5910
    // root_web setting instead of the current URL
5911
    // This is provided as an option to avoid breaking the storage of URL-specific
5912
    // homepages in home/localhost/
5913
    if (1 === $id && false === $returnDefault) {
5914
        $currentUrl = api_get_current_access_url_id();
5915
        // only do this if we are on the main URL (=1), otherwise we could get
5916
        // information on another URL instead of the one asked as parameter
5917
        if (1 === $currentUrl) {
5918
            $rootWeb = api_get_path(WEB_PATH);
5919
            $default = 'http://localhost/';
5920
            if ($result['url'] === $default && $rootWeb != $default) {
5921
                $result['url'] = $rootWeb;
5922
            }
5923
        }
5924
    }
5925
5926
    return $result;
5927
}
5928
5929
/**
5930
 * Gets all the current settings for a specific access url.
5931
 *
5932
 * @param string    The category, if any, that we want to get
5933
 * @param string    Whether we want a simple list (display a category) or
5934
 * a grouped list (group by variable as in settings.php default). Values: 'list' or 'group'
5935
 * @param int       Access URL's ID. Optional. Uses 1 by default, which is the unique URL
5936
 *
5937
 * @return array Array of database results for the current settings of the current access URL
5938
 */
5939
function &api_get_settings($cat = null, $ordering = 'list', $access_url = 1, $url_changeable = 0)
5940
{
5941
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5942
    $access_url = (int) $access_url;
5943
    $where_condition = '';
5944
    if (1 == $url_changeable) {
5945
        $where_condition = " AND access_url_changeable= '1' ";
5946
    }
5947
    if (empty($access_url) || -1 == $access_url) {
5948
        $access_url = 1;
5949
    }
5950
    $sql = "SELECT * FROM $table
5951
            WHERE access_url = $access_url  $where_condition ";
5952
5953
    if (!empty($cat)) {
5954
        $cat = Database::escape_string($cat);
5955
        $sql .= " AND category='$cat' ";
5956
    }
5957
    if ('group' == $ordering) {
5958
        $sql .= " ORDER BY id ASC";
5959
    } else {
5960
        $sql .= " ORDER BY 1,2 ASC";
5961
    }
5962
    $result = Database::query($sql);
5963
    if (null === $result) {
5964
        return [];
5965
    }
5966
    $result = Database::store_result($result, 'ASSOC');
5967
5968
    return $result;
5969
}
5970
5971
/**
5972
 * @param string $value       The value we want to record
5973
 * @param string $variable    The variable name we want to insert
5974
 * @param string $subKey      The subkey for the variable we want to insert
5975
 * @param string $type        The type for the variable we want to insert
5976
 * @param string $category    The category for the variable we want to insert
5977
 * @param string $title       The title
5978
 * @param string $comment     The comment
5979
 * @param string $scope       The scope
5980
 * @param string $subKeyText  The subkey text
5981
 * @param int    $accessUrlId The access_url for which this parameter is valid
5982
 * @param int    $visibility  The changeability of this setting for non-master urls
5983
 *
5984
 * @return int The setting ID
5985
 */
5986
function api_add_setting(
5987
    $value,
5988
    $variable,
5989
    $subKey = '',
5990
    $type = 'textfield',
5991
    $category = '',
5992
    $title = '',
5993
    $comment = '',
5994
    $scope = '',
5995
    $subKeyText = '',
5996
    $accessUrlId = 1,
5997
    $visibility = 0
5998
) {
5999
    $em = Database::getManager();
6000
    $settingRepo = $em->getRepository('ChamiloCoreBundle:SettingsCurrent');
6001
    $accessUrlId = (int) $accessUrlId ?: 1;
6002
6003
    if (is_array($value)) {
6004
        $value = serialize($value);
6005
    } else {
6006
        $value = trim($value);
6007
    }
6008
6009
    $criteria = ['variable' => $variable, 'url' => $accessUrlId];
6010
6011
    if (!empty($subKey)) {
6012
        $criteria['subkey'] = $subKey;
6013
    }
6014
6015
    // Check if this variable doesn't exist already
6016
    /** @var SettingsCurrent $setting */
6017
    $setting = $settingRepo->findOneBy($criteria);
6018
6019
    if ($setting) {
0 ignored issues
show
introduced by
$setting is of type Chamilo\CoreBundle\Entity\SettingsCurrent, thus it always evaluated to true.
Loading history...
6020
        $setting->setSelectedValue($value);
6021
6022
        $em->persist($setting);
6023
        $em->flush();
6024
6025
        return $setting->getId();
6026
    }
6027
6028
    // Item not found for this access_url, we have to check if the whole thing is missing
6029
    // (in which case we ignore the insert) or if there *is* a record but just for access_url = 1
6030
    $setting = new SettingsCurrent();
6031
    $url = api_get_url_entity();
6032
6033
    $setting
6034
        ->setVariable($variable)
6035
        ->setSelectedValue($value)
6036
        ->setType($type)
6037
        ->setCategory($category)
6038
        ->setSubkey($subKey)
6039
        ->setTitle($title)
6040
        ->setComment($comment)
6041
        ->setScope($scope)
6042
        ->setSubkeytext($subKeyText)
6043
        ->setUrl(api_get_url_entity())
6044
        ->setAccessUrlChangeable($visibility);
6045
6046
    $em->persist($setting);
6047
    $em->flush();
6048
6049
    return $setting->getId();
6050
}
6051
6052
/**
6053
 * Checks wether a user can or can't view the contents of a course.
6054
 *
6055
 * @deprecated use CourseManager::is_user_subscribed_in_course
6056
 *
6057
 * @param int $userid User id or NULL to get it from $_SESSION
6058
 * @param int $cid    course id to check whether the user is allowed
6059
 *
6060
 * @return bool
6061
 */
6062
function api_is_course_visible_for_user($userid = null, $cid = null)
6063
{
6064
    if (null === $userid) {
6065
        $userid = api_get_user_id();
6066
    }
6067
    if (empty($userid) || strval(intval($userid)) != $userid) {
6068
        if (api_is_anonymous()) {
6069
            $userid = api_get_anonymous_id();
6070
        } else {
6071
            return false;
6072
        }
6073
    }
6074
    $cid = Database::escape_string($cid);
6075
6076
    $courseInfo = api_get_course_info($cid);
6077
    $courseId = $courseInfo['real_id'];
6078
    $is_platformAdmin = api_is_platform_admin();
6079
6080
    $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
6081
    $course_cat_table = Database::get_main_table(TABLE_MAIN_CATEGORY);
6082
6083
    $sql = "SELECT
6084
                $course_cat_table.code AS category_code,
6085
                $course_table.visibility,
6086
                $course_table.code,
6087
                $course_cat_table.code
6088
            FROM $course_table
6089
            LEFT JOIN $course_cat_table
6090
                ON $course_table.category_id = $course_cat_table.id
6091
            WHERE
6092
                $course_table.code = '$cid'
6093
            LIMIT 1";
6094
6095
    $result = Database::query($sql);
6096
6097
    if (Database::num_rows($result) > 0) {
6098
        $visibility = Database::fetch_array($result);
6099
        $visibility = $visibility['visibility'];
6100
    } else {
6101
        $visibility = 0;
6102
    }
6103
    // Shortcut permissions in case the visibility is "open to the world".
6104
    if (COURSE_VISIBILITY_OPEN_WORLD === $visibility) {
6105
        return true;
6106
    }
6107
6108
    $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
6109
6110
    $sql = "SELECT
6111
                is_tutor, status
6112
            FROM $tbl_course_user
6113
            WHERE
6114
                user_id  = '$userid' AND
6115
                relation_type <> '".COURSE_RELATION_TYPE_RRHH."' AND
6116
                c_id = $courseId
6117
            LIMIT 1";
6118
6119
    $result = Database::query($sql);
6120
6121
    if (Database::num_rows($result) > 0) {
6122
        // This user has got a recorded state for this course.
6123
        $cuData = Database::fetch_array($result);
6124
        $is_courseMember = true;
6125
        $is_courseAdmin = (1 == $cuData['status']);
6126
    }
6127
6128
    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...
6129
        // This user has no status related to this course.
6130
        // Is it the session coach or the session admin?
6131
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
6132
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
6133
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
6134
6135
        $sql = "SELECT
6136
                    session.id_coach, session_admin_id, session.id
6137
                FROM
6138
                    $tbl_session as session
6139
                INNER JOIN $tbl_session_course
6140
                    ON session_rel_course.session_id = session.id
6141
                    AND session_rel_course.c_id = '$courseId'
6142
                LIMIT 1";
6143
6144
        $result = Database::query($sql);
6145
        $row = Database::store_result($result);
6146
6147
        if ($row[0]['id_coach'] == $userid) {
6148
            $is_courseMember = true;
6149
            $is_courseAdmin = false;
6150
        } elseif ($row[0]['session_admin_id'] == $userid) {
6151
            $is_courseMember = false;
6152
            $is_courseAdmin = false;
6153
        } else {
6154
            // Check if the current user is the course coach.
6155
            $sql = "SELECT 1
6156
                    FROM $tbl_session_course
6157
                    WHERE session_rel_course.c_id = '$courseId'
6158
                    AND session_rel_course.id_coach = '$userid'
6159
                    LIMIT 1";
6160
6161
            $result = Database::query($sql);
6162
6163
            //if ($row = Database::fetch_array($result)) {
6164
            if (Database::num_rows($result) > 0) {
6165
                $is_courseMember = true;
6166
                $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
6167
6168
                $sql = "SELECT status FROM $tbl_user
6169
                        WHERE user_id = $userid
6170
                        LIMIT 1";
6171
6172
                $result = Database::query($sql);
6173
6174
                if (1 == Database::result($result, 0, 0)) {
6175
                    $is_courseAdmin = true;
6176
                } else {
6177
                    $is_courseAdmin = false;
6178
                }
6179
            } else {
6180
                // Check if the user is a student is this session.
6181
                $sql = "SELECT  id
6182
                        FROM $tbl_session_course_user
6183
                        WHERE
6184
                            user_id  = '$userid' AND
6185
                            c_id = '$courseId'
6186
                        LIMIT 1";
6187
6188
                if (Database::num_rows($result) > 0) {
6189
                    // This user haa got a recorded state for this course.
6190
                    while ($row = Database::fetch_array($result)) {
6191
                        $is_courseMember = true;
6192
                        $is_courseAdmin = false;
6193
                    }
6194
                }
6195
            }
6196
        }
6197
    }
6198
6199
    switch ($visibility) {
6200
        case COURSE_VISIBILITY_OPEN_WORLD:
6201
            return true;
6202
        case COURSE_VISIBILITY_OPEN_PLATFORM:
6203
            return isset($userid);
6204
        case COURSE_VISIBILITY_REGISTERED:
6205
        case COURSE_VISIBILITY_CLOSED:
6206
            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...
6207
        case COURSE_VISIBILITY_HIDDEN:
6208
            return $is_platformAdmin;
6209
    }
6210
6211
    return false;
6212
}
6213
6214
/**
6215
 * Returns whether an element (forum, message, survey ...) belongs to a session or not.
6216
 *
6217
 * @param string the tool of the element
6218
 * @param int the element id in database
6219
 * @param int the session_id to compare with element session id
6220
 *
6221
 * @return bool true if the element is in the session, false else
6222
 */
6223
function api_is_element_in_the_session($tool, $element_id, $session_id = null)
6224
{
6225
    if (is_null($session_id)) {
6226
        $session_id = api_get_session_id();
6227
    }
6228
6229
    $element_id = (int) $element_id;
6230
6231
    if (empty($element_id)) {
6232
        return false;
6233
    }
6234
6235
    // Get information to build query depending of the tool.
6236
    switch ($tool) {
6237
        case TOOL_SURVEY:
6238
            $table_tool = Database::get_course_table(TABLE_SURVEY);
6239
            $key_field = 'survey_id';
6240
            break;
6241
        case TOOL_ANNOUNCEMENT:
6242
            $table_tool = Database::get_course_table(TABLE_ANNOUNCEMENT);
6243
            $key_field = 'id';
6244
            break;
6245
        case TOOL_AGENDA:
6246
            $table_tool = Database::get_course_table(TABLE_AGENDA);
6247
            $key_field = 'id';
6248
            break;
6249
        case TOOL_GROUP:
6250
            $table_tool = Database::get_course_table(TABLE_GROUP);
6251
            $key_field = 'id';
6252
            break;
6253
        default:
6254
            return false;
6255
    }
6256
    $course_id = api_get_course_int_id();
6257
6258
    $sql = "SELECT session_id FROM $table_tool
6259
            WHERE c_id = $course_id AND $key_field =  ".$element_id;
6260
    $rs = Database::query($sql);
6261
    if ($element_session_id = Database::result($rs, 0, 0)) {
6262
        if ($element_session_id == intval($session_id)) {
6263
            // The element belongs to the session.
6264
            return true;
6265
        }
6266
    }
6267
6268
    return false;
6269
}
6270
6271
/**
6272
 * Replaces "forbidden" characters in a filename string.
6273
 *
6274
 * @param string $filename
6275
 * @param bool   $treat_spaces_as_hyphens
6276
 *
6277
 * @return string
6278
 */
6279
function api_replace_dangerous_char($filename, $treat_spaces_as_hyphens = true)
0 ignored issues
show
Unused Code introduced by
The parameter $treat_spaces_as_hyphens is not used and could be removed. ( Ignorable by Annotation )

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

6279
function api_replace_dangerous_char($filename, /** @scrutinizer ignore-unused */ $treat_spaces_as_hyphens = true)

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

Loading history...
6280
{
6281
    // Some non-properly encoded file names can cause the whole file to be
6282
    // skipped when uploaded. Avoid this by detecting the encoding and
6283
    // converting to UTF-8, setting the source as ASCII (a reasonably
6284
    // limited characters set) if nothing could be found (BT#
6285
    $encoding = api_detect_encoding($filename);
6286
    if (empty($encoding)) {
6287
        $encoding = 'ASCII';
6288
        if (!api_is_valid_ascii($filename)) {
6289
            // try iconv and try non standard ASCII a.k.a CP437
6290
            // see BT#15022
6291
            if (function_exists('iconv')) {
6292
                $result = iconv('CP437', 'UTF-8', $filename);
6293
                if (api_is_valid_utf8($result)) {
6294
                    $filename = $result;
6295
                    $encoding = 'UTF-8';
6296
                }
6297
            }
6298
        }
6299
    }
6300
6301
    $filename = api_to_system_encoding($filename, $encoding);
6302
6303
    $url = URLify::filter(
6304
        $filename,
6305
        250,
6306
        '',
6307
        true,
6308
        false,
6309
        false,
6310
        false
6311
    );
6312
6313
    return $url;
6314
}
6315
6316
/**
6317
 * Fixes the $_SERVER['REQUEST_URI'] that is empty in IIS6.
6318
 *
6319
 * @author Ivan Tcholakov, 28-JUN-2006.
6320
 */
6321
function api_request_uri()
6322
{
6323
    if (!empty($_SERVER['REQUEST_URI'])) {
6324
        return $_SERVER['REQUEST_URI'];
6325
    }
6326
    $uri = $_SERVER['SCRIPT_NAME'];
6327
    if (!empty($_SERVER['QUERY_STRING'])) {
6328
        $uri .= '?'.$_SERVER['QUERY_STRING'];
6329
    }
6330
    $_SERVER['REQUEST_URI'] = $uri;
6331
6332
    return $uri;
6333
}
6334
6335
/** Gets the current access_url id of the Chamilo Platform
6336
 * @author Julio Montoya <[email protected]>
6337
 *
6338
 * @return int access_url_id of the current Chamilo Installation
6339
 */
6340
function api_get_current_access_url_id()
6341
{
6342
    if (false === api_get_multiple_access_url()) {
6343
        return 1;
6344
    }
6345
6346
    static $id;
6347
    if (!empty($id)) {
6348
        return $id;
6349
    }
6350
6351
    $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
6352
    $path = Database::escape_string(api_get_path(WEB_PATH));
6353
    $sql = "SELECT id FROM $table WHERE url = '".$path."'";
6354
    $result = Database::query($sql);
6355
    if (Database::num_rows($result) > 0) {
6356
        $id = Database::result($result, 0, 0);
6357
        if (false === $id) {
6358
            return -1;
6359
        }
6360
6361
        return (int) $id;
6362
    }
6363
6364
    $id = 1;
6365
6366
    //if the url in WEB_PATH was not found, it can only mean that there is
6367
    // either a configuration problem or the first URL has not been defined yet
6368
    // (by default it is http://localhost/). Thus the more sensible thing we can
6369
    // do is return 1 (the main URL) as the user cannot hack this value anyway
6370
    return 1;
6371
}
6372
6373
/**
6374
 * Gets the registered urls from a given user id.
6375
 *
6376
 * @author Julio Montoya <[email protected]>
6377
 *
6378
 * @param int $user_id
6379
 *
6380
 * @return array
6381
 */
6382
function api_get_access_url_from_user($user_id)
6383
{
6384
    $user_id = (int) $user_id;
6385
    $table_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
6386
    $table_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
6387
    $sql = "SELECT access_url_id
6388
            FROM $table_url_rel_user url_rel_user
6389
            INNER JOIN $table_url u
6390
            ON (url_rel_user.access_url_id = u.id)
6391
            WHERE user_id = ".$user_id;
6392
    $result = Database::query($sql);
6393
    $list = [];
6394
    while ($row = Database::fetch_array($result, 'ASSOC')) {
6395
        $list[] = $row['access_url_id'];
6396
    }
6397
6398
    return $list;
6399
}
6400
6401
/**
6402
 * Checks whether the curent user is in a group or not.
6403
 *
6404
 * @param string        The group id - optional (takes it from session if not given)
6405
 * @param string        The course code - optional (no additional check by course if course code is not given)
6406
 *
6407
 * @return bool
6408
 *
6409
 * @author Ivan Tcholakov
6410
 */
6411
function api_is_in_group($groupIdParam = null, $courseCodeParam = null)
6412
{
6413
    if (!empty($courseCodeParam)) {
6414
        $courseCode = api_get_course_id();
6415
        if (!empty($courseCode)) {
6416
            if ($courseCodeParam != $courseCode) {
6417
                return false;
6418
            }
6419
        } else {
6420
            return false;
6421
        }
6422
    }
6423
6424
    $groupId = api_get_group_id();
6425
6426
    if (isset($groupId) && '' != $groupId) {
6427
        if (!empty($groupIdParam)) {
6428
            return $groupIdParam == $groupId;
6429
        } else {
6430
            return true;
6431
        }
6432
    }
6433
6434
    return false;
6435
}
6436
6437
/**
6438
 * Checks whether a secret key is valid.
6439
 *
6440
 * @param string $original_key_secret - secret key from (webservice) client
6441
 * @param string $security_key        - security key from Chamilo
6442
 *
6443
 * @return bool - true if secret key is valid, false otherwise
6444
 */
6445
function api_is_valid_secret_key($original_key_secret, $security_key)
6446
{
6447
    return $original_key_secret == sha1($security_key);
6448
}
6449
6450
/**
6451
 * Checks whether a user is into course.
6452
 *
6453
 * @param int $course_id - the course id
6454
 * @param int $user_id   - the user id
6455
 *
6456
 * @return bool
6457
 */
6458
function api_is_user_of_course($course_id, $user_id)
6459
{
6460
    $tbl_course_rel_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
6461
    $sql = 'SELECT user_id FROM '.$tbl_course_rel_user.'
6462
            WHERE
6463
                c_id ="'.intval($course_id).'" AND
6464
                user_id = "'.intval($user_id).'" AND
6465
                relation_type <> '.COURSE_RELATION_TYPE_RRHH.' ';
6466
    $result = Database::query($sql);
6467
6468
    return 1 == Database::num_rows($result);
6469
}
6470
6471
/**
6472
 * Checks whether the server's operating system is Windows (TM).
6473
 *
6474
 * @return bool - true if the operating system is Windows, false otherwise
6475
 */
6476
function api_is_windows_os()
6477
{
6478
    if (function_exists('php_uname')) {
6479
        // php_uname() exists as of PHP 4.0.2, according to the documentation.
6480
        // We expect that this function will always work for Chamilo 1.8.x.
6481
        $os = php_uname();
6482
    }
6483
    // The following methods are not needed, but let them stay, just in case.
6484
    elseif (isset($_ENV['OS'])) {
6485
        // Sometimes $_ENV['OS'] may not be present (bugs?)
6486
        $os = $_ENV['OS'];
6487
    } elseif (defined('PHP_OS')) {
6488
        // PHP_OS means on which OS PHP was compiled, this is why
6489
        // using PHP_OS is the last choice for detection.
6490
        $os = PHP_OS;
6491
    } else {
6492
        return false;
6493
    }
6494
6495
    return 'win' == strtolower(substr((string) $os, 0, 3));
6496
}
6497
6498
/**
6499
 * This function informs whether the sent request is XMLHttpRequest.
6500
 */
6501
function api_is_xml_http_request()
6502
{
6503
    return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && 'xmlhttprequest' == strtolower($_SERVER['HTTP_X_REQUESTED_WITH']);
6504
}
6505
6506
/**
6507
 * This wrapper function has been implemented for avoiding some known problems about the function getimagesize().
6508
 *
6509
 * @see http://php.net/manual/en/function.getimagesize.php
6510
 * @see http://www.dokeos.com/forum/viewtopic.php?t=12345
6511
 * @see http://www.dokeos.com/forum/viewtopic.php?t=16355
6512
 *
6513
 * @return int
6514
 */
6515
function api_getimagesize($path)
6516
{
6517
    $image = new Image($path);
6518
6519
    return $image->get_image_size();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $image->get_image_size() returns the type array|array<string,integer> which is incompatible with the documented return type integer.
Loading history...
6520
}
6521
6522
/**
6523
 * This function resizes an image, with preserving its proportions (or aspect ratio).
6524
 *
6525
 * @author Ivan Tcholakov, MAY-2009.
6526
 *
6527
 * @param int $image         System path or URL of the image
6528
 * @param int $target_width  Targeted width
6529
 * @param int $target_height Targeted height
6530
 *
6531
 * @return array Calculated new width and height
6532
 */
6533
function api_resize_image($image, $target_width, $target_height)
6534
{
6535
    $image_properties = api_getimagesize($image);
6536
6537
    return api_calculate_image_size(
6538
        $image_properties['width'],
6539
        $image_properties['height'],
6540
        $target_width,
6541
        $target_height
6542
    );
6543
}
6544
6545
/**
6546
 * This function calculates new image size, with preserving image's proportions (or aspect ratio).
6547
 *
6548
 * @author Ivan Tcholakov, MAY-2009.
6549
 * @author The initial idea has been taken from code by Patrick Cool, MAY-2004.
6550
 *
6551
 * @param int $image_width   Initial width
6552
 * @param int $image_height  Initial height
6553
 * @param int $target_width  Targeted width
6554
 * @param int $target_height Targeted height
6555
 *
6556
 * @return array Calculated new width and height
6557
 */
6558
function api_calculate_image_size(
6559
    $image_width,
6560
    $image_height,
6561
    $target_width,
6562
    $target_height
6563
) {
6564
    // Only maths is here.
6565
    $result = ['width' => $image_width, 'height' => $image_height];
6566
    if ($image_width <= 0 || $image_height <= 0) {
6567
        return $result;
6568
    }
6569
    $resize_factor_width = $target_width / $image_width;
6570
    $resize_factor_height = $target_height / $image_height;
6571
    $delta_width = $target_width - $image_width * $resize_factor_height;
6572
    $delta_height = $target_height - $image_height * $resize_factor_width;
6573
    if ($delta_width > $delta_height) {
6574
        $result['width'] = ceil($image_width * $resize_factor_height);
6575
        $result['height'] = ceil($image_height * $resize_factor_height);
6576
    } elseif ($delta_width < $delta_height) {
6577
        $result['width'] = ceil($image_width * $resize_factor_width);
6578
        $result['height'] = ceil($image_height * $resize_factor_width);
6579
    } else {
6580
        $result['width'] = ceil($target_width);
6581
        $result['height'] = ceil($target_height);
6582
    }
6583
6584
    return $result;
6585
}
6586
6587
/**
6588
 * Returns a list of Chamilo's tools or
6589
 * checks whether a given identificator is a valid Chamilo's tool.
6590
 *
6591
 * @author Isaac flores paz
6592
 *
6593
 * @param string The tool name to filter
6594
 *
6595
 * @return mixed Filtered string or array
6596
 */
6597
function api_get_tools_lists($my_tool = null)
6598
{
6599
    $tools_list = [
6600
        TOOL_DOCUMENT,
6601
        TOOL_THUMBNAIL,
6602
        TOOL_HOTPOTATOES,
6603
        TOOL_CALENDAR_EVENT,
6604
        TOOL_LINK,
6605
        TOOL_COURSE_DESCRIPTION,
6606
        TOOL_SEARCH,
6607
        TOOL_LEARNPATH,
6608
        TOOL_ANNOUNCEMENT,
6609
        TOOL_FORUM,
6610
        TOOL_THREAD,
6611
        TOOL_POST,
6612
        TOOL_DROPBOX,
6613
        TOOL_QUIZ,
6614
        TOOL_USER,
6615
        TOOL_GROUP,
6616
        TOOL_BLOGS,
6617
        TOOL_CHAT,
6618
        TOOL_STUDENTPUBLICATION,
6619
        TOOL_TRACKING,
6620
        TOOL_HOMEPAGE_LINK,
6621
        TOOL_COURSE_SETTING,
6622
        TOOL_BACKUP,
6623
        TOOL_COPY_COURSE_CONTENT,
6624
        TOOL_RECYCLE_COURSE,
6625
        TOOL_COURSE_HOMEPAGE,
6626
        TOOL_COURSE_RIGHTS_OVERVIEW,
6627
        TOOL_UPLOAD,
6628
        TOOL_COURSE_MAINTENANCE,
6629
        TOOL_SURVEY,
6630
        TOOL_WIKI,
6631
        TOOL_GLOSSARY,
6632
        TOOL_GRADEBOOK,
6633
        TOOL_NOTEBOOK,
6634
        TOOL_ATTENDANCE,
6635
        TOOL_COURSE_PROGRESS,
6636
    ];
6637
    if (empty($my_tool)) {
6638
        return $tools_list;
6639
    }
6640
6641
    return in_array($my_tool, $tools_list) ? $my_tool : '';
6642
}
6643
6644
/**
6645
 * Checks whether we already approved the last version term and condition.
6646
 *
6647
 * @param int user id
6648
 *
6649
 * @return bool true if we pass false otherwise
6650
 */
6651
function api_check_term_condition($userId)
6652
{
6653
    if ('true' === api_get_setting('allow_terms_conditions')) {
6654
        // Check if exists terms and conditions
6655
        if (0 == LegalManager::count()) {
6656
            return true;
6657
        }
6658
6659
        $extraFieldValue = new ExtraFieldValue('user');
6660
        $data = $extraFieldValue->get_values_by_handler_and_field_variable(
6661
            $userId,
6662
            'legal_accept'
6663
        );
6664
6665
        if (!empty($data) && isset($data['value']) && !empty($data['value'])) {
6666
            $result = $data['value'];
6667
            $user_conditions = explode(':', $result);
6668
            $version = $user_conditions[0];
6669
            $langId = $user_conditions[1];
6670
            $realVersion = LegalManager::get_last_version($langId);
6671
6672
            return $version >= $realVersion;
6673
        }
6674
6675
        return false;
6676
    }
6677
6678
    return false;
6679
}
6680
6681
/**
6682
 * Gets all information of a tool into course.
6683
 *
6684
 * @param int The tool id
6685
 *
6686
 * @return array
6687
 */
6688
function api_get_tool_information_by_name($name)
6689
{
6690
    $t_tool = Database::get_course_table(TABLE_TOOL_LIST);
6691
    $course_id = api_get_course_int_id();
6692
6693
    $sql = "SELECT id FROM tool
6694
            WHERE name = '".Database::escape_string($name)."' ";
6695
    $rs = Database::query($sql);
6696
    $data = Database::fetch_array($rs);
6697
    $tool = $data['id'];
6698
6699
    $sql = "SELECT * FROM $t_tool
6700
            WHERE c_id = $course_id  AND tool_id = '".$tool."' ";
6701
    $rs = Database::query($sql);
6702
6703
    return Database::fetch_array($rs, 'ASSOC');
6704
}
6705
6706
/**
6707
 * Function used to protect a "global" admin script.
6708
 * The function blocks access when the user has no global platform admin rights.
6709
 * Global admins are the admins that are registered in the main.admin table
6710
 * AND the users who have access to the "principal" portal.
6711
 * That means that there is a record in the main.access_url_rel_user table
6712
 * with his user id and the access_url_id=1.
6713
 *
6714
 * @author Julio Montoya
6715
 *
6716
 * @param int $user_id
6717
 *
6718
 * @return bool
6719
 */
6720
function api_is_global_platform_admin($user_id = null)
6721
{
6722
    $user_id = (int) $user_id;
6723
    if (empty($user_id)) {
6724
        $user_id = api_get_user_id();
6725
    }
6726
    if (api_is_platform_admin_by_id($user_id)) {
6727
        $urlList = api_get_access_url_from_user($user_id);
6728
        // The admin is registered in the first "main" site with access_url_id = 1
6729
        if (in_array(1, $urlList)) {
6730
            return true;
6731
        } else {
6732
            return false;
6733
        }
6734
    }
6735
6736
    return false;
6737
}
6738
6739
/**
6740
 * @param int  $admin_id_to_check
6741
 * @param int  $my_user_id
6742
 * @param bool $allow_session_admin
6743
 *
6744
 * @return bool
6745
 */
6746
function api_global_admin_can_edit_admin(
6747
    $admin_id_to_check,
6748
    $my_user_id = null,
6749
    $allow_session_admin = false
6750
) {
6751
    if (empty($my_user_id)) {
6752
        $my_user_id = api_get_user_id();
6753
    }
6754
6755
    $iam_a_global_admin = api_is_global_platform_admin($my_user_id);
6756
    $user_is_global_admin = api_is_global_platform_admin($admin_id_to_check);
6757
6758
    if ($iam_a_global_admin) {
6759
        // Global admin can edit everything
6760
        return true;
6761
    } else {
6762
        // If i'm a simple admin
6763
        $is_platform_admin = api_is_platform_admin_by_id($my_user_id);
6764
6765
        if ($allow_session_admin) {
6766
            $is_platform_admin = api_is_platform_admin_by_id($my_user_id) || (SESSIONADMIN == api_get_user_status($my_user_id));
6767
        }
6768
6769
        if ($is_platform_admin) {
6770
            if ($user_is_global_admin) {
6771
                return false;
6772
            } else {
6773
                return true;
6774
            }
6775
        } else {
6776
            return false;
6777
        }
6778
    }
6779
}
6780
6781
/**
6782
 * @param int  $admin_id_to_check
6783
 * @param int  $my_user_id
6784
 * @param bool $allow_session_admin
6785
 *
6786
 * @return bool|null
6787
 */
6788
function api_protect_super_admin($admin_id_to_check, $my_user_id = null, $allow_session_admin = false)
6789
{
6790
    if (api_global_admin_can_edit_admin($admin_id_to_check, $my_user_id, $allow_session_admin)) {
6791
        return true;
6792
    } else {
6793
        api_not_allowed();
6794
    }
6795
}
6796
6797
/**
6798
 * Function used to protect a global admin script.
6799
 * The function blocks access when the user has no global platform admin rights.
6800
 * See also the api_is_global_platform_admin() function wich defines who's a "global" admin.
6801
 *
6802
 * @author Julio Montoya
6803
 */
6804
function api_protect_global_admin_script()
6805
{
6806
    if (!api_is_global_platform_admin()) {
6807
        api_not_allowed();
6808
6809
        return false;
6810
    }
6811
6812
    return true;
6813
}
6814
6815
/**
6816
 * Check browser support for specific file types or features
6817
 * This function checks if the user's browser supports a file format or given
6818
 * feature, or returns the current browser and major version when
6819
 * $format=check_browser. Only a limited number of formats and features are
6820
 * checked by this method. Make sure you check its definition first.
6821
 *
6822
 * @param string $format Can be a file format (extension like svg, webm, ...) or a feature (like autocapitalize, ...)
6823
 *
6824
 * @deprecated
6825
 *
6826
 * @return bool or return text array if $format=check_browser
6827
 *
6828
 * @author Juan Carlos Raña Trabado
6829
 */
6830
function api_browser_support($format = '')
0 ignored issues
show
Unused Code introduced by
The parameter $format is not used and could be removed. ( Ignorable by Annotation )

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

6830
function api_browser_support(/** @scrutinizer ignore-unused */ $format = '')

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

Loading history...
6831
{
6832
    return true;
6833
6834
    $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...
6835
    $current_browser = $browser->getBrowser();
6836
    $a_versiontemp = explode('.', $browser->getVersion());
6837
    $current_majorver = $a_versiontemp[0];
6838
6839
    static $result;
6840
6841
    if (isset($result[$format])) {
6842
        return $result[$format];
6843
    }
6844
6845
    // Native svg support
6846
    if ('svg' == $format) {
6847
        if (('Internet Explorer' == $current_browser && $current_majorver >= 9) ||
6848
            ('Firefox' == $current_browser && $current_majorver > 1) ||
6849
            ('Safari' == $current_browser && $current_majorver >= 4) ||
6850
            ('Chrome' == $current_browser && $current_majorver >= 1) ||
6851
            ('Opera' == $current_browser && $current_majorver >= 9)
6852
        ) {
6853
            $result[$format] = true;
6854
6855
            return true;
6856
        } else {
6857
            $result[$format] = false;
6858
6859
            return false;
6860
        }
6861
    } elseif ('pdf' == $format) {
6862
        // native pdf support
6863
        if ('Chrome' == $current_browser && $current_majorver >= 6) {
6864
            $result[$format] = true;
6865
6866
            return true;
6867
        } else {
6868
            $result[$format] = false;
6869
6870
            return false;
6871
        }
6872
    } elseif ('tif' == $format || 'tiff' == $format) {
6873
        //native tif support
6874
        if ('Safari' == $current_browser && $current_majorver >= 5) {
6875
            $result[$format] = true;
6876
6877
            return true;
6878
        } else {
6879
            $result[$format] = false;
6880
6881
            return false;
6882
        }
6883
    } elseif ('ogg' == $format || 'ogx' == $format || 'ogv' == $format || 'oga' == $format) {
6884
        //native ogg, ogv,oga support
6885
        if (('Firefox' == $current_browser && $current_majorver >= 3) ||
6886
            ('Chrome' == $current_browser && $current_majorver >= 3) ||
6887
            ('Opera' == $current_browser && $current_majorver >= 9)) {
6888
            $result[$format] = true;
6889
6890
            return true;
6891
        } else {
6892
            $result[$format] = false;
6893
6894
            return false;
6895
        }
6896
    } elseif ('mpg' == $format || 'mpeg' == $format) {
6897
        //native mpg support
6898
        if (('Safari' == $current_browser && $current_majorver >= 5)) {
6899
            $result[$format] = true;
6900
6901
            return true;
6902
        } else {
6903
            $result[$format] = false;
6904
6905
            return false;
6906
        }
6907
    } elseif ('mp4' == $format) {
6908
        //native mp4 support (TODO: Android, iPhone)
6909
        if ('Android' == $current_browser || 'iPhone' == $current_browser) {
6910
            $result[$format] = true;
6911
6912
            return true;
6913
        } else {
6914
            $result[$format] = false;
6915
6916
            return false;
6917
        }
6918
    } elseif ('mov' == $format) {
6919
        //native mov support( TODO:check iPhone)
6920
        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...
6921
            $result[$format] = true;
6922
6923
            return true;
6924
        } else {
6925
            $result[$format] = false;
6926
6927
            return false;
6928
        }
6929
    } elseif ('avi' == $format) {
6930
        //native avi support
6931
        if ('Safari' == $current_browser && $current_majorver >= 5) {
6932
            $result[$format] = true;
6933
6934
            return true;
6935
        } else {
6936
            $result[$format] = false;
6937
6938
            return false;
6939
        }
6940
    } elseif ('wmv' == $format) {
6941
        //native wmv support
6942
        if ('Firefox' == $current_browser && $current_majorver >= 4) {
6943
            $result[$format] = true;
6944
6945
            return true;
6946
        } else {
6947
            $result[$format] = false;
6948
6949
            return false;
6950
        }
6951
    } elseif ('webm' == $format) {
6952
        //native webm support (TODO:check IE9, Chrome9, Android)
6953
        if (('Firefox' == $current_browser && $current_majorver >= 4) ||
6954
            ('Opera' == $current_browser && $current_majorver >= 9) ||
6955
            ('Internet Explorer' == $current_browser && $current_majorver >= 9) ||
6956
            ('Chrome' == $current_browser && $current_majorver >= 9) ||
6957
            'Android' == $current_browser
6958
        ) {
6959
            $result[$format] = true;
6960
6961
            return true;
6962
        } else {
6963
            $result[$format] = false;
6964
6965
            return false;
6966
        }
6967
    } elseif ('wav' == $format) {
6968
        //native wav support (only some codecs !)
6969
        if (('Firefox' == $current_browser && $current_majorver >= 4) ||
6970
            ('Safari' == $current_browser && $current_majorver >= 5) ||
6971
            ('Opera' == $current_browser && $current_majorver >= 9) ||
6972
            ('Internet Explorer' == $current_browser && $current_majorver >= 9) ||
6973
            ('Chrome' == $current_browser && $current_majorver > 9) ||
6974
            'Android' == $current_browser ||
6975
            'iPhone' == $current_browser
6976
        ) {
6977
            $result[$format] = true;
6978
6979
            return true;
6980
        } else {
6981
            $result[$format] = false;
6982
6983
            return false;
6984
        }
6985
    } elseif ('mid' == $format || 'kar' == $format) {
6986
        //native midi support (TODO:check Android)
6987
        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...
6988
            $result[$format] = true;
6989
6990
            return true;
6991
        } else {
6992
            $result[$format] = false;
6993
6994
            return false;
6995
        }
6996
    } elseif ('wma' == $format) {
6997
        //native wma support
6998
        if ('Firefox' == $current_browser && $current_majorver >= 4) {
6999
            $result[$format] = true;
7000
7001
            return true;
7002
        } else {
7003
            $result[$format] = false;
7004
7005
            return false;
7006
        }
7007
    } elseif ('au' == $format) {
7008
        //native au support
7009
        if ('Safari' == $current_browser && $current_majorver >= 5) {
7010
            $result[$format] = true;
7011
7012
            return true;
7013
        } else {
7014
            $result[$format] = false;
7015
7016
            return false;
7017
        }
7018
    } elseif ('mp3' == $format) {
7019
        //native mp3 support (TODO:check Android, iPhone)
7020
        if (('Safari' == $current_browser && $current_majorver >= 5) ||
7021
            ('Chrome' == $current_browser && $current_majorver >= 6) ||
7022
            ('Internet Explorer' == $current_browser && $current_majorver >= 9) ||
7023
            'Android' == $current_browser ||
7024
            'iPhone' == $current_browser ||
7025
            'Firefox' == $current_browser
7026
        ) {
7027
            $result[$format] = true;
7028
7029
            return true;
7030
        } else {
7031
            $result[$format] = false;
7032
7033
            return false;
7034
        }
7035
    } elseif ('autocapitalize' == $format) {
7036
        // Help avoiding showing the autocapitalize option if the browser doesn't
7037
        // support it: this attribute is against the HTML5 standard
7038
        if ('Safari' == $current_browser || 'iPhone' == $current_browser) {
7039
            return true;
7040
        } else {
7041
            return false;
7042
        }
7043
    } elseif ("check_browser" == $format) {
7044
        $array_check_browser = [$current_browser, $current_majorver];
7045
7046
        return $array_check_browser;
7047
    } else {
7048
        $result[$format] = false;
7049
7050
        return false;
7051
    }
7052
}
7053
7054
/**
7055
 * This function checks if exist path and file browscap.ini
7056
 * In order for this to work, your browscap configuration setting in php.ini
7057
 * must point to the correct location of the browscap.ini file on your system
7058
 * http://php.net/manual/en/function.get-browser.php.
7059
 *
7060
 * @return bool
7061
 *
7062
 * @author Juan Carlos Raña Trabado
7063
 */
7064
function api_check_browscap()
7065
{
7066
    $setting = ini_get('browscap');
7067
    if ($setting) {
7068
        $browser = get_browser($_SERVER['HTTP_USER_AGENT'], true);
7069
        if (strpos($setting, 'browscap.ini') && !empty($browser)) {
7070
            return true;
7071
        }
7072
    }
7073
7074
    return false;
7075
}
7076
7077
/**
7078
 * Returns the <script> HTML tag.
7079
 */
7080
function api_get_js($file)
7081
{
7082
    return '<script type="text/javascript" src="'.api_get_path(WEB_LIBRARY_PATH).'javascript/'.$file.'"></script>'."\n";
7083
}
7084
7085
function api_get_build_js($file)
7086
{
7087
    return '<script type="text/javascript" src="'.api_get_path(WEB_PUBLIC_PATH).'build/'.$file.'"></script>'."\n";
7088
}
7089
7090
/**
7091
 * Returns the <script> HTML tag.
7092
 *
7093
 * @return string
7094
 */
7095
function api_get_asset($file)
7096
{
7097
    return '<script type="text/javascript" src="'.api_get_path(WEB_PUBLIC_PATH).'build/libs/'.$file.'"></script>'."\n";
7098
}
7099
7100
/**
7101
 * Returns the <script> HTML tag.
7102
 *
7103
 * @param string $file
7104
 * @param string $media
7105
 *
7106
 * @return string
7107
 */
7108
function api_get_css_asset($file, $media = 'screen')
7109
{
7110
    return '<link href="'.api_get_path(WEB_PUBLIC_PATH).'libs/'.$file.'" rel="stylesheet" media="'.$media.'" type="text/css" />'."\n";
7111
}
7112
7113
/**
7114
 * Returns the <link> HTML tag.
7115
 *
7116
 * @param string $file
7117
 * @param string $media
7118
 */
7119
function api_get_css($file, $media = 'screen')
7120
{
7121
    return '<link href="'.$file.'" rel="stylesheet" media="'.$media.'" type="text/css" />'."\n";
7122
}
7123
7124
function api_get_bootstrap_and_font_awesome($returnOnlyPath = false)
7125
{
7126
    $url = api_get_path(WEB_PUBLIC_PATH).'build/css/bootstrap.css';
7127
    if ($returnOnlyPath) {
7128
        return $url;
7129
    }
7130
7131
    return '<link href="'.$url.'" rel="stylesheet" type="text/css" />'."\n";
7132
}
7133
7134
/**
7135
 * Returns the js header to include the jquery library.
7136
 */
7137
function api_get_jquery_js()
7138
{
7139
    return api_get_asset('jquery/jquery.min.js');
7140
}
7141
7142
/**
7143
 * Returns the jquery path.
7144
 *
7145
 * @return string
7146
 */
7147
function api_get_jquery_web_path()
7148
{
7149
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery/jquery.min.js';
7150
}
7151
7152
/**
7153
 * @return string
7154
 */
7155
function api_get_jquery_ui_js_web_path()
7156
{
7157
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery-ui/jquery-ui.min.js';
7158
}
7159
7160
/**
7161
 * @return string
7162
 */
7163
function api_get_jquery_ui_css_web_path()
7164
{
7165
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery-ui/themes/smoothness/jquery-ui.min.css';
7166
}
7167
7168
/**
7169
 * Returns the jquery-ui library js headers.
7170
 *
7171
 * @return string html tags
7172
 */
7173
function api_get_jquery_ui_js()
7174
{
7175
    $libraries = [];
7176
7177
    return api_get_jquery_libraries_js($libraries);
7178
}
7179
7180
function api_get_jqgrid_js()
7181
{
7182
    $routePublic = Container::getRouter()->generate('home');
7183
7184
    return api_get_css($routePublic.'build/free-jqgrid.css').PHP_EOL
7185
        .api_get_js_simple($routePublic.'build/free-jqgrid.js');
7186
}
7187
7188
/**
7189
 * Returns the jquery library js and css headers.
7190
 *
7191
 * @param   array   list of jquery libraries supported jquery-ui
7192
 * @param   bool    add the jquery library
7193
 *
7194
 * @return string html tags
7195
 */
7196
function api_get_jquery_libraries_js($libraries)
7197
{
7198
    $js = '';
7199
7200
    //Document multiple upload funcionality
7201
    if (in_array('jquery-uploadzs', $libraries)) {
7202
        $js .= api_get_asset('blueimp-load-image/js/load-image.all.min.js');
7203
        $js .= api_get_asset('blueimp-canvas-to-blob/js/canvas-to-blob.min.js');
7204
        $js .= api_get_asset('jquery-file-upload/js/jquery.iframe-transport.js');
7205
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload.js');
7206
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-process.js');
7207
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-image.js');
7208
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-audio.js');
7209
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-video.js');
7210
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-validate.js');
7211
7212
        $js .= api_get_css(api_get_path(WEB_PUBLIC_PATH).'assets/jquery-file-upload/css/jquery.fileupload.css');
7213
        $js .= api_get_css(api_get_path(WEB_PUBLIC_PATH).'assets/jquery-file-upload/css/jquery.fileupload-ui.css');
7214
    }
7215
7216
    // jquery datepicker
7217
    if (in_array('datepicker', $libraries)) {
7218
        $languaje = 'en-GB';
7219
        $platform_isocode = strtolower(api_get_language_isocode());
7220
7221
        $datapicker_langs = [
7222
            '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',
7223
        ];
7224
        if (in_array($platform_isocode, $datapicker_langs)) {
7225
            $languaje = $platform_isocode;
7226
        }
7227
7228
        $js .= api_get_js('jquery-ui/jquery-ui-i18n.min.js');
7229
        $script = '<script>
7230
        $(function(){
7231
            $.datepicker.setDefaults($.datepicker.regional["'.$languaje.'"]);
7232
            $.datepicker.regional["local"] = $.datepicker.regional["'.$languaje.'"];
7233
        });
7234
        </script>
7235
        ';
7236
        $js .= $script;
7237
    }
7238
7239
    return $js;
7240
}
7241
7242
/**
7243
 * Returns the URL to the course or session, removing the complexity of the URL
7244
 * building piece by piece.
7245
 *
7246
 * This function relies on api_get_course_info()
7247
 *
7248
 * @param string $courseCode The course code - optional (takes it from context if not given)
7249
 * @param int    $sessionId  The session ID  - optional (takes it from context if not given)
7250
 * @param int    $groupId    The group ID - optional (takes it from context if not given)
7251
 *
7252
 * @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
7253
 *
7254
 * @author  Julio Montoya <[email protected]>
7255
 */
7256
function api_get_course_url($courseCode = null, $sessionId = null, $groupId = null)
7257
{
7258
    $courseDirectory = '';
7259
    $url = '';
7260
    // If courseCode not set, get context or []
7261
    if (empty($courseCode)) {
7262
        $courseInfo = api_get_course_info();
7263
    } else {
7264
        $courseInfo = api_get_course_info($courseCode);
7265
    }
7266
7267
    // If course defined, get directory, otherwise keep empty string
7268
    if (!empty($courseInfo['directory'])) {
7269
        $courseDirectory = $courseInfo['directory'];
7270
    }
7271
7272
    // If sessionId not set, get context or 0
7273
    if (empty($sessionId)) {
7274
        $sessionId = api_get_session_id();
7275
    }
7276
7277
    // If groupId not set, get context or 0
7278
    if (empty($groupId)) {
7279
        $groupId = api_get_group_id();
7280
    }
7281
7282
    // Build the URL
7283
    if (!empty($courseDirectory)) {
7284
        // directory not empty, so we do have a course
7285
        $url = api_get_path(WEB_COURSE_PATH).$courseDirectory.'/index.php?id_session='.$sessionId.'&gidReq='.$groupId;
7286
    } elseif (!empty($sessionId) &&
7287
        'true' !== api_get_setting('session.remove_session_url')
7288
    ) {
7289
        // if the course was unset and the session was set, send directly to the session
7290
        $url = api_get_path(WEB_CODE_PATH).'session/index.php?session_id='.$sessionId;
7291
    }
7292
7293
    // if not valid combination was found, return an empty string
7294
    return $url;
7295
}
7296
7297
/**
7298
 * Check if the current portal has the $_configuration['multiple_access_urls'] parameter on.
7299
 *
7300
 * @return bool true if multi site is enabled
7301
 */
7302
function api_get_multiple_access_url()
7303
{
7304
    global $_configuration;
7305
    if (isset($_configuration['multiple_access_urls']) && $_configuration['multiple_access_urls']) {
7306
        return true;
7307
    }
7308
7309
    return false;
7310
}
7311
7312
/**
7313
 * @return bool
7314
 */
7315
function api_is_multiple_url_enabled()
7316
{
7317
    return api_get_multiple_access_url();
7318
}
7319
7320
/**
7321
 * Returns a md5 unique id.
7322
 *
7323
 * @todo add more parameters
7324
 */
7325
function api_get_unique_id()
7326
{
7327
    $id = md5(time().uniqid().api_get_user_id().api_get_course_id().api_get_session_id());
7328
7329
    return $id;
7330
}
7331
7332
/**
7333
 * @param int Course id
7334
 * @param int tool id: TOOL_QUIZ, TOOL_FORUM, TOOL_STUDENTPUBLICATION, TOOL_LEARNPATH
7335
 * @param int the item id (tool id, exercise id, lp id)
7336
 *
7337
 * @return bool
7338
 */
7339
function api_resource_is_locked_by_gradebook($item_id, $link_type, $course_code = null)
7340
{
7341
    if (api_is_platform_admin()) {
7342
        return false;
7343
    }
7344
    if ('true' == api_get_setting('gradebook_locking_enabled')) {
7345
        if (empty($course_code)) {
7346
            $course_code = api_get_course_id();
7347
        }
7348
        $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_LINK);
7349
        $item_id = (int) $item_id;
7350
        $link_type = (int) $link_type;
7351
        $course_code = Database::escape_string($course_code);
7352
        $sql = "SELECT locked FROM $table
7353
                WHERE locked = 1 AND ref_id = $item_id AND type = $link_type AND course_code = '$course_code' ";
7354
        $result = Database::query($sql);
7355
        if (Database::num_rows($result)) {
7356
            return true;
7357
        }
7358
    }
7359
7360
    return false;
7361
}
7362
7363
/**
7364
 * Blocks a page if the item was added in a gradebook.
7365
 *
7366
 * @param int       exercise id, work id, thread id,
7367
 * @param int       LINK_EXERCISE, LINK_STUDENTPUBLICATION, LINK_LEARNPATH LINK_FORUM_THREAD, LINK_ATTENDANCE
7368
 * see gradebook/lib/be/linkfactory
7369
 * @param string    course code
7370
 *
7371
 * @return false|null
7372
 */
7373
function api_block_course_item_locked_by_gradebook($item_id, $link_type, $course_code = null)
7374
{
7375
    if (api_is_platform_admin()) {
7376
        return false;
7377
    }
7378
7379
    if (api_resource_is_locked_by_gradebook($item_id, $link_type, $course_code)) {
7380
        $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');
7381
        api_not_allowed(true, $message);
7382
    }
7383
}
7384
7385
/**
7386
 * Checks the PHP version installed is enough to run Chamilo.
7387
 *
7388
 * @param string Include path (used to load the error page)
7389
 */
7390
function api_check_php_version()
7391
{
7392
    if (!function_exists('version_compare') ||
7393
        version_compare(phpversion(), REQUIRED_PHP_VERSION, '<')
7394
    ) {
7395
        throw new Exception('Wrong PHP version');
7396
    }
7397
}
7398
7399
/**
7400
 * Checks whether the Archive directory is present and writeable. If not,
7401
 * prints a warning message.
7402
 */
7403
function api_check_archive_dir()
7404
{
7405
    if (is_dir(api_get_path(SYS_ARCHIVE_PATH)) && !is_writable(api_get_path(SYS_ARCHIVE_PATH))) {
7406
        $message = Display::return_message(get_lang('The app/cache/ directory, used by this tool, is not writeable. Please contact your platform administrator.'), 'warning');
7407
        api_not_allowed(true, $message);
7408
    }
7409
}
7410
7411
/**
7412
 * Returns an array of global configuration settings which should be ignored
7413
 * when printing the configuration settings screens.
7414
 *
7415
 * @return array Array of strings, each identifying one of the excluded settings
7416
 */
7417
function api_get_locked_settings()
7418
{
7419
    return [
7420
        'permanently_remove_deleted_files',
7421
        'account_valid_duration',
7422
        'service_ppt2lp',
7423
        'wcag_anysurfer_public_pages',
7424
        'upload_extensions_list_type',
7425
        'upload_extensions_blacklist',
7426
        'upload_extensions_whitelist',
7427
        'upload_extensions_skip',
7428
        'upload_extensions_replace_by',
7429
        'hide_dltt_markup',
7430
        'split_users_upload_directory',
7431
        'permissions_for_new_directories',
7432
        'permissions_for_new_files',
7433
        'platform_charset',
7434
        'ldap_description',
7435
        'cas_activate',
7436
        'cas_server',
7437
        'cas_server_uri',
7438
        'cas_port',
7439
        'cas_protocol',
7440
        'cas_add_user_activate',
7441
        'update_user_info_cas_with_ldap',
7442
        'languagePriority1',
7443
        'languagePriority2',
7444
        'languagePriority3',
7445
        'languagePriority4',
7446
        'login_is_email',
7447
        'chamilo_database_version',
7448
    ];
7449
}
7450
7451
/**
7452
 * Checks if the user is corrently logged in. Returns the user ID if he is, or
7453
 * false if he isn't. If the user ID is given and is an integer, then the same
7454
 * ID is simply returned.
7455
 *
7456
 * @param  int User ID
7457
 *
7458
 * @return bool Integer User ID is logged in, or false otherwise
7459
 */
7460
function api_user_is_login($user_id = null)
0 ignored issues
show
Unused Code introduced by
The parameter $user_id is not used and could be removed. ( Ignorable by Annotation )

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

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

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

Loading history...
7461
{
7462
    return Container::getAuthorizationChecker()->isGranted('IS_AUTHENTICATED_FULLY');
7463
}
7464
7465
/**
7466
 * Guess the real ip for register in the database, even in reverse proxy cases.
7467
 * To be recognized, the IP has to be found in either $_SERVER['REMOTE_ADDR'] or
7468
 * in $_SERVER['HTTP_X_FORWARDED_FOR'], which is in common use with rproxies.
7469
 * Note: the result of this function is not SQL-safe. Please escape it before
7470
 * inserting in a database.
7471
 *
7472
 * @return string the user's real ip (unsafe - escape it before inserting to db)
7473
 *
7474
 * @author Jorge Frisancho Jibaja <[email protected]>, USIL - Some changes to allow the use of real IP using reverse proxy
7475
 *
7476
 * @version CEV CHANGE 24APR2012
7477
 */
7478
function api_get_real_ip()
7479
{
7480
    $ip = trim($_SERVER['REMOTE_ADDR']);
7481
    if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
7482
        if (preg_match('/,/', $_SERVER['HTTP_X_FORWARDED_FOR'])) {
7483
            @list($ip1, $ip2) = @explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
7484
        } else {
7485
            $ip1 = $_SERVER['HTTP_X_FORWARDED_FOR'];
7486
        }
7487
        $ip = trim($ip1);
7488
    }
7489
7490
    return $ip;
7491
}
7492
7493
/**
7494
 * Checks whether an IP is included inside an IP range.
7495
 *
7496
 * @param string IP address
7497
 * @param string IP range
7498
 * @param string $ip
7499
 *
7500
 * @return bool True if IP is in the range, false otherwise
7501
 *
7502
 * @author claudiu at cnixs dot com  on http://www.php.net/manual/fr/ref.network.php#55230
7503
 * @author Yannick Warnier for improvements and managment of multiple ranges
7504
 *
7505
 * @todo check for IPv6 support
7506
 */
7507
function api_check_ip_in_range($ip, $range)
7508
{
7509
    if (empty($ip) or empty($range)) {
7510
        return false;
7511
    }
7512
    $ip_ip = ip2long($ip);
7513
    // divide range param into array of elements
7514
    if (false !== strpos($range, ',')) {
7515
        $ranges = explode(',', $range);
7516
    } else {
7517
        $ranges = [$range];
7518
    }
7519
    foreach ($ranges as $range) {
0 ignored issues
show
introduced by
$range is overwriting one of the parameters of this function.
Loading history...
7520
        $range = trim($range);
7521
        if (empty($range)) {
7522
            continue;
7523
        }
7524
        if (false === strpos($range, '/')) {
7525
            if (0 === strcmp($ip, $range)) {
7526
                return true; // there is a direct IP match, return OK
7527
            }
7528
            continue; //otherwise, get to the next range
7529
        }
7530
        // the range contains a "/", so analyse completely
7531
        list($net, $mask) = explode("/", $range);
7532
7533
        $ip_net = ip2long($net);
7534
        // mask binary magic
7535
        $ip_mask = ~((1 << (32 - $mask)) - 1);
7536
7537
        $ip_ip_net = $ip_ip & $ip_mask;
7538
        if ($ip_ip_net == $ip_net) {
7539
            return true;
7540
        }
7541
    }
7542
7543
    return false;
7544
}
7545
7546
function api_check_user_access_to_legal($course_visibility)
7547
{
7548
    $course_visibility_list = [COURSE_VISIBILITY_OPEN_WORLD, COURSE_VISIBILITY_OPEN_PLATFORM];
7549
7550
    return in_array($course_visibility, $course_visibility_list) || api_is_drh();
7551
}
7552
7553
/**
7554
 * Checks if the global chat is enabled or not.
7555
 *
7556
 * @return bool
7557
 */
7558
function api_is_global_chat_enabled()
7559
{
7560
    return
7561
        !api_is_anonymous() &&
7562
        'true' === api_get_setting('allow_global_chat') &&
7563
        'true' === api_get_setting('allow_social_tool');
7564
}
7565
7566
/**
7567
 * @todo Fix tool_visible_by_default_at_creation labels
7568
 * @todo Add sessionId parameter to avoid using context
7569
 *
7570
 * @param int   $item_id
7571
 * @param int   $tool_id
7572
 * @param int   $group_id   id
7573
 * @param array $courseInfo
7574
 * @param int   $sessionId
7575
 * @param int   $userId
7576
 */
7577
function api_set_default_visibility(
7578
    $item_id,
7579
    $tool_id,
7580
    $group_id = 0,
7581
    $courseInfo = [],
7582
    $sessionId = 0,
7583
    $userId = 0
7584
) {
7585
    $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
7586
    $courseId = $courseInfo['real_id'];
7587
    $courseCode = $courseInfo['code'];
7588
    $sessionId = empty($sessionId) ? api_get_session_id() : $sessionId;
7589
    $userId = empty($userId) ? api_get_user_id() : $userId;
7590
7591
    // if group is null force group_id = 0, this force is needed to create a LP folder with group = 0
7592
    if (is_null($group_id)) {
7593
        $group_id = 0;
7594
    } else {
7595
        $group_id = empty($group_id) ? api_get_group_id() : $group_id;
7596
    }
7597
7598
    $groupInfo = [];
7599
    if (!empty($group_id)) {
7600
        $groupInfo = GroupManager::get_group_properties($group_id);
7601
    }
7602
    $original_tool_id = $tool_id;
7603
7604
    switch ($tool_id) {
7605
        case TOOL_LINK:
7606
        case TOOL_LINK_CATEGORY:
7607
            $tool_id = 'links';
7608
            break;
7609
        case TOOL_DOCUMENT:
7610
            $tool_id = 'documents';
7611
            break;
7612
        case TOOL_LEARNPATH:
7613
            $tool_id = 'learning';
7614
            break;
7615
        case TOOL_ANNOUNCEMENT:
7616
            $tool_id = 'announcements';
7617
            break;
7618
        case TOOL_FORUM:
7619
        case TOOL_FORUM_CATEGORY:
7620
        case TOOL_FORUM_THREAD:
7621
            $tool_id = 'forums';
7622
            break;
7623
        case TOOL_QUIZ:
7624
            $tool_id = 'quiz';
7625
            break;
7626
    }
7627
    $setting = api_get_setting('tool_visible_by_default_at_creation');
7628
7629
    if (isset($setting[$tool_id])) {
7630
        $visibility = 'invisible';
7631
        if ('true' == $setting[$tool_id]) {
7632
            $visibility = 'visible';
7633
        }
7634
7635
        // Read the portal and course default visibility
7636
        if ('documents' === $tool_id) {
7637
            $visibility = DocumentManager::getDocumentDefaultVisibility($courseInfo);
7638
        }
7639
7640
        api_item_property_update(
7641
            $courseInfo,
7642
            $original_tool_id,
7643
            $item_id,
7644
            $visibility,
7645
            $userId,
7646
            $groupInfo,
7647
            null,
7648
            null,
7649
            null,
7650
            $sessionId
7651
        );
7652
7653
        // Fixes default visibility for tests
7654
        switch ($original_tool_id) {
7655
            case TOOL_QUIZ:
7656
                if (empty($sessionId)) {
7657
                    $objExerciseTmp = new Exercise($courseId);
7658
                    $objExerciseTmp->read($item_id);
7659
                    if ('visible' == $visibility) {
7660
                        $objExerciseTmp->enable();
7661
                        $objExerciseTmp->save();
7662
                    } else {
7663
                        $objExerciseTmp->disable();
7664
                        $objExerciseTmp->save();
7665
                    }
7666
                }
7667
                break;
7668
        }
7669
    }
7670
}
7671
7672
/**
7673
 * @return string
7674
 */
7675
function api_get_security_key()
7676
{
7677
    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...
7678
}
7679
7680
/**
7681
 * @param int $user_id
7682
 * @param int $courseId
7683
 * @param int $session_id
7684
 *
7685
 * @return array
7686
 */
7687
function api_detect_user_roles($user_id, $courseId, $session_id = 0)
7688
{
7689
    $user_roles = [];
7690
    $courseInfo = api_get_course_info_by_id($courseId);
7691
    $course_code = $courseInfo['code'];
7692
7693
    $url_id = api_get_current_access_url_id();
7694
    if (api_is_platform_admin_by_id($user_id, $url_id)) {
7695
        $user_roles[] = PLATFORM_ADMIN;
7696
    }
7697
7698
    /*if (api_is_drh()) {
7699
        $user_roles[] = DRH;
7700
    }*/
7701
7702
    if (!empty($session_id)) {
7703
        if (SessionManager::user_is_general_coach($user_id, $session_id)) {
7704
            $user_roles[] = SESSION_GENERAL_COACH;
7705
        }
7706
    }
7707
7708
    if (!empty($course_code)) {
7709
        if (empty($session_id)) {
7710
            if (CourseManager::is_course_teacher($user_id, $course_code)) {
7711
                $user_roles[] = COURSEMANAGER;
7712
            }
7713
            if (CourseManager::get_tutor_in_course_status($user_id, $courseInfo['real_id'])) {
7714
                $user_roles[] = COURSE_TUTOR;
7715
            }
7716
7717
            if (CourseManager::is_user_subscribed_in_course($user_id, $course_code)) {
7718
                $user_roles[] = COURSE_STUDENT;
7719
            }
7720
        } else {
7721
            $user_status_in_session = SessionManager::get_user_status_in_course_session(
7722
                $user_id,
7723
                $courseId,
7724
                $session_id
7725
            );
7726
7727
            if (!empty($user_status_in_session)) {
7728
                if (0 == $user_status_in_session) {
7729
                    $user_roles[] = SESSION_STUDENT;
7730
                }
7731
                if (2 == $user_status_in_session) {
7732
                    $user_roles[] = SESSION_COURSE_COACH;
7733
                }
7734
            }
7735
7736
            /*if (api_is_course_session_coach($user_id, $course_code, $session_id)) {
7737
               $user_roles[] = SESSION_COURSE_COACH;
7738
            }*/
7739
        }
7740
    }
7741
7742
    return $user_roles;
7743
}
7744
7745
/**
7746
 * @param int $courseId
7747
 * @param int $session_id
7748
 *
7749
 * @return bool
7750
 */
7751
function api_coach_can_edit_view_results($courseId = null, $session_id = null)
7752
{
7753
    if (api_is_platform_admin()) {
7754
        return true;
7755
    }
7756
7757
    $user_id = api_get_user_id();
7758
7759
    if (empty($courseId)) {
7760
        $courseId = api_get_course_int_id();
7761
    }
7762
7763
    if (empty($session_id)) {
7764
        $session_id = api_get_session_id();
7765
    }
7766
7767
    $roles = api_detect_user_roles($user_id, $courseId, $session_id);
7768
7769
    if (in_array(SESSION_COURSE_COACH, $roles)) {
7770
        //return api_get_setting('session_tutor_reports_visibility') == 'true';
7771
        return true;
7772
    } else {
7773
        if (in_array(COURSEMANAGER, $roles)) {
7774
            return true;
7775
        }
7776
7777
        return false;
7778
    }
7779
}
7780
7781
/**
7782
 * @param string $file
7783
 *
7784
 * @return string
7785
 */
7786
function api_get_js_simple($file)
7787
{
7788
    return '<script type="text/javascript" src="'.$file.'"></script>'."\n";
7789
}
7790
7791
/**
7792
 * Modify default memory_limit and max_execution_time limits
7793
 * Needed when processing long tasks.
7794
 */
7795
function api_set_more_memory_and_time_limits()
7796
{
7797
    if (function_exists('ini_set')) {
7798
        api_set_memory_limit('256M');
7799
        ini_set('max_execution_time', 1800);
7800
    }
7801
}
7802
7803
/**
7804
 * Tries to set memory limit, if authorized and new limit is higher than current.
7805
 *
7806
 * @param string $mem New memory limit
7807
 *
7808
 * @return bool True on success, false on failure or current is higher than suggested
7809
 * @assert (null) === false
7810
 * @assert (-1) === false
7811
 * @assert (0) === true
7812
 * @assert ('1G') === true
7813
 */
7814
function api_set_memory_limit($mem)
7815
{
7816
    //if ini_set() not available, this function is useless
7817
    if (!function_exists('ini_set') || is_null($mem) || -1 == $mem) {
7818
        return false;
7819
    }
7820
7821
    $memory_limit = ini_get('memory_limit');
7822
    if (api_get_bytes_memory_limit($mem) > api_get_bytes_memory_limit($memory_limit)) {
7823
        ini_set('memory_limit', $mem);
7824
7825
        return true;
7826
    }
7827
7828
    return false;
7829
}
7830
7831
/**
7832
 * Gets memory limit in bytes.
7833
 *
7834
 * @param string The memory size (128M, 1G, 1000K, etc)
7835
 *
7836
 * @return int
7837
 * @assert (null) === false
7838
 * @assert ('1t')  === 1099511627776
7839
 * @assert ('1g')  === 1073741824
7840
 * @assert ('1m')  === 1048576
7841
 * @assert ('100k') === 102400
7842
 */
7843
function api_get_bytes_memory_limit($mem)
7844
{
7845
    $size = strtolower(substr($mem, -1));
7846
7847
    switch ($size) {
7848
        case 't':
7849
            $mem = intval(substr($mem, -1)) * 1024 * 1024 * 1024 * 1024;
7850
            break;
7851
        case 'g':
7852
            $mem = intval(substr($mem, 0, -1)) * 1024 * 1024 * 1024;
7853
            break;
7854
        case 'm':
7855
            $mem = intval(substr($mem, 0, -1)) * 1024 * 1024;
7856
            break;
7857
        case 'k':
7858
            $mem = intval(substr($mem, 0, -1)) * 1024;
7859
            break;
7860
        default:
7861
            // we assume it's integer only
7862
            $mem = intval($mem);
7863
            break;
7864
    }
7865
7866
    return $mem;
7867
}
7868
7869
/**
7870
 * Finds all the information about a user from username instead of user id.
7871
 *
7872
 * @param string $officialCode
7873
 *
7874
 * @return array $user_info user_id, lastname, firstname, username, email, ...
7875
 *
7876
 * @author Yannick Warnier <[email protected]>
7877
 */
7878
function api_get_user_info_from_official_code($officialCode)
7879
{
7880
    if (empty($officialCode)) {
7881
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type array.
Loading history...
7882
    }
7883
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
7884
            WHERE official_code ='".Database::escape_string($officialCode)."'";
7885
    $result = Database::query($sql);
7886
    if (Database::num_rows($result) > 0) {
7887
        $result_array = Database::fetch_array($result);
7888
7889
        return _api_format_user($result_array);
7890
    }
7891
7892
    return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type array.
Loading history...
7893
}
7894
7895
/**
7896
 * @param string $usernameInputId
7897
 * @param string $passwordInputId
7898
 *
7899
 * @return string|null
7900
 */
7901
function api_get_password_checker_js($usernameInputId, $passwordInputId)
7902
{
7903
    $checkPass = api_get_setting('allow_strength_pass_checker');
7904
    $useStrengthPassChecker = 'true' === $checkPass;
7905
7906
    if (false === $useStrengthPassChecker) {
7907
        return null;
7908
    }
7909
7910
    $translations = [
7911
        'wordLength' => get_lang('The password is too short'),
7912
        'wordNotEmail' => get_lang('Your password cannot be the same as your email'),
7913
        'wordSimilarToUsername' => get_lang('Your password cannot contain your username'),
7914
        'wordTwoCharacterClasses' => get_lang('Use different character classes'),
7915
        'wordRepetitions' => get_lang('Too many repetitions'),
7916
        'wordSequences' => get_lang('Your password contains sequences'),
7917
        'errorList' => get_lang('errors found'),
7918
        'veryWeak' => get_lang('Very weak'),
7919
        'weak' => get_lang('Weak'),
7920
        'normal' => get_lang('Normal'),
7921
        'medium' => get_lang('Medium'),
7922
        'strong' => get_lang('Strong'),
7923
        'veryStrong' => get_lang('Very strong'),
7924
    ];
7925
7926
    $js = api_get_asset('pwstrength-bootstrap/dist/pwstrength-bootstrap.min.js');
7927
    $js .= "<script>
7928
    var errorMessages = {
7929
        password_to_short : \"".get_lang('The password is too short')."\",
7930
        same_as_username : \"".get_lang('Your password cannot be the same as your username')."\"
7931
    };
7932
7933
    $(function() {
7934
        var lang = ".json_encode($translations).";
7935
        var options = {
7936
            onLoad : function () {
7937
                //$('#messages').text('Start typing password');
7938
            },
7939
            onKeyUp: function (evt) {
7940
                $(evt.target).pwstrength('outputErrorList');
7941
            },
7942
            errorMessages : errorMessages,
7943
            viewports: {
7944
                progress: '#password_progress',
7945
                verdict: '#password-verdict',
7946
                errors: '#password-errors'
7947
            },
7948
            usernameField: '$usernameInputId'
7949
        };
7950
        options.i18n = {
7951
            t: function (key) {
7952
                var result = lang[key];
7953
                return result === key ? '' : result; // This assumes you return the
7954
            }
7955
        };
7956
        $('".$passwordInputId."').pwstrength(options);
7957
    });
7958
    </script>";
7959
7960
    return $js;
7961
}
7962
7963
/**
7964
 * create an user extra field called 'captcha_blocked_until_date'.
7965
 *
7966
 * @param string $username
7967
 *
7968
 * @return bool
7969
 */
7970
function api_block_account_captcha($username)
7971
{
7972
    $userInfo = api_get_user_info_from_username($username);
7973
    if (empty($userInfo)) {
7974
        return false;
7975
    }
7976
    $minutesToBlock = api_get_setting('captcha_time_to_block');
7977
    $time = time() + $minutesToBlock * 60;
7978
    UserManager::update_extra_field_value(
7979
        $userInfo['user_id'],
7980
        'captcha_blocked_until_date',
7981
        api_get_utc_datetime($time)
7982
    );
7983
7984
    return true;
7985
}
7986
7987
/**
7988
 * @param string $username
7989
 *
7990
 * @return bool
7991
 */
7992
function api_clean_account_captcha($username)
7993
{
7994
    $userInfo = api_get_user_info_from_username($username);
7995
    if (empty($userInfo)) {
7996
        return false;
7997
    }
7998
    Session::erase('loginFailedCount');
7999
    UserManager::update_extra_field_value(
8000
        $userInfo['user_id'],
8001
        'captcha_blocked_until_date',
8002
        null
8003
    );
8004
8005
    return true;
8006
}
8007
8008
/**
8009
 * @param string $username
8010
 *
8011
 * @return bool
8012
 */
8013
function api_get_user_blocked_by_captcha($username)
8014
{
8015
    $userInfo = api_get_user_info_from_username($username);
8016
    if (empty($userInfo)) {
8017
        return false;
8018
    }
8019
    $data = UserManager::get_extra_user_data_by_field(
8020
        $userInfo['user_id'],
8021
        'captcha_blocked_until_date'
8022
    );
8023
    if (isset($data) && isset($data['captcha_blocked_until_date'])) {
8024
        return $data['captcha_blocked_until_date'];
8025
    }
8026
8027
    return false;
8028
}
8029
8030
/**
8031
 * Remove tags from HTML anf return the $in_number_char first non-HTML char
8032
 * Postfix the text with "..." if it has been truncated.
8033
 *
8034
 * @param string $text
8035
 * @param int    $number
8036
 *
8037
 * @return string
8038
 *
8039
 * @author hubert borderiou
8040
 */
8041
function api_get_short_text_from_html($text, $number)
8042
{
8043
    // Delete script and style tags
8044
    $text = preg_replace('/(<(script|style)\b[^>]*>).*?(<\/\2>)/is', "$1$3", $text);
8045
    $text = api_html_entity_decode($text);
8046
    $out_res = api_remove_tags_with_space($text, false);
8047
    $postfix = "...";
8048
    if (strlen($out_res) > $number) {
8049
        $out_res = substr($out_res, 0, $number).$postfix;
8050
    }
8051
8052
    return $out_res;
8053
}
8054
8055
/**
8056
 * Replace tags with a space in a text.
8057
 * If $in_double_quote_replace, replace " with '' (for HTML attribute purpose, for exemple).
8058
 *
8059
 * @return string
8060
 *
8061
 * @author hubert borderiou
8062
 */
8063
function api_remove_tags_with_space($in_html, $in_double_quote_replace = true)
8064
{
8065
    $out_res = $in_html;
8066
    if ($in_double_quote_replace) {
8067
        $out_res = str_replace('"', "''", $out_res);
8068
    }
8069
    // avoid text stuck together when tags are removed, adding a space after >
8070
    $out_res = str_replace(">", "> ", $out_res);
8071
    $out_res = strip_tags($out_res);
8072
8073
    return $out_res;
8074
}
8075
8076
/**
8077
 * If true, the drh can access all content (courses, users) inside a session.
8078
 *
8079
 * @return bool
8080
 */
8081
function api_drh_can_access_all_session_content()
8082
{
8083
    $value = api_get_setting('drh_can_access_all_session_content');
8084
8085
    return 'true' === $value;
8086
}
8087
8088
/**
8089
 * @param string $tool
8090
 * @param string $setting
8091
 * @param int    $defaultValue
8092
 *
8093
 * @return string
8094
 */
8095
function api_get_default_tool_setting($tool, $setting, $defaultValue)
8096
{
8097
    global $_configuration;
8098
    if (isset($_configuration[$tool]) &&
8099
        isset($_configuration[$tool]['default_settings']) &&
8100
        isset($_configuration[$tool]['default_settings'][$setting])
8101
    ) {
8102
        return $_configuration[$tool]['default_settings'][$setting];
8103
    }
8104
8105
    return $defaultValue;
8106
}
8107
8108
/**
8109
 * Checks if user can login as another user.
8110
 *
8111
 * @param int $loginAsUserId the user id to log in
8112
 * @param int $userId        my user id
8113
 *
8114
 * @return bool
8115
 */
8116
function api_can_login_as($loginAsUserId, $userId = null)
8117
{
8118
    if (empty($userId)) {
8119
        $userId = api_get_user_id();
8120
    }
8121
    if ($loginAsUserId == $userId) {
8122
        return false;
8123
    }
8124
8125
    if (empty($loginAsUserId)) {
8126
        return false;
8127
    }
8128
8129
    if ($loginAsUserId != strval(intval($loginAsUserId))) {
8130
        return false;
8131
    }
8132
8133
    // Check if the user to login is an admin
8134
    if (api_is_platform_admin_by_id($loginAsUserId)) {
8135
        // Only super admins can login to admin accounts
8136
        if (!api_global_admin_can_edit_admin($loginAsUserId)) {
8137
            return false;
8138
        }
8139
    }
8140
8141
    $userInfo = api_get_user_info($loginAsUserId);
8142
    $isDrh = function () use ($loginAsUserId) {
8143
        if (api_is_drh()) {
8144
            if (api_drh_can_access_all_session_content()) {
8145
                $users = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus(
8146
                    'drh_all',
8147
                    api_get_user_id()
8148
                );
8149
                $userList = [];
8150
                if (is_array($users)) {
8151
                    foreach ($users as $user) {
8152
                        $userList[] = $user['user_id'];
8153
                    }
8154
                }
8155
                if (in_array($loginAsUserId, $userList)) {
8156
                    return true;
8157
                }
8158
            } else {
8159
                if (api_is_drh() &&
8160
                    UserManager::is_user_followed_by_drh($loginAsUserId, api_get_user_id())
8161
                ) {
8162
                    return true;
8163
                }
8164
            }
8165
        }
8166
8167
        return false;
8168
    };
8169
8170
    $loginAsStatusForSessionAdmins = [STUDENT];
8171
8172
    if (api_get_setting('session.allow_session_admin_login_as_teacher')) {
8173
        $loginAsStatusForSessionAdmins[] = COURSEMANAGER;
8174
    }
8175
8176
    return api_is_platform_admin() ||
8177
        (api_is_session_admin() && in_array($userInfo['status'], $loginAsStatusForSessionAdmins)) ||
8178
        $isDrh();
8179
}
8180
8181
/**
8182
 * @return bool
8183
 */
8184
function api_is_allowed_in_course()
8185
{
8186
    if (api_is_platform_admin()) {
8187
        return true;
8188
    }
8189
8190
    $user = api_get_current_user();
8191
    if ($user instanceof User) {
8192
        if ($user->hasRole('ROLE_CURRENT_SESSION_COURSE_STUDENT') ||
8193
            $user->hasRole('ROLE_CURRENT_SESSION_COURSE_TEACHER') ||
8194
            $user->hasRole('ROLE_CURRENT_COURSE_STUDENT') ||
8195
            $user->hasRole('ROLE_CURRENT_COURSE_TEACHER')
8196
        ) {
8197
            return true;
8198
        }
8199
    }
8200
8201
    return false;
8202
}
8203
8204
/**
8205
 * Set the cookie to go directly to the course code $in_firstpage
8206
 * after login.
8207
 *
8208
 * @param string $value is the course code of the course to go
8209
 */
8210
function api_set_firstpage_parameter($value)
8211
{
8212
    setcookie('GotoCourse', $value);
8213
}
8214
8215
/**
8216
 * Delete the cookie to go directly to the course code $in_firstpage
8217
 * after login.
8218
 */
8219
function api_delete_firstpage_parameter()
8220
{
8221
    setcookie('GotoCourse', '', time() - 3600);
8222
}
8223
8224
/**
8225
 * @return bool if course_code for direct course access after login is set
8226
 */
8227
function exist_firstpage_parameter()
8228
{
8229
    return isset($_COOKIE['GotoCourse']) && '' != $_COOKIE['GotoCourse'];
8230
}
8231
8232
/**
8233
 * @return return the course_code of the course where user login
8234
 */
8235
function api_get_firstpage_parameter()
8236
{
8237
    return $_COOKIE['GotoCourse'];
8238
}
8239
8240
/**
8241
 * Return true on https install.
8242
 *
8243
 * @return bool
8244
 */
8245
function api_is_https()
8246
{
8247
    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...
8248
        'https' == $_SERVER['HTTP_X_FORWARDED_PROTO'] || !empty($_configuration['force_https_forwarded_proto'])
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $_configuration seems to never exist and therefore empty should always be true.
Loading history...
8249
    ) {
8250
        $isSecured = true;
8251
    } else {
8252
        if (!empty($_SERVER['HTTPS']) && 'off' != $_SERVER['HTTPS']) {
8253
            $isSecured = true;
8254
        } else {
8255
            $isSecured = false;
8256
            // last chance
8257
            if (!empty($_SERVER['SERVER_PORT']) && 443 == $_SERVER['SERVER_PORT']) {
8258
                $isSecured = true;
8259
            }
8260
        }
8261
    }
8262
8263
    return $isSecured;
8264
}
8265
8266
/**
8267
 * Return protocol (http or https).
8268
 *
8269
 * @return string
8270
 */
8271
function api_get_protocol()
8272
{
8273
    return api_is_https() ? 'https' : 'http';
8274
}
8275
8276
/**
8277
 * Return a string where " are replaced with 2 '
8278
 * It is useful when you pass a PHP variable in a Javascript browser dialog
8279
 * e.g. : alert("<?php get_lang('Message') ?>");
8280
 * and message contains character ".
8281
 *
8282
 * @param string $in_text
8283
 *
8284
 * @return string
8285
 */
8286
function convert_double_quote_to_single($in_text)
8287
{
8288
    return api_preg_replace('/"/', "''", $in_text);
8289
}
8290
8291
/**
8292
 * Get origin.
8293
 *
8294
 * @param string
8295
 *
8296
 * @return string
8297
 */
8298
function api_get_origin()
8299
{
8300
    $origin = isset($_REQUEST['origin']) ? Security::remove_XSS($_REQUEST['origin']) : '';
8301
8302
    return $origin;
8303
}
8304
8305
/**
8306
 * Warns an user that the portal reach certain limit.
8307
 *
8308
 * @param string $limitName
8309
 */
8310
function api_warn_hosting_contact($limitName)
8311
{
8312
    $hostingParams = api_get_configuration_value(1);
8313
    $email = null;
8314
8315
    if (!empty($hostingParams)) {
8316
        if (isset($hostingParams['hosting_contact_mail'])) {
8317
            $email = $hostingParams['hosting_contact_mail'];
8318
        }
8319
    }
8320
8321
    if (!empty($email)) {
8322
        $subject = get_lang('Hosting warning reached');
8323
        $body = get_lang('Portal name').': '.api_get_path(WEB_PATH)." \n ";
8324
        $body .= get_lang('Portal\'s limit type').': '.$limitName." \n ";
8325
        if (isset($hostingParams[$limitName])) {
8326
            $body .= get_lang('Value').': '.$hostingParams[$limitName];
8327
        }
8328
        api_mail_html(null, $email, $subject, $body);
8329
    }
8330
}
8331
8332
/**
8333
 * Gets value of a variable from config/configuration.php
8334
 * Variables that are not set in the configuration.php file but set elsewhere:
8335
 * - virtual_css_theme_folder (vchamilo plugin)
8336
 * - access_url (global.inc.php)
8337
 * - apc/apc_prefix (global.inc.php).
8338
 *
8339
 * @param string $variable
8340
 *
8341
 * @return bool|mixed
8342
 */
8343
function api_get_configuration_value($variable)
8344
{
8345
    global $_configuration;
8346
    // Check the current url id, id = 1 by default
8347
    $urlId = isset($_configuration['access_url']) ? (int) $_configuration['access_url'] : 1;
8348
8349
    $variable = trim($variable);
8350
8351
    // Check if variable exists
8352
    if (isset($_configuration[$variable])) {
8353
        if (is_array($_configuration[$variable])) {
8354
            // Check if it exists for the sub portal
8355
            if (array_key_exists($urlId, $_configuration[$variable])) {
8356
                return $_configuration[$variable][$urlId];
8357
            } else {
8358
                // Try to found element with id = 1 (master portal)
8359
                if (array_key_exists(1, $_configuration[$variable])) {
8360
                    return $_configuration[$variable][1];
8361
                }
8362
            }
8363
        }
8364
8365
        return $_configuration[$variable];
8366
    }
8367
8368
    return false;
8369
}
8370
8371
/**
8372
 * Returns supported image extensions in the portal.
8373
 *
8374
 * @param bool $supportVectors Whether vector images should also be accepted or not
8375
 *
8376
 * @return array Supported image extensions in the portal
8377
 */
8378
function api_get_supported_image_extensions($supportVectors = true)
8379
{
8380
    // jpg can also be called jpeg, jpe, jfif and jif. See https://en.wikipedia.org/wiki/JPEG#JPEG_filename_extensions
8381
    $supportedImageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'jpe', 'jfif', 'jif'];
8382
    if ($supportVectors) {
8383
        array_push($supportedImageExtensions, 'svg');
8384
    }
8385
    if (version_compare(PHP_VERSION, '5.5.0', '>=')) {
8386
        array_push($supportedImageExtensions, 'webp');
8387
    }
8388
8389
    return $supportedImageExtensions;
8390
}
8391
8392
/**
8393
 * This setting changes the registration status for the campus.
8394
 *
8395
 * @author Patrick Cool <[email protected]>, Ghent University
8396
 *
8397
 * @version August 2006
8398
 *
8399
 * @param bool $listCampus Whether we authorize
8400
 *
8401
 * @todo the $_settings should be reloaded here. => write api function for this and use this in global.inc.php also.
8402
 */
8403
function api_register_campus($listCampus = true)
8404
{
8405
    $tbl_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
8406
8407
    $sql = "UPDATE $tbl_settings SET selected_value='true' WHERE variable='registered'";
8408
    Database::query($sql);
8409
8410
    if (!$listCampus) {
8411
        $sql = "UPDATE $tbl_settings SET selected_value='true' WHERE variable='donotlistcampus'";
8412
        Database::query($sql);
8413
    }
8414
}
8415
8416
/**
8417
 * Checks whether current user is a student boss.
8418
 *
8419
 * @global array $_user
8420
 *
8421
 * @return bool
8422
 */
8423
function api_is_student_boss()
8424
{
8425
    $_user = api_get_user_info();
8426
8427
    return isset($_user['status']) && STUDENT_BOSS == $_user['status'];
8428
}
8429
8430
/**
8431
 * Check whether the user type should be exclude.
8432
 * Such as invited or anonymous users.
8433
 *
8434
 * @param bool $checkDB Optional. Whether check the user status
8435
 * @param int  $userId  Options. The user id
8436
 *
8437
 * @return bool
8438
 */
8439
function api_is_excluded_user_type($checkDB = false, $userId = 0)
8440
{
8441
    if ($checkDB) {
8442
        $userId = empty($userId) ? api_get_user_id() : (int) $userId;
8443
8444
        if (0 == $userId) {
8445
            return true;
8446
        }
8447
8448
        $userInfo = api_get_user_info($userId);
8449
8450
        switch ($userInfo['status']) {
8451
            case INVITEE:
8452
            case ANONYMOUS:
8453
                return true;
8454
            default:
8455
                return false;
8456
        }
8457
    }
8458
8459
    $isInvited = api_is_invitee();
8460
    $isAnonymous = api_is_anonymous();
8461
8462
    if ($isInvited || $isAnonymous) {
8463
        return true;
8464
    }
8465
8466
    return false;
8467
}
8468
8469
/**
8470
 * Get the user status to ignore in reports.
8471
 *
8472
 * @param string $format Optional. The result type (array or string)
8473
 *
8474
 * @return array|string
8475
 */
8476
function api_get_users_status_ignored_in_reports($format = 'array')
8477
{
8478
    $excludedTypes = [
8479
        INVITEE,
8480
        ANONYMOUS,
8481
    ];
8482
8483
    if ('string' == $format) {
8484
        return implode(', ', $excludedTypes);
8485
    }
8486
8487
    return $excludedTypes;
8488
}
8489
8490
/**
8491
 * Set the Site Use Cookie Warning for 1 year.
8492
 */
8493
function api_set_site_use_cookie_warning_cookie()
8494
{
8495
    setcookie('ChamiloUsesCookies', 'ok', time() + 31556926);
8496
}
8497
8498
/**
8499
 * Return true if the Site Use Cookie Warning Cookie warning exists.
8500
 *
8501
 * @return bool
8502
 */
8503
function api_site_use_cookie_warning_cookie_exist()
8504
{
8505
    return isset($_COOKIE['ChamiloUsesCookies']);
8506
}
8507
8508
/**
8509
 * Given a number of seconds, format the time to show hours, minutes and seconds.
8510
 *
8511
 * @param int    $time         The time in seconds
8512
 * @param string $originFormat Optional. PHP o JS
8513
 *
8514
 * @return string (00h00'00")
8515
 */
8516
function api_format_time($time, $originFormat = 'php')
8517
{
8518
    $h = get_lang('h');
8519
    $hours = $time / 3600;
8520
    $mins = ($time % 3600) / 60;
8521
    $secs = ($time % 60);
8522
8523
    if ($time < 0) {
8524
        $hours = 0;
8525
        $mins = 0;
8526
        $secs = 0;
8527
    }
8528
8529
    if ('js' == $originFormat) {
8530
        $formattedTime = trim(sprintf("%02d : %02d : %02d", $hours, $mins, $secs));
8531
    } else {
8532
        $formattedTime = trim(sprintf("%02d$h%02d'%02d\"", $hours, $mins, $secs));
8533
    }
8534
8535
    return $formattedTime;
8536
}
8537
8538
/**
8539
 * Create a new empty directory with index.html file.
8540
 *
8541
 * @param string $name            The new directory name
8542
 * @param string $parentDirectory Directory parent directory name
8543
 *
8544
 * @deprecated use Resources
8545
 *
8546
 * @return bool Return true if the directory was create. Otherwise return false
8547
 */
8548
function api_create_protected_dir($name, $parentDirectory)
8549
{
8550
    $isCreated = false;
8551
8552
    if (!is_writable($parentDirectory)) {
8553
        return false;
8554
    }
8555
8556
    $fullPath = $parentDirectory.api_replace_dangerous_char($name);
8557
8558
    if (mkdir($fullPath, api_get_permissions_for_new_directories(), true)) {
8559
        $fp = fopen($fullPath.'/index.html', 'w');
8560
8561
        if ($fp) {
0 ignored issues
show
introduced by
$fp is of type false|resource, thus it always evaluated to false.
Loading history...
8562
            if (fwrite($fp, '<html><head></head><body></body></html>')) {
8563
                $isCreated = true;
8564
            }
8565
        }
8566
8567
        fclose($fp);
0 ignored issues
show
Bug introduced by
It seems like $fp can also be of type false; however, parameter $handle of fclose() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

8567
        fclose(/** @scrutinizer ignore-type */ $fp);
Loading history...
8568
    }
8569
8570
    return $isCreated;
8571
}
8572
8573
/**
8574
 * Sends an email
8575
 * Sender name and email can be specified, if not specified
8576
 * name and email of the platform admin are used.
8577
 *
8578
 * @param string    name of recipient
8579
 * @param string    email of recipient
8580
 * @param string    email subject
8581
 * @param string    email body
8582
 * @param string    sender name
8583
 * @param string    sender e-mail
8584
 * @param array     extra headers in form $headers = array($name => $value) to allow parsing
8585
 * @param array     data file (path and filename)
8586
 * @param bool      True for attaching a embedded file inside content html (optional)
8587
 * @param array     Additional parameters
8588
 *
8589
 * @return bool true if mail was sent
8590
 */
8591
function api_mail_html(
8592
    $recipientName,
8593
    $recipientEmail,
8594
    $subject,
8595
    $body,
8596
    $senderName = '',
8597
    $senderEmail = '',
8598
    $extra_headers = [],
8599
    $data_file = [],
8600
    $embeddedImage = false,
0 ignored issues
show
Unused Code introduced by
The parameter $embeddedImage is not used and could be removed. ( Ignorable by Annotation )

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

8600
    /** @scrutinizer ignore-unused */ $embeddedImage = false,

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

Loading history...
8601
    $additionalParameters = []
8602
) {
8603
    if (!api_valid_email($recipientEmail)) {
8604
        return false;
8605
    }
8606
8607
    // Default values
8608
    $notification = new Notification();
8609
    $defaultEmail = $notification->getDefaultPlatformSenderEmail();
8610
    $defaultName = $notification->getDefaultPlatformSenderName();
8611
8612
    // If the parameter is set don't use the admin.
8613
    $senderName = !empty($senderName) ? $senderName : $defaultName;
8614
    $senderEmail = !empty($senderEmail) ? $senderEmail : $defaultEmail;
8615
8616
    // Reply to first
8617
    $replyToName = '';
8618
    $replyToEmail = '';
8619
    if (isset($extra_headers['reply_to'])) {
8620
        $replyToEmail = $extra_headers['reply_to']['mail'];
8621
        $replyToName = $extra_headers['reply_to']['name'];
8622
    }
8623
8624
    try {
8625
        $message = new TemplatedEmail();
8626
        $message->subject($subject);
8627
8628
        $list = api_get_configuration_value('send_all_emails_to');
8629
        if (!empty($list) && isset($list['emails'])) {
8630
            foreach ($list['emails'] as $email) {
8631
                $message->cc($email);
8632
            }
8633
        }
8634
8635
        // Attachment
8636
        if (!empty($data_file)) {
8637
            foreach ($data_file as $file_attach) {
8638
                if (!empty($file_attach['path']) && !empty($file_attach['filename'])) {
8639
                    $message->attachFromPath($file_attach['path'], $file_attach['filename']);
8640
                }
8641
            }
8642
        }
8643
8644
        $noReply = api_get_setting('noreply_email_address');
8645
        $automaticEmailText = '';
8646
        if (!empty($noReply)) {
8647
            $automaticEmailText = '<br />'.get_lang('This is an automatic email message. Please do not reply to it.');
8648
        }
8649
8650
        $params = [
8651
            'mail_header_style' => api_get_configuration_value('mail_header_style'),
8652
            'mail_content_style' => api_get_configuration_value('mail_content_style'),
8653
            'link' => $additionalParameters['link'] ?? '',
8654
            'automatic_email_text' => $automaticEmailText,
8655
            'content' => $body,
8656
            'theme' => api_get_visual_theme(),
8657
        ];
8658
8659
        if (!empty($senderEmail)) {
8660
            $message->from(new Address($senderEmail, $senderName));
8661
        }
8662
8663
        if (!empty($recipientEmail)) {
8664
            $message->to(new Address($recipientEmail, $recipientName));
8665
        }
8666
8667
        if (!empty($replyToEmail)) {
8668
            $message->replyTo(new Address($replyToEmail, $replyToName));
8669
        }
8670
8671
        $message
8672
            ->htmlTemplate('ChamiloThemeBundle:Mailer:Default/default.html.twig')
8673
            ->textTemplate('ChamiloThemeBundle:Mailer:Default/default.text.twig')
8674
        ;
8675
        $message->context($params);
8676
        Container::getMailer()->send($message);
8677
8678
        return true;
8679
    } catch (Exception $e) {
8680
        error_log($e->getMessage());
8681
    }
8682
8683
    if (!empty($additionalParameters)) {
8684
        $plugin = new AppPlugin();
8685
        $smsPlugin = $plugin->getSMSPluginLibrary();
8686
        if ($smsPlugin) {
0 ignored issues
show
introduced by
$smsPlugin is of type SmsPluginLibraryInterface, thus it always evaluated to true.
Loading history...
8687
            $smsPlugin->send($additionalParameters);
8688
        }
8689
    }
8690
8691
    return 1;
0 ignored issues
show
Bug Best Practice introduced by
The expression return 1 returns the type integer which is incompatible with the documented return type boolean.
Loading history...
8692
}
8693
8694
/**
8695
 * @param string $tool       Possible values: GroupManager::GROUP_TOOL_*
8696
 * @param bool   $showHeader
8697
 */
8698
function api_protect_course_group($tool, $showHeader = true)
8699
{
8700
    $groupId = api_get_group_id();
8701
    if (!empty($groupId)) {
8702
        if (api_is_platform_admin()) {
8703
            return true;
8704
        }
8705
8706
        if (api_is_allowed_to_edit(false, true, true)) {
8707
            return true;
8708
        }
8709
8710
        $userId = api_get_user_id();
8711
        $sessionId = api_get_session_id();
8712
        if (!empty($sessionId)) {
8713
            if (api_is_coach($sessionId, api_get_course_int_id())) {
8714
                return true;
8715
            }
8716
8717
            if (api_is_drh()) {
8718
                if (SessionManager::isUserSubscribedAsHRM($sessionId, $userId)) {
8719
                    return true;
8720
                }
8721
            }
8722
        }
8723
8724
        $groupInfo = GroupManager::get_group_properties($groupId);
8725
8726
        // Group doesn't exists
8727
        if (empty($groupInfo)) {
8728
            api_not_allowed($showHeader);
8729
        }
8730
8731
        // Check group access
8732
        $allow = GroupManager::user_has_access(
8733
            $userId,
8734
            $groupInfo['iid'],
8735
            $tool
8736
        );
8737
8738
        if (!$allow) {
8739
            api_not_allowed($showHeader);
8740
        }
8741
    }
8742
}
8743
8744
/**
8745
 * Check if a date is in a date range.
8746
 *
8747
 * @param datetime $startDate
8748
 * @param datetime $endDate
8749
 * @param datetime $currentDate
8750
 *
8751
 * @return bool true if date is in rage, false otherwise
8752
 */
8753
function api_is_date_in_date_range($startDate, $endDate, $currentDate = null)
8754
{
8755
    $startDate = strtotime(api_get_local_time($startDate));
8756
    $endDate = strtotime(api_get_local_time($endDate));
8757
    $currentDate = strtotime(api_get_local_time($currentDate));
8758
8759
    if ($currentDate >= $startDate && $currentDate <= $endDate) {
8760
        return true;
8761
    }
8762
8763
    return false;
8764
}
8765
8766
/**
8767
 * Eliminate the duplicates of a multidimensional array by sending the key.
8768
 *
8769
 * @param array $array multidimensional array
8770
 * @param int   $key   key to find to compare
8771
 *
8772
 * @return array
8773
 */
8774
function api_unique_multidim_array($array, $key)
8775
{
8776
    $temp_array = [];
8777
    $i = 0;
8778
    $key_array = [];
8779
8780
    foreach ($array as $val) {
8781
        if (!in_array($val[$key], $key_array)) {
8782
            $key_array[$i] = $val[$key];
8783
            $temp_array[$i] = $val;
8784
        }
8785
        $i++;
8786
    }
8787
8788
    return $temp_array;
8789
}
8790
8791
/**
8792
 * Limit the access to Session Admins when the limit_session_admin_role
8793
 * configuration variable is set to true.
8794
 */
8795
function api_protect_limit_for_session_admin()
8796
{
8797
    $limitAdmin = api_get_setting('limit_session_admin_role');
8798
    if (api_is_session_admin() && 'true' === $limitAdmin) {
8799
        api_not_allowed(true);
8800
    }
8801
}
8802
8803
/**
8804
 * Limits that a session admin has access to list users.
8805
 * When limit_session_admin_list_users configuration variable is set to true.
8806
 */
8807
function api_protect_session_admin_list_users()
8808
{
8809
    $limitAdmin = api_get_configuration_value('limit_session_admin_list_users');
8810
8811
    if (api_is_session_admin() && true === $limitAdmin) {
8812
        api_not_allowed(true);
8813
    }
8814
}
8815
8816
/**
8817
 * @return bool
8818
 */
8819
function api_is_student_view_active()
8820
{
8821
    $studentView = Session::read('studentview');
8822
8823
    return 'studentview' === $studentView;
8824
}
8825
8826
/**
8827
 * Adds a file inside the upload/$type/id.
8828
 *
8829
 * @param string $type
8830
 * @param array  $file
8831
 * @param int    $itemId
8832
 * @param string $cropParameters
8833
 *
8834
 * @deprecated use Resources
8835
 *
8836
 * @return array|bool
8837
 */
8838
function api_upload_file($type, $file, $itemId, $cropParameters = '')
8839
{
8840
    $upload = process_uploaded_file($file);
8841
    if ($upload) {
8842
        $name = api_replace_dangerous_char($file['name']);
8843
8844
        // No "dangerous" files
8845
        $name = disable_dangerous_file($name);
8846
8847
        $pathId = '/'.substr((string) $itemId, 0, 1).'/'.$itemId.'/';
8848
        $path = api_get_path(SYS_UPLOAD_PATH).$type.$pathId;
8849
8850
        if (!is_dir($path)) {
8851
            mkdir($path, api_get_permissions_for_new_directories(), true);
8852
        }
8853
8854
        $pathToSave = $path.$name;
8855
        $result = moveUploadedFile($file, $pathToSave);
8856
8857
        if ($result) {
8858
            if (!empty($cropParameters)) {
8859
                $image = new Image($pathToSave);
8860
                $image->crop($cropParameters);
8861
            }
8862
8863
            return ['path_to_save' => $pathId.$name];
8864
        }
8865
8866
        return false;
8867
    }
8868
}
8869
8870
/**
8871
 * @param string $type
8872
 * @param int    $itemId
8873
 * @param string $file
8874
 *
8875
 * @return bool
8876
 */
8877
function api_get_uploaded_web_url($type, $itemId, $file)
8878
{
8879
    return api_get_uploaded_file($type, $itemId, $file, true);
8880
}
8881
8882
/**
8883
 * @param string $type
8884
 * @param int    $itemId
8885
 * @param string $file
8886
 * @param bool   $getUrl
8887
 *
8888
 * @return bool
8889
 */
8890
function api_get_uploaded_file($type, $itemId, $file, $getUrl = false)
8891
{
8892
    $itemId = (int) $itemId;
8893
    $pathId = '/'.substr((string) $itemId, 0, 1).'/'.$itemId.'/';
8894
    $path = api_get_path(SYS_UPLOAD_PATH).$type.$pathId;
8895
    $file = basename($file);
8896
    $file = $path.'/'.$file;
8897
    if (Security::check_abs_path($file, $path) && is_file($file) && file_exists($file)) {
8898
        if ($getUrl) {
8899
            return str_replace(api_get_path(SYS_UPLOAD_PATH), api_get_path(WEB_UPLOAD_PATH), $file);
0 ignored issues
show
Bug Best Practice introduced by
The expression return str_replace(api_g...EB_UPLOAD_PATH), $file) returns the type string which is incompatible with the documented return type boolean.
Loading history...
8900
        }
8901
8902
        return $file;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $file returns the type string which is incompatible with the documented return type boolean.
Loading history...
8903
    }
8904
8905
    return false;
8906
}
8907
8908
/**
8909
 * @param string $type
8910
 * @param int    $itemId
8911
 * @param string $file
8912
 * @param string $title
8913
 */
8914
function api_download_uploaded_file($type, $itemId, $file, $title = '')
8915
{
8916
    $file = api_get_uploaded_file($type, $itemId, $file);
8917
    if ($file) {
8918
        if (Security::check_abs_path($file, api_get_path(SYS_UPLOAD_PATH).$type)) {
8919
            DocumentManager::file_send_for_download($file, true, $title);
8920
            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...
8921
        }
8922
    }
8923
    api_not_allowed(true);
8924
}
8925
8926
/**
8927
 * @param string $type
8928
 * @param string $file
8929
 */
8930
function api_remove_uploaded_file($type, $file)
8931
{
8932
    $typePath = api_get_path(SYS_UPLOAD_PATH).$type;
8933
    $path = $typePath.'/'.$file;
8934
    if (Security::check_abs_path($path, $typePath) && file_exists($path) && is_file($path)) {
8935
        unlink($path);
8936
    }
8937
}
8938
8939
/**
8940
 * @param string $type
8941
 * @param int    $itemId
8942
 * @param string $file
8943
 *
8944
 * @return bool
8945
 */
8946
function api_remove_uploaded_file_by_id($type, $itemId, $file)
8947
{
8948
    $file = api_get_uploaded_file($type, $itemId, $file, false);
8949
    $typePath = api_get_path(SYS_UPLOAD_PATH).$type;
8950
    if (Security::check_abs_path($file, $typePath) && file_exists($file) && is_file($file)) {
8951
        unlink($file);
8952
8953
        return true;
8954
    }
8955
8956
    return false;
8957
}
8958
8959
/**
8960
 * Converts string value to float value.
8961
 *
8962
 * 3.141516 => 3.141516
8963
 * 3,141516 => 3.141516
8964
 *
8965
 * @todo WIP
8966
 *
8967
 * @param string $number
8968
 *
8969
 * @return float
8970
 */
8971
function api_float_val($number)
8972
{
8973
    $number = (float) str_replace(',', '.', trim($number));
8974
8975
    return $number;
8976
}
8977
8978
/**
8979
 * Converts float values
8980
 * Example if $decimals = 2.
8981
 *
8982
 * 3.141516 => 3.14
8983
 * 3,141516 => 3,14
8984
 *
8985
 * @param string $number            number in iso code
8986
 * @param int    $decimals
8987
 * @param string $decimalSeparator
8988
 * @param string $thousandSeparator
8989
 *
8990
 * @return bool|string
8991
 */
8992
function api_number_format($number, $decimals = 0, $decimalSeparator = '.', $thousandSeparator = ',')
8993
{
8994
    $number = api_float_val($number);
8995
8996
    return number_format($number, $decimals, $decimalSeparator, $thousandSeparator);
8997
}
8998
8999
/**
9000
 * Set location url with a exit break by default.
9001
 *
9002
 * @param $url
9003
 * @param bool $exit
9004
 */
9005
function location($url, $exit = true)
9006
{
9007
    header('Location: '.$url);
9008
9009
    if ($exit) {
9010
        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...
9011
    }
9012
}
9013
9014
/**
9015
 * @return string
9016
 */
9017
function api_get_web_url()
9018
{
9019
    if ('test' === api_get_setting('server_type')) {
9020
        return api_get_path(WEB_PATH).'web/app_dev.php/';
9021
    } else {
9022
        return api_get_path(WEB_PATH).'web/';
9023
    }
9024
}
9025
9026
/**
9027
 * @param string $from
9028
 * @param string $to
9029
 *
9030
 * @return string
9031
 */
9032
function api_get_relative_path($from, $to)
9033
{
9034
    // some compatibility fixes for Windows paths
9035
    $from = is_dir($from) ? rtrim($from, '\/').'/' : $from;
9036
    $to = is_dir($to) ? rtrim($to, '\/').'/' : $to;
9037
    $from = str_replace('\\', '/', $from);
9038
    $to = str_replace('\\', '/', $to);
9039
9040
    $from = explode('/', $from);
9041
    $to = explode('/', $to);
9042
    $relPath = $to;
9043
9044
    foreach ($from as $depth => $dir) {
9045
        // find first non-matching dir
9046
        if ($dir === $to[$depth]) {
9047
            // ignore this directory
9048
            array_shift($relPath);
9049
        } else {
9050
            // get number of remaining dirs to $from
9051
            $remaining = count($from) - $depth;
9052
            if ($remaining > 1) {
9053
                // add traversals up to first matching dir
9054
                $padLength = (count($relPath) + $remaining - 1) * -1;
9055
                $relPath = array_pad($relPath, $padLength, '..');
9056
                break;
9057
            } else {
9058
                $relPath[0] = './'.$relPath[0];
9059
            }
9060
        }
9061
    }
9062
9063
    return implode('/', $relPath);
9064
}
9065
9066
/**
9067
 * Unserialize content using Brummann\Polyfill\Unserialize.
9068
 *
9069
 * @param string $type
9070
 * @param string $serialized
9071
 * @param bool   $ignoreErrors. Optional.
9072
 *
9073
 * @return mixed
9074
 */
9075
function api_unserialize_content($type, $serialized, $ignoreErrors = false)
9076
{
9077
    switch ($type) {
9078
        case 'career':
9079
        case 'sequence_graph':
9080
            $allowedClasses = [Graph::class, VerticesMap::class, Vertices::class, Edges::class];
9081
            break;
9082
        case 'lp':
9083
            $allowedClasses = [
9084
                learnpath::class,
9085
                learnpathItem::class,
9086
                aicc::class,
9087
                aiccBlock::class,
9088
                aiccItem::class,
9089
                aiccObjective::class,
9090
                aiccResource::class,
9091
                scorm::class,
9092
                scormItem::class,
9093
                scormMetadata::class,
9094
                scormOrganization::class,
9095
                scormResource::class,
9096
                Link::class,
9097
                LpItem::class,
9098
            ];
9099
            break;
9100
        case 'course':
9101
            $allowedClasses = [
9102
                Course::class,
9103
                Announcement::class,
9104
                Attendance::class,
9105
                CalendarEvent::class,
9106
                CourseCopyLearnpath::class,
9107
                CourseCopyTestCategory::class,
9108
                CourseDescription::class,
9109
                CourseSession::class,
9110
                Document::class,
9111
                Forum::class,
9112
                ForumCategory::class,
9113
                ForumPost::class,
9114
                ForumTopic::class,
9115
                Glossary::class,
9116
                GradeBookBackup::class,
9117
                Link::class,
9118
                LinkCategory::class,
9119
                Quiz::class,
9120
                QuizQuestion::class,
9121
                QuizQuestionOption::class,
9122
                ScormDocument::class,
9123
                Survey::class,
9124
                SurveyInvitation::class,
9125
                SurveyQuestion::class,
9126
                Thematic::class,
9127
                ToolIntro::class,
9128
                Wiki::class,
9129
                Work::class,
9130
                stdClass::class,
9131
            ];
9132
            break;
9133
        case 'not_allowed_classes':
9134
        default:
9135
            $allowedClasses = false;
9136
    }
9137
9138
    if ($ignoreErrors) {
9139
        return @Unserialize::unserialize(
9140
            $serialized,
9141
            ['allowed_classes' => $allowedClasses]
9142
        );
9143
    }
9144
9145
    return Unserialize::unserialize(
9146
        $serialized,
9147
        ['allowed_classes' => $allowedClasses]
9148
    );
9149
}
9150
9151
/**
9152
 * @param string $template
9153
 *
9154
 * @return string
9155
 */
9156
function api_find_template($template)
9157
{
9158
    return Template::findTemplateFilePath($template);
9159
}
9160
9161
/**
9162
 * @return array
9163
 */
9164
function api_get_language_list_for_flag()
9165
{
9166
    $table = Database::get_main_table(TABLE_MAIN_LANGUAGE);
9167
    $sql = "SELECT english_name, isocode FROM $table
9168
            ORDER BY original_name ASC";
9169
    static $languages = [];
9170
    if (empty($languages)) {
9171
        $result = Database::query($sql);
9172
        while ($row = Database::fetch_array($result)) {
9173
            $languages[$row['english_name']] = $row['isocode'];
9174
        }
9175
        $languages['english'] = 'gb';
9176
    }
9177
9178
    return $languages;
9179
}
9180
9181
/**
9182
 * @param string $name
9183
 *
9184
 * @return \ZipStream\ZipStream
9185
 */
9186
function api_create_zip($name)
9187
{
9188
    $zipStreamOptions = new \ZipStream\Option\Archive();
9189
    $zipStreamOptions->setSendHttpHeaders(true);
9190
    $zipStreamOptions->setContentDisposition('attachment');
9191
    $zipStreamOptions->setContentType('application/x-zip');
9192
9193
    $zip = new \ZipStream\ZipStream($name, $zipStreamOptions);
9194
9195
    return $zip;
9196
}
9197
9198
/**
9199
 * @return string
9200
 */
9201
function api_get_language_translate_html()
9202
{
9203
    $translate = api_get_configuration_value('translate_html');
9204
9205
    if (!$translate) {
9206
        return '';
9207
    }
9208
9209
    $languageList = api_get_languages();
9210
    $hideAll = '';
9211
    foreach ($languageList['all'] as $language) {
9212
        $hideAll .= '
9213
        $("span:lang('.$language['isocode'].')").filter(
9214
            function(e, val) {
9215
                // Only find the spans if they have set the lang
9216
                if ($(this).attr("lang") == null) {
9217
                    return false;
9218
                }
9219
9220
                // Ignore ckeditor classes
9221
                return !this.className.match(/cke(.*)/);
9222
        }).hide();'."\n";
9223
    }
9224
9225
    $userInfo = api_get_user_info();
9226
    $languageId = api_get_language_id($userInfo['language']);
9227
    $languageInfo = api_get_language_info($languageId);
9228
    $isoCode = 'en';
9229
9230
    if (!empty($languageInfo)) {
9231
        $isoCode = $languageInfo['isocode'];
9232
    }
9233
9234
    return '
9235
            $(function() {
9236
                '.$hideAll.'
9237
                var defaultLanguageFromUser = "'.$isoCode.'";
9238
9239
                $("span:lang('.$isoCode.')").filter(
9240
                    function() {
9241
                        // Ignore ckeditor classes
9242
                        return !this.className.match(/cke(.*)/);
9243
                }).show();
9244
9245
                var defaultLanguage = "";
9246
                var langFromUserFound = false;
9247
9248
                $(this).find("span").filter(
9249
                    function() {
9250
                        // Ignore ckeditor classes
9251
                        return !this.className.match(/cke(.*)/);
9252
                }).each(function() {
9253
                    defaultLanguage = $(this).attr("lang");
9254
                    if (defaultLanguage) {
9255
                        $(this).before().next("br").remove();
9256
                        if (defaultLanguageFromUser == defaultLanguage) {
9257
                            langFromUserFound = true;
9258
                        }
9259
                    }
9260
                });
9261
9262
                // Show default language
9263
                if (langFromUserFound == false && defaultLanguage) {
9264
                    $("span:lang("+defaultLanguage+")").filter(
9265
                    function() {
9266
                            // Ignore ckeditor classes
9267
                            return !this.className.match(/cke(.*)/);
9268
                    }).show();
9269
                }
9270
            });
9271
    ';
9272
}
9273