Completed
Push — master ( 1a5e2c...34133a )
by Julito
08:10
created

api_get_course_plugin_setting()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 19
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

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

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

1545
    /** @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...
1546
) {
1547
    // Make sure user_id is safe
1548
    $user_id = (int) $user_id;
1549
    $user = false;
1550
    if (empty($user_id)) {
1551
        $userFromSession = Session::read('_user');
1552
        if (isset($userFromSession) && !empty($userFromSession)) {
1553
            return $userFromSession;
1554
            /*
1555
            return _api_format_user(
1556
                $userFromSession,
1557
                $showPassword,
1558
                $loadAvatars
1559
            );*/
1560
        }
1561
1562
        return false;
1563
    }
1564
1565
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1566
            WHERE id = $user_id";
1567
    $result = Database::query($sql);
1568
    if (Database::num_rows($result) > 0) {
1569
        $result_array = Database::fetch_array($result);
1570
        $result_array['user_is_online_in_chat'] = 0;
1571
        if ($checkIfUserOnline) {
1572
            $use_status_in_platform = user_is_online($user_id);
1573
            $result_array['user_is_online'] = $use_status_in_platform;
1574
            $user_online_in_chat = 0;
1575
            if ($use_status_in_platform) {
1576
                $user_status = UserManager::get_extra_user_data_by_field(
1577
                    $user_id,
1578
                    'user_chat_status',
1579
                    false,
1580
                    true
1581
                );
1582
                if (1 == (int) $user_status['user_chat_status']) {
1583
                    $user_online_in_chat = 1;
1584
                }
1585
            }
1586
            $result_array['user_is_online_in_chat'] = $user_online_in_chat;
1587
        }
1588
1589
        if ($loadExtraData) {
1590
            $fieldValue = new ExtraFieldValue('user');
1591
            $result_array['extra'] = $fieldValue->getAllValuesForAnItem(
1592
                $user_id,
1593
                $loadOnlyVisibleExtraData
1594
            );
1595
        }
1596
        $user = _api_format_user($result_array, $showPassword, $loadAvatars);
1597
    }
1598
1599
    return $user;
1600
}
1601
1602
function api_get_user_info_from_entity(
1603
    User $user,
1604
    $checkIfUserOnline = false,
1605
    $showPassword = false,
1606
    $loadExtraData = false,
1607
    $loadOnlyVisibleExtraData = false,
1608
    $loadAvatars = true,
1609
    $loadCertificate = false
1610
) {
1611
    if (!$user instanceof UserInterface) {
1612
        return false;
1613
    }
1614
1615
    // Make sure user_id is safe
1616
    $user_id = (int) $user->getId();
1617
1618
    if (empty($user_id)) {
1619
        $userFromSession = Session::read('_user');
1620
1621
        if (isset($userFromSession) && !empty($userFromSession)) {
1622
            return $userFromSession;
1623
        }
1624
1625
        return false;
1626
    }
1627
1628
    $result = [];
1629
    $result['user_is_online_in_chat'] = 0;
1630
    if ($checkIfUserOnline) {
1631
        $use_status_in_platform = user_is_online($user_id);
1632
        $result['user_is_online'] = $use_status_in_platform;
1633
        $user_online_in_chat = 0;
1634
        if ($use_status_in_platform) {
1635
            $user_status = UserManager::get_extra_user_data_by_field(
1636
                $user_id,
1637
                'user_chat_status',
1638
                false,
1639
                true
1640
            );
1641
            if (1 == (int) $user_status['user_chat_status']) {
1642
                $user_online_in_chat = 1;
1643
            }
1644
        }
1645
        $result['user_is_online_in_chat'] = $user_online_in_chat;
1646
    }
1647
1648
    if ($loadExtraData) {
1649
        $fieldValue = new ExtraFieldValue('user');
1650
        $result['extra'] = $fieldValue->getAllValuesForAnItem(
1651
            $user_id,
1652
            $loadOnlyVisibleExtraData
1653
        );
1654
    }
1655
1656
    $result['username'] = $user->getUsername();
1657
    $result['status'] = $user->getStatus();
1658
    $result['firstname'] = $user->getFirstname();
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $result['firstname'] is correct as $user->getFirstname() targeting Chamilo\CoreBundle\Entity\User::getFirstname() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
1659
    $result['lastname'] = $user->getLastname();
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $result['lastname'] is correct as $user->getLastname() targeting Chamilo\CoreBundle\Entity\User::getLastname() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
1660
    $result['email'] = $result['mail'] = $user->getEmail();
1661
    $result['complete_name'] = api_get_person_name($result['firstname'], $result['lastname']);
1662
    $result['complete_name_with_username'] = $result['complete_name'];
1663
1664
    if (!empty($result['username']) && 'false' === api_get_setting('profile.hide_username_with_complete_name')) {
1665
        $result['complete_name_with_username'] = $result['complete_name'].' ('.$result['username'].')';
1666
    }
1667
1668
    $showEmail = 'true' === api_get_setting('show_email_addresses');
1669
    if (!empty($result['email'])) {
1670
        $result['complete_name_with_email_forced'] = $result['complete_name'].' ('.$result['email'].')';
1671
        if ($showEmail) {
1672
            $result['complete_name_with_email'] = $result['complete_name'].' ('.$result['email'].')';
1673
        }
1674
    } else {
1675
        $result['complete_name_with_email'] = $result['complete_name'];
1676
        $result['complete_name_with_email_forced'] = $result['complete_name'];
1677
    }
1678
1679
    // Kept for historical reasons
1680
    $result['firstName'] = $result['firstname'];
1681
    $result['lastName'] = $result['lastname'];
1682
1683
    $attributes = [
1684
        'picture_uri',
1685
        'last_login',
1686
        'user_is_online',
1687
    ];
1688
1689
    $result['phone'] = $user->getPhone();
1690
    $result['address'] = $user->getAddress();
1691
    $result['official_code'] = $user->getOfficialCode();
1692
    $result['active'] = $user->getActive();
1693
    $result['auth_source'] = $user->getAuthSource();
1694
    $result['language'] = $user->getLanguage();
1695
    $result['creator_id'] = $user->getCreatorId();
1696
    $result['registration_date'] = $user->getRegistrationDate()->format('Y-m-d H:i:s');
1697
    $result['hr_dept_id'] = $user->getHrDeptId();
1698
    $result['expiration_date'] = $user->getExpirationDate()->format('Y-m-d H:i:s');
1699
1700
    $result['last_login'] = null;
1701
    if ($user->getLastLogin()) {
1702
        $result['last_login'] = $user->getLastLogin()->format('Y-m-d H:i:s');
1703
    }
1704
1705
    $result['competences'] = $user->getCompetences();
1706
    $result['diplomas'] = $user->getDiplomas();
1707
    $result['teach'] = $user->getTeach();
1708
    $result['openarea'] = $user->getOpenarea();
1709
    $user_id = (int) $user->getId();
1710
1711
    // Maintain the user_id index for backwards compatibility
1712
    $result['user_id'] = $result['id'] = $user_id;
1713
1714
    if ($loadCertificate) {
1715
        $hasCertificates = Certificate::getCertificateByUser($user_id);
1716
        $result['has_certificates'] = 0;
1717
        if (!empty($hasCertificates)) {
1718
            $result['has_certificates'] = 1;
1719
        }
1720
    }
1721
1722
    $result['icon_status'] = '';
1723
    $result['icon_status_medium'] = '';
1724
    $result['is_admin'] = UserManager::is_admin($user_id);
1725
1726
    // Getting user avatar.
1727
    if ($loadAvatars) {
1728
        $result['avatar'] = '';
1729
        $result['avatar_no_query'] = '';
1730
        $result['avatar_small'] = '';
1731
        $result['avatar_medium'] = '';
1732
1733
        /*if (!isset($user['avatar'])) {
1734
            $originalFile = UserManager::getUserPicture(
1735
                $user_id,
1736
                USER_IMAGE_SIZE_ORIGINAL,
1737
                null,
1738
                $result
1739
            );
1740
            $result['avatar'] = $originalFile;
1741
            $avatarString = explode('?', $result['avatar']);
1742
            $result['avatar_no_query'] = reset($avatarString);
1743
        } else {
1744
            $result['avatar'] = $user['avatar'];
1745
            $avatarString = explode('?', $user['avatar']);
1746
            $result['avatar_no_query'] = reset($avatarString);
1747
        }
1748
1749
        if (!isset($user['avatar_small'])) {
1750
            $smallFile = UserManager::getUserPicture(
1751
                $user_id,
1752
                USER_IMAGE_SIZE_SMALL,
1753
                null,
1754
                $result
1755
            );
1756
            $result['avatar_small'] = $smallFile;
1757
        } else {
1758
            $result['avatar_small'] = $user['avatar_small'];
1759
        }
1760
1761
        if (!isset($user['avatar_medium'])) {
1762
            $mediumFile = UserManager::getUserPicture(
1763
                $user_id,
1764
                USER_IMAGE_SIZE_MEDIUM,
1765
                null,
1766
                $result
1767
            );
1768
            $result['avatar_medium'] = $mediumFile;
1769
        } else {
1770
            $result['avatar_medium'] = $user['avatar_medium'];
1771
        }*/
1772
1773
        //$urlImg = api_get_path(WEB_IMG_PATH);
1774
        $urlImg = '/';
1775
        $iconStatus = '';
1776
        $iconStatusMedium = '';
1777
1778
        switch ($user->getStatus()) {
1779
            case STUDENT:
1780
                if (isset($result['has_certificates']) && $result['has_certificates']) {
1781
                    $iconStatus = $urlImg.'icons/svg/identifier_graduated.svg';
1782
                } else {
1783
                    $iconStatus = $urlImg.'icons/svg/identifier_student.svg';
1784
                }
1785
                break;
1786
            case COURSEMANAGER:
1787
                if ($result['is_admin']) {
1788
                    $iconStatus = $urlImg.'icons/svg/identifier_admin.svg';
1789
                } else {
1790
                    $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1791
                }
1792
                break;
1793
            case STUDENT_BOSS:
1794
                $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1795
                break;
1796
        }
1797
1798
        if (!empty($iconStatus)) {
1799
            $iconStatusMedium = '<img src="'.$iconStatus.'" width="32px" height="32px">';
1800
            $iconStatus = '<img src="'.$iconStatus.'" width="22px" height="22px">';
1801
        }
1802
1803
        $result['icon_status'] = $iconStatus;
1804
        $result['icon_status_medium'] = $iconStatusMedium;
1805
    }
1806
1807
    if (isset($result['user_is_online'])) {
1808
        $result['user_is_online'] = true == $result['user_is_online'] ? 1 : 0;
1809
    }
1810
    if (isset($result['user_is_online_in_chat'])) {
1811
        $result['user_is_online_in_chat'] = (int) $result['user_is_online_in_chat'];
1812
    }
1813
1814
    $result['password'] = '';
1815
    if ($showPassword) {
1816
        $result['password'] = $user->getPassword();
1817
    }
1818
1819
    if (isset($result['profile_completed'])) {
1820
        $result['profile_completed'] = $result['profile_completed'];
1821
    }
1822
1823
    $result['profile_url'] = api_get_path(WEB_CODE_PATH).'social/profile.php?u='.$user_id;
1824
1825
    // Send message link
1826
    $sendMessage = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&user_id='.$user_id;
1827
    $result['complete_name_with_message_link'] = Display::url(
1828
        $result['complete_name_with_username'],
1829
        $sendMessage,
1830
        ['class' => 'ajax']
1831
    );
1832
1833
    if (isset($result['extra'])) {
1834
        $result['extra'] = $result['extra'];
1835
    }
1836
1837
    return $result;
1838
}
1839
1840
/**
1841
 * @param int $userId
1842
 *
1843
 * @return User
1844
 */
1845
function api_get_user_entity($userId)
1846
{
1847
    $userId = (int) $userId;
1848
    $repo = UserManager::getRepository();
1849
1850
    /** @var User $user */
1851
    $user = $repo->find($userId);
1852
1853
    return $user;
1854
}
1855
1856
/**
1857
 * @return User|null
1858
 */
1859
function api_get_current_user()
1860
{
1861
    $isLoggedIn = Container::$container->get('security.authorization_checker')->isGranted('IS_AUTHENTICATED_REMEMBERED');
1862
    if (false === $isLoggedIn) {
1863
        return null;
1864
    }
1865
1866
    $token = Container::$container->get('security.token_storage')->getToken();
1867
1868
    if (null !== $token) {
1869
        return $token->getUser();
1870
    }
1871
1872
    return null;
1873
}
1874
1875
/**
1876
 * Finds all the information about a user from username instead of user id.
1877
 *
1878
 * @param string $username
1879
 *
1880
 * @return mixed $user_info array user_id, lastname, firstname, username, email or false on error
1881
 *
1882
 * @author Yannick Warnier <[email protected]>
1883
 */
1884
function api_get_user_info_from_username($username)
1885
{
1886
    if (empty($username)) {
1887
        return false;
1888
    }
1889
    $username = trim($username);
1890
1891
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1892
            WHERE username='".Database::escape_string($username)."'";
1893
    $result = Database::query($sql);
1894
    if (Database::num_rows($result) > 0) {
1895
        $resultArray = Database::fetch_array($result);
1896
1897
        return _api_format_user($resultArray);
1898
    }
1899
1900
    return false;
1901
}
1902
1903
/**
1904
 * Get first user with an email.
1905
 *
1906
 * @param string $email
1907
 *
1908
 * @return array|bool
1909
 */
1910
function api_get_user_info_from_email($email = '')
1911
{
1912
    if (empty($email)) {
1913
        return false;
1914
    }
1915
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1916
            WHERE email ='".Database::escape_string($email)."' LIMIT 1";
1917
    $result = Database::query($sql);
1918
    if (Database::num_rows($result) > 0) {
1919
        $resultArray = Database::fetch_array($result);
1920
1921
        return _api_format_user($resultArray);
1922
    }
1923
1924
    return false;
1925
}
1926
1927
/**
1928
 * @return string
1929
 */
1930
function api_get_course_id()
1931
{
1932
    return Session::read('_cid', null);
1933
}
1934
1935
/**
1936
 * Returns the current course id (integer).
1937
 *
1938
 * @param string $code Optional course code
1939
 *
1940
 * @return int
1941
 */
1942
function api_get_course_int_id($code = null)
1943
{
1944
    if (!empty($code)) {
1945
        $code = Database::escape_string($code);
1946
        $row = Database::select(
1947
            'id',
1948
            Database::get_main_table(TABLE_MAIN_COURSE),
1949
            ['where' => ['code = ?' => [$code]]],
1950
            'first'
1951
        );
1952
1953
        if (is_array($row) && isset($row['id'])) {
1954
            return $row['id'];
1955
        } else {
1956
            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...
1957
        }
1958
    }
1959
1960
    return Session::read('_real_cid', 0);
1961
}
1962
1963
/**
1964
 * Returns the current course directory.
1965
 *
1966
 * This function relies on api_get_course_info()
1967
 *
1968
 * @param string    The course code - optional (takes it from session if not given)
1969
 *
1970
 * @return string The directory where the course is located inside the Chamilo "courses" directory
1971
 *
1972
 * @author Yannick Warnier <[email protected]>
1973
 */
1974
function api_get_course_path($course_code = null)
1975
{
1976
    $info = !empty($course_code) ? api_get_course_info($course_code) : api_get_course_info();
1977
1978
    return $info['path'];
1979
}
1980
1981
/**
1982
 * Gets a course setting from the current course_setting table. Try always using integer values.
1983
 *
1984
 * @param string $settingName The name of the setting we want from the table
1985
 * @param array  $courseInfo
1986
 * @param bool   $force       force checking the value in the database
1987
 *
1988
 * @return mixed The value of that setting in that table. Return -1 if not found.
1989
 */
1990
function api_get_course_setting($settingName, $courseInfo = [], $force = false)
1991
{
1992
    if (empty($courseInfo)) {
1993
        $courseInfo = api_get_course_info();
1994
    }
1995
1996
    if (empty($courseInfo) || empty($settingName)) {
1997
        return -1;
1998
    }
1999
2000
    $courseId = isset($courseInfo['real_id']) && !empty($courseInfo['real_id']) ? $courseInfo['real_id'] : 0;
2001
2002
    if (empty($courseId)) {
2003
        return -1;
2004
    }
2005
2006
    static $courseSettingInfo = [];
2007
2008
    if ($force) {
2009
        $courseSettingInfo = [];
2010
    }
2011
2012
    if (!isset($courseSettingInfo[$courseId])) {
2013
        $table = Database::get_course_table(TABLE_COURSE_SETTING);
2014
        $settingName = Database::escape_string($settingName);
2015
2016
        $sql = "SELECT variable, value FROM $table
2017
                WHERE c_id = $courseId ";
2018
        $res = Database::query($sql);
2019
        if (Database::num_rows($res) > 0) {
2020
            $result = Database::store_result($res, 'ASSOC');
2021
            $courseSettingInfo[$courseId] = array_column($result, 'value', 'variable');
2022
2023
            if (isset($courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'])) {
2024
                $value = $courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'];
2025
                if (!is_null($value)) {
2026
                    $result = explode(',', $value);
2027
                    $courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'] = $result;
2028
                }
2029
            }
2030
        }
2031
    }
2032
2033
    if (isset($courseSettingInfo[$courseId]) && isset($courseSettingInfo[$courseId][$settingName])) {
2034
        return $courseSettingInfo[$courseId][$settingName];
2035
    }
2036
2037
    return -1;
2038
}
2039
2040
function api_get_course_plugin_setting($plugin, $settingName, $courseInfo = [])
2041
{
2042
    $value = api_get_course_setting($settingName, $courseInfo, true);
2043
2044
    if (-1 === $value) {
2045
        // Check global settings
2046
        $value = api_get_plugin_setting($plugin, $settingName);
2047
        if ($value === 'true') {
2048
            return 1;
2049
        }
2050
        if ($value === 'false') {
2051
            return 0;
2052
        }
2053
        if (null === $value) {
2054
            return -1;
2055
        }
2056
    }
2057
2058
    return $value;
2059
}
2060
2061
/**
2062
 * Gets an anonymous user ID.
2063
 *
2064
 * For some tools that need tracking, like the learnpath tool, it is necessary
2065
 * to have a usable user-id to enable some kind of tracking, even if not
2066
 * perfect. An anonymous ID is taken from the users table by looking for a
2067
 * status of "6" (anonymous).
2068
 *
2069
 * @return int User ID of the anonymous user, or O if no anonymous user found
2070
 */
2071
function api_get_anonymous_id()
2072
{
2073
    // Find if another anon is connected now
2074
    $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
2075
    $tableU = Database::get_main_table(TABLE_MAIN_USER);
2076
    $ip = Database::escape_string(api_get_real_ip());
2077
    $max = (int) api_get_configuration_value('max_anonymous_users');
2078
    if ($max >= 2) {
2079
        $sql = "SELECT * FROM $table as TEL
2080
                JOIN $tableU as U
2081
                ON U.user_id = TEL.login_user_id
2082
                WHERE TEL.user_ip = '$ip'
2083
                    AND U.status = ".ANONYMOUS."
2084
                    AND U.user_id != 2 ";
2085
2086
        $result = Database::query($sql);
2087
        if (empty(Database::num_rows($result))) {
2088
            $login = uniqid('anon_');
2089
            $anonList = UserManager::get_user_list(['status' => ANONYMOUS], ['registration_date ASC']);
2090
            if (count($anonList) >= $max) {
2091
                foreach ($anonList as $userToDelete) {
2092
                    UserManager::delete_user($userToDelete['user_id']);
2093
                    break;
2094
                }
2095
            }
2096
            $userId = UserManager::create_user(
2097
                $login,
2098
                'anon',
2099
                ANONYMOUS,
2100
                ' anonymous@localhost',
2101
                $login,
2102
                $login
2103
            );
2104
2105
            return $userId;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $userId could also return false which is incompatible with the documented return type integer. Did you maybe forget to handle an error condition?

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

Loading history...
2106
        } else {
2107
            $row = Database::fetch_array($result, 'ASSOC');
2108
2109
            return $row['user_id'];
2110
        }
2111
    }
2112
2113
    $table = Database::get_main_table(TABLE_MAIN_USER);
2114
    $sql = "SELECT user_id
2115
            FROM $table
2116
            WHERE status = ".ANONYMOUS." ";
2117
    $res = Database::query($sql);
2118
    if (Database::num_rows($res) > 0) {
2119
        $row = Database::fetch_array($res, 'ASSOC');
2120
2121
        return $row['user_id'];
2122
    }
2123
2124
    // No anonymous user was found.
2125
    return 0;
2126
}
2127
2128
/**
2129
 * @param string $courseCode
2130
 * @param int    $sessionId
2131
 * @param int    $groupId
2132
 *
2133
 * @return string
2134
 */
2135
function api_get_cidreq_params($courseCode, $sessionId = 0, $groupId = 0)
2136
{
2137
    $courseCode = !empty($courseCode) ? htmlspecialchars($courseCode) : '';
2138
    $sessionId = !empty($sessionId) ? (int) $sessionId : 0;
2139
    $groupId = !empty($groupId) ? (int) $groupId : 0;
2140
2141
    $url = 'cidReq='.$courseCode;
2142
    $url .= '&id_session='.$sessionId;
2143
    $url .= '&gidReq='.$groupId;
2144
2145
    return $url;
2146
}
2147
2148
/**
2149
 * Returns the current course url part including session, group, and gradebook params.
2150
 *
2151
 * @param bool   $addSessionId
2152
 * @param bool   $addGroupId
2153
 * @param string $origin
2154
 *
2155
 * @return string Course & session references to add to a URL
2156
 */
2157
function api_get_cidreq($addSessionId = true, $addGroupId = true, $origin = '')
2158
{
2159
    $courseId = api_get_course_int_id();
2160
    $url = empty($courseId) ? '' : 'cid='.$courseId;
2161
    $origin = empty($origin) ? api_get_origin() : Security::remove_XSS($origin);
2162
2163
    if ($addSessionId) {
2164
        if (!empty($url)) {
2165
            $url .= 0 == api_get_session_id() ? '&sid=0' : '&sid='.api_get_session_id();
2166
        }
2167
    }
2168
2169
    if ($addGroupId) {
2170
        if (!empty($url)) {
2171
            $url .= 0 == api_get_group_id() ? '&gid=0' : '&gid='.api_get_group_id();
2172
        }
2173
    }
2174
2175
    if (!empty($url)) {
2176
        $url .= '&gradebook='.(int) api_is_in_gradebook();
2177
        $url .= '&origin='.$origin;
2178
    }
2179
2180
    return $url;
2181
}
2182
2183
/**
2184
 * Get if we visited a gradebook page.
2185
 *
2186
 * @return bool
2187
 */
2188
function api_is_in_gradebook()
2189
{
2190
    return Session::read('in_gradebook', false);
2191
}
2192
2193
/**
2194
 * Set that we are in a page inside a gradebook.
2195
 */
2196
function api_set_in_gradebook()
2197
{
2198
    Session::write('in_gradebook', true);
2199
}
2200
2201
/**
2202
 * Remove gradebook session.
2203
 */
2204
function api_remove_in_gradebook()
2205
{
2206
    Session::erase('in_gradebook');
2207
}
2208
2209
/**
2210
 * Returns the current course info array see api_format_course_array()
2211
 * If the course_code is given, the returned array gives info about that
2212
 * particular course, if none given it gets the course info from the session.
2213
 *
2214
 * @param string $course_code
2215
 *
2216
 * @return array
2217
 */
2218
function api_get_course_info($course_code = null)
2219
{
2220
    if (!empty($course_code)) {
2221
        $course = Container::getCourseRepository()->findOneByCode($course_code);
2222
        if (empty($course)) {
2223
            return [];
2224
        }
2225
2226
        $courseInfo = api_format_course_array($course);
2227
2228
        return $courseInfo;
2229
    }
2230
2231
    /*$course_code = Database::escape_string($course_code);
2232
    $courseId = api_get_course_int_id($course_code);
2233
    if (empty($courseId)) {
2234
        return [];
2235
    }
2236
2237
    $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
2238
    $course_cat_table = Database::get_main_table(TABLE_MAIN_CATEGORY);
2239
    $sql = "SELECT
2240
                course.*,
2241
                course_category.code faCode,
2242
                course_category.name faName
2243
            FROM $course_table
2244
            LEFT JOIN $course_cat_table
2245
            ON course.category_code = course_category.code
2246
            WHERE course.id = $courseId";
2247
    $result = Database::query($sql);
2248
    $courseInfo = [];
2249
    if (Database::num_rows($result) > 0) {
2250
        $data = Database::fetch_array($result);
2251
        $courseInfo = api_format_course_array($data);
2252
    }
2253
2254
    return $courseInfo;*/
2255
2256
    $course = Session::read('_course');
2257
    if ('-1' == $course) {
2258
        $course = [];
2259
    }
2260
2261
    return $course;
2262
}
2263
2264
/**
2265
 * @param int $courseId
2266
 *
2267
 * @return Course
2268
 */
2269
function api_get_course_entity($courseId = 0)
2270
{
2271
    if (empty($courseId)) {
2272
        $courseId = api_get_course_int_id();
2273
    }
2274
2275
    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

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

3880
    /** @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...
3881
    $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

3881
    /** @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...
3882
    $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

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

5309
            $files = copyr("$source/$entry", "$dest/$entry", $exclude, /** @scrutinizer ignore-type */ $copied_files);
Loading history...
5310
        }
5311
    }
5312
    // Clean up.
5313
    $dir->close();
5314
5315
    return true;
5316
}
5317
5318
/**
5319
 * @todo: Using DIRECTORY_SEPARATOR is not recommended, this is an obsolete approach.
5320
 * Documentation header to be added here.
5321
 *
5322
 * @param string $pathname
5323
 * @param string $base_path_document
5324
 * @param int    $session_id
5325
 *
5326
 * @return mixed True if directory already exists, false if a file already exists at
5327
 *               the destination and null if everything goes according to plan
5328
 */
5329
function copy_folder_course_session(
5330
    $pathname,
5331
    $base_path_document,
5332
    $session_id,
5333
    $course_info,
5334
    $document,
5335
    $source_course_id
5336
) {
5337
    $table = Database::get_course_table(TABLE_DOCUMENT);
5338
    $session_id = intval($session_id);
5339
    $source_course_id = intval($source_course_id);
5340
5341
    // Check whether directory already exists.
5342
    if (is_dir($pathname) || empty($pathname)) {
5343
        return true;
5344
    }
5345
5346
    // Ensure that a file with the same name does not already exist.
5347
    if (is_file($pathname)) {
5348
        trigger_error('copy_folder_course_session(): File exists', E_USER_WARNING);
5349
5350
        return false;
5351
    }
5352
5353
    $course_id = $course_info['real_id'];
5354
    $folders = explode(DIRECTORY_SEPARATOR, str_replace($base_path_document.DIRECTORY_SEPARATOR, '', $pathname));
5355
    $new_pathname = $base_path_document;
5356
    $path = '';
5357
5358
    foreach ($folders as $folder) {
5359
        $new_pathname .= DIRECTORY_SEPARATOR.$folder;
5360
        $path .= DIRECTORY_SEPARATOR.$folder;
5361
5362
        if (!file_exists($new_pathname)) {
5363
            $path = Database::escape_string($path);
5364
5365
            $sql = "SELECT * FROM $table
5366
                    WHERE
5367
                        c_id = $source_course_id AND
5368
                        path = '$path' AND
5369
                        filetype = 'folder' AND
5370
                        session_id = '$session_id'";
5371
            $rs1 = Database::query($sql);
5372
            $num_rows = Database::num_rows($rs1);
5373
5374
            if (0 == $num_rows) {
5375
                mkdir($new_pathname, api_get_permissions_for_new_directories());
5376
5377
                // Insert new folder with destination session_id.
5378
                $params = [
5379
                    'c_id' => $course_id,
5380
                    'path' => $path,
5381
                    'comment' => $document->comment,
5382
                    'title' => basename($new_pathname),
5383
                    'filetype' => 'folder',
5384
                    'size' => '0',
5385
                    'session_id' => $session_id,
5386
                ];
5387
                $document_id = Database::insert($table, $params);
5388
                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...
5389
                    $sql = "UPDATE $table SET id = iid WHERE iid = $document_id";
5390
                    Database::query($sql);
5391
5392
                    api_item_property_update(
5393
                        $course_info,
5394
                        TOOL_DOCUMENT,
5395
                        $document_id,
5396
                        'FolderCreated',
5397
                        api_get_user_id(),
5398
                        0,
5399
                        0,
5400
                        null,
5401
                        null,
5402
                        $session_id
5403
                    );
5404
                }
5405
            }
5406
        }
5407
    } // en foreach
5408
}
5409
5410
// TODO: chmodr() is a better name. Some corrections are needed. Documentation header to be added here.
5411
/**
5412
 * @param string $path
5413
 */
5414
function api_chmod_R($path, $filemode)
5415
{
5416
    if (!is_dir($path)) {
5417
        return chmod($path, $filemode);
5418
    }
5419
5420
    $handler = opendir($path);
5421
    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

5421
    while ($file = readdir(/** @scrutinizer ignore-type */ $handler)) {
Loading history...
5422
        if ('.' != $file && '..' != $file) {
5423
            $fullpath = "$path/$file";
5424
            if (!is_dir($fullpath)) {
5425
                if (!chmod($fullpath, $filemode)) {
5426
                    return false;
5427
                }
5428
            } else {
5429
                if (!api_chmod_R($fullpath, $filemode)) {
5430
                    return false;
5431
                }
5432
            }
5433
        }
5434
    }
5435
5436
    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

5436
    closedir(/** @scrutinizer ignore-type */ $handler);
Loading history...
5437
5438
    return chmod($path, $filemode);
5439
}
5440
5441
// TODO: Where the following function has been copy/pased from? There is no information about author and license. Style, coding conventions...
5442
/**
5443
 * Parse info file format. (e.g: file.info).
5444
 *
5445
 * Files should use an ini-like format to specify values.
5446
 * White-space generally doesn't matter, except inside values.
5447
 * e.g.
5448
 *
5449
 * @verbatim
5450
 *   key = value
5451
 *   key = "value"
5452
 *   key = 'value'
5453
 *   key = "multi-line
5454
 *
5455
 *   value"
5456
 *   key = 'multi-line
5457
 *
5458
 *   value'
5459
 *   key
5460
 *   =
5461
 *   'value'
5462
 * @endverbatim
5463
 *
5464
 * Arrays are created using a GET-like syntax:
5465
 *
5466
 * @verbatim
5467
 *   key[] = "numeric array"
5468
 *   key[index] = "associative array"
5469
 *   key[index][] = "nested numeric array"
5470
 *   key[index][index] = "nested associative array"
5471
 * @endverbatim
5472
 *
5473
 * PHP constants are substituted in, but only when used as the entire value:
5474
 *
5475
 * Comments should start with a semi-colon at the beginning of a line.
5476
 *
5477
 * This function is NOT for placing arbitrary module-specific settings. Use
5478
 * variable_get() and variable_set() for that.
5479
 *
5480
 * Information stored in the module.info file:
5481
 * - name: The real name of the module for display purposes.
5482
 * - description: A brief description of the module.
5483
 * - dependencies: An array of shortnames of other modules this module depends on.
5484
 * - package: The name of the package of modules this module belongs to.
5485
 *
5486
 * Example of .info file:
5487
 * <code>
5488
 * @verbatim
5489
 *   name = Forum
5490
 *   description = Enables threaded discussions about general topics.
5491
 *   dependencies[] = taxonomy
5492
 *   dependencies[] = comment
5493
 *   package = Core - optional
5494
 *   version = VERSION
5495
 * @endverbatim
5496
 * </code>
5497
 *
5498
 * @param string $filename
5499
 *                         The file we are parsing. Accepts file with relative or absolute path.
5500
 *
5501
 * @return
5502
 *   The info array
5503
 */
5504
function api_parse_info_file($filename)
5505
{
5506
    $info = [];
5507
5508
    if (!file_exists($filename)) {
5509
        return $info;
5510
    }
5511
5512
    $data = file_get_contents($filename);
5513
    if (preg_match_all('
5514
        @^\s*                           # Start at the beginning of a line, ignoring leading whitespace
5515
        ((?:
5516
          [^=;\[\]]|                    # Key names cannot contain equal signs, semi-colons or square brackets,
5517
          \[[^\[\]]*\]                  # unless they are balanced and not nested
5518
        )+?)
5519
        \s*=\s*                         # Key/value pairs are separated by equal signs (ignoring white-space)
5520
        (?:
5521
          ("(?:[^"]|(?<=\\\\)")*")|     # Double-quoted string, which may contain slash-escaped quotes/slashes
5522
          (\'(?:[^\']|(?<=\\\\)\')*\')| # Single-quoted string, which may contain slash-escaped quotes/slashes
5523
          ([^\r\n]*?)                   # Non-quoted string
5524
        )\s*$                           # Stop at the next end of a line, ignoring trailing whitespace
5525
        @msx', $data, $matches, PREG_SET_ORDER)) {
5526
        $key = $value1 = $value2 = $value3 = '';
5527
        foreach ($matches as $match) {
5528
            // Fetch the key and value string.
5529
            $i = 0;
5530
            foreach (['key', 'value1', 'value2', 'value3'] as $var) {
5531
                $$var = isset($match[++$i]) ? $match[$i] : '';
5532
            }
5533
            $value = stripslashes(substr($value1, 1, -1)).stripslashes(substr($value2, 1, -1)).$value3;
5534
5535
            // Parse array syntax.
5536
            $keys = preg_split('/\]?\[/', rtrim($key, ']'));
5537
            $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

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

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

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

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

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

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