Passed
Push — master ( 8cd85a...5627cd )
by Julito
09:53 queued 10s
created

api_format_course_array()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 104
Code Lines 46

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 46
nc 5
nop 1
dl 0
loc 104
rs 9.1781
c 0
b 0
f 0

How to fix   Long Method   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
/* For licensing terms, see /license.txt */
3
4
use Chamilo\CoreBundle\Entity\AccessUrl;
5
use Chamilo\CoreBundle\Entity\Course;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Course. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

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

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
1121
            isset($course_info['registration_code']) &&
1122
            !empty($course_info['registration_code'])
1123
        ) {
1124
            $is_visible = false;
1125
        }
1126
    }
1127
1128
    if (!empty($checkTool)) {
1129
        if (!api_is_allowed_to_edit(true, true, true)) {
1130
            $toolInfo = api_get_tool_information_by_name($checkTool);
1131
            if (!empty($toolInfo) && isset($toolInfo['visibility']) && $toolInfo['visibility'] == 0) {
1132
                api_not_allowed(true);
1133
1134
                return false;
1135
            }
1136
        }
1137
    }
1138
1139
    // Check session visibility
1140
    $session_id = api_get_session_id();
1141
1142
    if (!empty($session_id)) {
1143
        // $isAllowedInCourse was set in local.inc.php
1144
        if (!$isAllowedInCourse) {
1145
            $is_visible = false;
1146
        }
1147
    }
1148
1149
    if (!$is_visible) {
1150
        api_not_allowed($print_headers);
1151
1152
        return false;
1153
    }
1154
1155
    return true;
1156
}
1157
1158
/**
1159
 * Function used to protect an admin script.
1160
 *
1161
 * The function blocks access when the user has no platform admin rights
1162
 * with an error message printed on default output
1163
 *
1164
 * @param bool Whether to allow session admins as well
1165
 * @param bool Whether to allow HR directors as well
1166
 * @param string An optional message (already passed through get_lang)
1167
 *
1168
 * @return bool True if user is allowed, false otherwise.
1169
 *              The function also outputs an error message in case not allowed
1170
 *
1171
 * @author Roan Embrechts (original author)
1172
 */
1173
function api_protect_admin_script($allow_sessions_admins = false, $allow_drh = false, $message = null)
1174
{
1175
    if (!api_is_platform_admin($allow_sessions_admins, $allow_drh)) {
1176
        api_not_allowed(true, $message);
1177
1178
        return false;
1179
    }
1180
1181
    return true;
1182
}
1183
1184
/**
1185
 * Function used to protect a teacher script.
1186
 * The function blocks access when the user has no teacher rights.
1187
 *
1188
 * @return bool True if the current user can access the script, false otherwise
1189
 *
1190
 * @author Yoselyn Castillo
1191
 */
1192
function api_protect_teacher_script()
1193
{
1194
    if (!api_is_allowed_to_edit()) {
1195
        api_not_allowed(true);
1196
1197
        return false;
1198
    }
1199
1200
    return true;
1201
}
1202
1203
/**
1204
 * Function used to prevent anonymous users from accessing a script.
1205
 *
1206
 * @param bool|true $printHeaders
1207
 *
1208
 * @author Roan Embrechts
1209
 *
1210
 * @return bool
1211
 */
1212
function api_block_anonymous_users($printHeaders = true)
1213
{
1214
    $user = api_get_user_info();
1215
    if (!(isset($user['user_id']) && $user['user_id']) || api_is_anonymous($user['user_id'], true)) {
1216
        api_not_allowed($printHeaders);
1217
1218
        return false;
1219
    }
1220
1221
    return true;
1222
}
1223
1224
/**
1225
 * Returns a rough evaluation of the browser's name and version based on very
1226
 * simple regexp.
1227
 *
1228
 * @return array with the navigator name and version ['name' => '...', 'version' => '...']
1229
 */
1230
function api_get_navigator()
1231
{
1232
    $navigator = 'Unknown';
1233
    $version = 0;
1234
1235
    if (!isset($_SERVER['HTTP_USER_AGENT'])) {
1236
        return ['name' => 'Unknown', 'version' => '0.0.0'];
1237
    }
1238
1239
    if (strpos($_SERVER['HTTP_USER_AGENT'], 'Opera') !== false) {
1240
        $navigator = 'Opera';
1241
        list(, $version) = explode('Opera', $_SERVER['HTTP_USER_AGENT']);
1242
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Edge') !== false) {
1243
        $navigator = 'Edge';
1244
        list(, $version) = explode('Edge', $_SERVER['HTTP_USER_AGENT']);
1245
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== false) {
1246
        $navigator = 'Internet Explorer';
1247
        list(, $version) = explode('MSIE ', $_SERVER['HTTP_USER_AGENT']);
1248
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Chrome') !== false) {
1249
        $navigator = 'Chrome';
1250
        list(, $version) = explode('Chrome', $_SERVER['HTTP_USER_AGENT']);
1251
    } elseif (stripos($_SERVER['HTTP_USER_AGENT'], 'Safari') !== false) {
1252
        $navigator = 'Safari';
1253
        if (stripos($_SERVER['HTTP_USER_AGENT'], 'Version/') !== false) {
1254
            // If this Safari does have the "Version/" string in its user agent
1255
            // then use that as a version indicator rather than what's after
1256
            // "Safari/" which is rather a "build number" or something
1257
            list(, $version) = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1258
        } else {
1259
            list(, $version) = explode('Safari/', $_SERVER['HTTP_USER_AGENT']);
1260
        }
1261
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Firefox') !== false) {
1262
        $navigator = 'Firefox';
1263
        list(, $version) = explode('Firefox', $_SERVER['HTTP_USER_AGENT']);
1264
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Netscape') !== false) {
1265
        $navigator = 'Netscape';
1266
        if (stripos($_SERVER['HTTP_USER_AGENT'], 'Netscape/') !== false) {
1267
            list(, $version) = explode('Netscape', $_SERVER['HTTP_USER_AGENT']);
1268
        } else {
1269
            list(, $version) = explode('Navigator', $_SERVER['HTTP_USER_AGENT']);
1270
        }
1271
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Konqueror') !== false) {
1272
        $navigator = 'Konqueror';
1273
        list(, $version) = explode('Konqueror', $_SERVER['HTTP_USER_AGENT']);
1274
    } elseif (stripos($_SERVER['HTTP_USER_AGENT'], 'applewebkit') !== false) {
1275
        $navigator = 'AppleWebKit';
1276
        list(, $version) = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1277
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Gecko') !== false) {
1278
        $navigator = 'Mozilla';
1279
        list(, $version) = explode('; rv:', $_SERVER['HTTP_USER_AGENT']);
1280
    }
1281
1282
    // Now cut extra stuff around (mostly *after*) the version number
1283
    $version = preg_replace('/^([\/\s])?([\d\.]+)?.*/', '\2', $version);
1284
1285
    if (strpos($version, '.') === false) {
1286
        $version = number_format(doubleval($version), 1);
1287
    }
1288
    $return = ['name' => $navigator, 'version' => $version];
1289
1290
    return $return;
1291
}
1292
1293
/**
1294
 * @return true if user self registration is allowed, false otherwise
1295
 */
1296
function api_is_self_registration_allowed()
1297
{
1298
    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...
1299
}
1300
1301
/**
1302
 * This function returns the id of the user which is stored in the $_user array.
1303
 *
1304
 * example: The function can be used to check if a user is logged in
1305
 *          if (api_get_user_id())
1306
 *
1307
 * @return int the id of the current user, 0 if is empty
1308
 */
1309
function api_get_user_id()
1310
{
1311
    $userInfo = Session::read('_user');
1312
    if ($userInfo && isset($userInfo['user_id'])) {
1313
        return (int) $userInfo['user_id'];
1314
    }
1315
1316
    return 0;
1317
}
1318
1319
/**
1320
 * Gets the list of courses a specific user is subscribed to.
1321
 *
1322
 * @param int       User ID
1323
 * @param bool $fetch_session Whether to get session courses or not - NOT YET IMPLEMENTED
1324
 *
1325
 * @return array Array of courses in the form [0]=>('code'=>xxx,'db'=>xxx,'dir'=>xxx,'status'=>d)
1326
 *
1327
 * @deprecated use CourseManager::get_courses_list_by_user_id()
1328
 */
1329
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

1329
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...
1330
{
1331
    // Get out if not integer
1332
    if ($userId != strval(intval($userId))) {
1333
        return [];
1334
    }
1335
1336
    $t_course = Database::get_main_table(TABLE_MAIN_COURSE);
1337
    $t_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
1338
1339
    $sql = "SELECT cc.id as real_id, cc.code code, cc.directory dir, cu.status status
1340
            FROM $t_course cc, $t_course_user cu
1341
            WHERE
1342
                cc.id = cu.c_id AND
1343
                cu.user_id = $userId AND
1344
                cu.relation_type <> ".COURSE_RELATION_TYPE_RRHH;
1345
    $result = Database::query($sql);
1346
    if ($result === false) {
1347
        return [];
1348
    }
1349
1350
    $courses = [];
1351
    while ($row = Database::fetch_array($result)) {
1352
        // we only need the database name of the course
1353
        $courses[] = $row;
1354
    }
1355
1356
    return $courses;
1357
}
1358
1359
/**
1360
 * Formats user information into a standard array
1361
 * This function should be only used inside api_get_user_info().
1362
 *
1363
 * @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...
1364
 * @param bool $add_password
1365
 * @param bool $loadAvatars  turn off to improve performance
1366
 *
1367
 * @return array Standard user array
1368
 */
1369
function _api_format_user($user, $add_password = false, $loadAvatars = true)
1370
{
1371
    $result = [];
1372
1373
    if (!isset($user['user_id'])) {
1374
        return [];
1375
    }
1376
1377
    $result['firstname'] = null;
1378
    $result['lastname'] = null;
1379
1380
    if (isset($user['firstname']) && isset($user['lastname'])) {
1381
        // with only lowercase
1382
        $result['firstname'] = $user['firstname'];
1383
        $result['lastname'] = $user['lastname'];
1384
    } elseif (isset($user['firstName']) && isset($user['lastName'])) {
1385
        // with uppercase letters
1386
        $result['firstname'] = isset($user['firstName']) ? $user['firstName'] : null;
1387
        $result['lastname'] = isset($user['lastName']) ? $user['lastName'] : null;
1388
    }
1389
1390
    if (isset($user['email'])) {
1391
        $result['mail'] = isset($user['email']) ? $user['email'] : null;
1392
        $result['email'] = isset($user['email']) ? $user['email'] : null;
1393
    } else {
1394
        $result['mail'] = isset($user['mail']) ? $user['mail'] : null;
1395
        $result['email'] = isset($user['mail']) ? $user['mail'] : null;
1396
    }
1397
1398
    $result['complete_name'] = api_get_person_name($result['firstname'], $result['lastname']);
1399
    $result['complete_name_with_username'] = $result['complete_name'];
1400
1401
    if (!empty($user['username']) && api_get_setting('profile.hide_username_with_complete_name') === 'false') {
1402
        $result['complete_name_with_username'] = $result['complete_name'].' ('.$user['username'].')';
1403
    }
1404
1405
    $showEmail = api_get_setting('show_email_addresses') === 'true';
1406
    if (!empty($user['email'])) {
1407
        $result['complete_name_with_email_forced'] = $result['complete_name'].' ('.$user['email'].')';
1408
        if ($showEmail) {
1409
            $result['complete_name_with_email'] = $result['complete_name'].' ('.$user['email'].')';
1410
        }
1411
    } else {
1412
        $result['complete_name_with_email'] = $result['complete_name'];
1413
        $result['complete_name_with_email_forced'] = $result['complete_name'];
1414
    }
1415
1416
    // Kept for historical reasons
1417
    $result['firstName'] = $result['firstname'];
1418
    $result['lastName'] = $result['lastname'];
1419
1420
    $attributes = [
1421
        'phone',
1422
        'address',
1423
        'picture_uri',
1424
        'official_code',
1425
        'status',
1426
        'active',
1427
        'auth_source',
1428
        'username',
1429
        'theme',
1430
        'language',
1431
        'creator_id',
1432
        'registration_date',
1433
        'hr_dept_id',
1434
        'expiration_date',
1435
        'last_login',
1436
        'user_is_online',
1437
    ];
1438
1439
    if (api_get_setting('extended_profile') === 'true') {
1440
        $attributes[] = 'competences';
1441
        $attributes[] = 'diplomas';
1442
        $attributes[] = 'teach';
1443
        $attributes[] = 'openarea';
1444
    }
1445
1446
    foreach ($attributes as $attribute) {
1447
        $result[$attribute] = isset($user[$attribute]) ? $user[$attribute] : null;
1448
    }
1449
1450
    $user_id = (int) $user['user_id'];
1451
    // Maintain the user_id index for backwards compatibility
1452
    $result['user_id'] = $result['id'] = $user_id;
1453
1454
    $hasCertificates = Certificate::getCertificateByUser($user_id);
1455
    $result['has_certificates'] = 0;
1456
    if (!empty($hasCertificates)) {
1457
        $result['has_certificates'] = 1;
1458
    }
1459
1460
    $result['icon_status'] = '';
1461
    $result['icon_status_medium'] = '';
1462
1463
    $result['is_admin'] = UserManager::is_admin($user_id);
1464
1465
    // Getting user avatar.
1466
    if ($loadAvatars) {
1467
        $result['avatar'] = '';
1468
        $result['avatar_no_query'] = '';
1469
        $result['avatar_small'] = '';
1470
        $result['avatar_medium'] = '';
1471
1472
        if (!isset($user['avatar'])) {
1473
            $originalFile = UserManager::getUserPicture(
1474
                $user_id,
1475
                USER_IMAGE_SIZE_ORIGINAL,
1476
                null,
1477
                $result
1478
            );
1479
            $result['avatar'] = $originalFile;
1480
            $avatarString = explode('?', $result['avatar']);
1481
            $result['avatar_no_query'] = reset($avatarString);
1482
        } else {
1483
            $result['avatar'] = $user['avatar'];
1484
            $avatarString = explode('?', $user['avatar']);
1485
            $result['avatar_no_query'] = reset($avatarString);
1486
        }
1487
1488
        if (!isset($user['avatar_small'])) {
1489
            $smallFile = UserManager::getUserPicture(
1490
                $user_id,
1491
                USER_IMAGE_SIZE_SMALL,
1492
                null,
1493
                $result
1494
            );
1495
            $result['avatar_small'] = $smallFile;
1496
        } else {
1497
            $result['avatar_small'] = $user['avatar_small'];
1498
        }
1499
1500
        if (!isset($user['avatar_medium'])) {
1501
            $mediumFile = UserManager::getUserPicture(
1502
                $user_id,
1503
                USER_IMAGE_SIZE_MEDIUM,
1504
                null,
1505
                $result
1506
            );
1507
            $result['avatar_medium'] = $mediumFile;
1508
        } else {
1509
            $result['avatar_medium'] = $user['avatar_medium'];
1510
        }
1511
1512
        $urlImg = api_get_path(WEB_IMG_PATH);
1513
        $iconStatus = '';
1514
        $iconStatusMedium = '';
1515
1516
        switch ($result['status']) {
1517
            case STUDENT:
1518
                if ($result['has_certificates']) {
1519
                    $iconStatus = $urlImg.'icons/svg/identifier_graduated.svg';
1520
                } else {
1521
                    $iconStatus = $urlImg.'icons/svg/identifier_student.svg';
1522
                }
1523
                break;
1524
            case COURSEMANAGER:
1525
                if ($result['is_admin']) {
1526
                    $iconStatus = $urlImg.'icons/svg/identifier_admin.svg';
1527
                } else {
1528
                    $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1529
                }
1530
                break;
1531
            case STUDENT_BOSS:
1532
                $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1533
                break;
1534
        }
1535
1536
        if (!empty($iconStatus)) {
1537
            $iconStatusMedium = '<img src="'.$iconStatus.'" width="32px" height="32px">';
1538
            $iconStatus = '<img src="'.$iconStatus.'" width="22px" height="22px">';
1539
        }
1540
1541
        $result['icon_status'] = $iconStatus;
1542
        $result['icon_status_medium'] = $iconStatusMedium;
1543
    }
1544
1545
    if (isset($user['user_is_online'])) {
1546
        $result['user_is_online'] = $user['user_is_online'] == true ? 1 : 0;
1547
    }
1548
    if (isset($user['user_is_online_in_chat'])) {
1549
        $result['user_is_online_in_chat'] = (int) $user['user_is_online_in_chat'];
1550
    }
1551
1552
    if ($add_password) {
1553
        $result['password'] = $user['password'];
1554
    }
1555
1556
    if (isset($result['profile_completed'])) {
1557
        $result['profile_completed'] = $user['profile_completed'];
1558
    }
1559
1560
    $result['profile_url'] = api_get_path(WEB_CODE_PATH).'social/profile.php?u='.$user_id;
1561
1562
    // Send message link
1563
    $sendMessage = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&user_id='.$user_id;
1564
    $result['complete_name_with_message_link'] = Display::url(
1565
        $result['complete_name_with_username'],
1566
        $sendMessage,
1567
        ['class' => 'ajax']
1568
    );
1569
1570
    if (isset($user['extra'])) {
1571
        $result['extra'] = $user['extra'];
1572
    }
1573
1574
    return $result;
1575
}
1576
1577
/**
1578
 * Finds all the information about a user.
1579
 * If no parameter is passed you find all the information about the current user.
1580
 *
1581
 * @param int  $user_id
1582
 * @param bool $checkIfUserOnline
1583
 * @param bool $showPassword
1584
 * @param bool $loadExtraData
1585
 * @param bool $loadOnlyVisibleExtraData Get the user extra fields that are visible
1586
 * @param bool $loadAvatars              turn off to improve performance and if avatars are not needed
1587
 * @param bool $updateCache              update apc cache if exists
1588
 *
1589
 * @return mixed $user_info user_id, lastname, firstname, username, email, etc or false on error
1590
 *
1591
 * @author Patrick Cool <[email protected]>
1592
 * @author Julio Montoya
1593
 *
1594
 * @version 21 September 2004
1595
 */
1596
function api_get_user_info(
1597
    $user_id = 0,
1598
    $checkIfUserOnline = false,
1599
    $showPassword = false,
1600
    $loadExtraData = false,
1601
    $loadOnlyVisibleExtraData = false,
1602
    $loadAvatars = true,
1603
    $updateCache = false
1604
) {
1605
    $apcVar = null;
1606
    $user = false;
1607
    $cacheAvailable = api_get_configuration_value('apc');
1608
1609
    if (empty($user_id)) {
1610
        $userFromSession = Session::read('_user');
1611
1612
        if (isset($userFromSession)) {
1613
            if ($cacheAvailable === true &&
1614
                (
1615
                    empty($userFromSession['is_anonymous']) &&
1616
                    (isset($userFromSession['status']) && $userFromSession['status'] != ANONYMOUS)
1617
                )
1618
            ) {
1619
                $apcVar = api_get_configuration_value('apc_prefix').'userinfo_'.$userFromSession['user_id'];
1620
                if (apcu_exists($apcVar)) {
1621
                    if ($updateCache) {
1622
                        apcu_store($apcVar, $userFromSession, 60);
1623
                    }
1624
                    $user = apcu_fetch($apcVar);
1625
                } else {
1626
                    $user = _api_format_user(
1627
                        $userFromSession,
1628
                        $showPassword,
1629
                        $loadAvatars
1630
                    );
1631
                    apcu_store($apcVar, $user, 60);
1632
                }
1633
            } else {
1634
                $user = _api_format_user(
1635
                    $userFromSession,
1636
                    $showPassword,
1637
                    $loadAvatars
1638
                );
1639
            }
1640
1641
            return $user;
1642
        }
1643
1644
        return false;
1645
    }
1646
1647
    // Make sure user_id is safe
1648
    $user_id = (int) $user_id;
1649
1650
    // Re-use user information if not stale and already stored in APCu
1651
    if ($cacheAvailable === true) {
1652
        $apcVar = api_get_configuration_value('apc_prefix').'userinfo_'.$user_id;
1653
        if (apcu_exists($apcVar) && $updateCache == false && $checkIfUserOnline == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
1654
            $user = apcu_fetch($apcVar);
1655
1656
            return $user;
1657
        }
1658
    }
1659
1660
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1661
            WHERE id = $user_id";
1662
    $result = Database::query($sql);
1663
    if (Database::num_rows($result) > 0) {
1664
        $result_array = Database::fetch_array($result);
1665
        $result_array['user_is_online_in_chat'] = 0;
1666
        if ($checkIfUserOnline) {
1667
            $use_status_in_platform = user_is_online($user_id);
1668
            $result_array['user_is_online'] = $use_status_in_platform;
1669
            $user_online_in_chat = 0;
1670
            if ($use_status_in_platform) {
1671
                $user_status = UserManager::get_extra_user_data_by_field(
1672
                    $user_id,
1673
                    'user_chat_status',
1674
                    false,
1675
                    true
1676
                );
1677
                if ((int) $user_status['user_chat_status'] == 1) {
1678
                    $user_online_in_chat = 1;
1679
                }
1680
            }
1681
            $result_array['user_is_online_in_chat'] = $user_online_in_chat;
1682
        }
1683
1684
        if ($loadExtraData) {
1685
            $fieldValue = new ExtraFieldValue('user');
1686
            $result_array['extra'] = $fieldValue->getAllValuesForAnItem(
1687
                $user_id,
1688
                $loadOnlyVisibleExtraData
1689
            );
1690
        }
1691
        $user = _api_format_user($result_array, $showPassword, $loadAvatars);
1692
    }
1693
1694
    if ($cacheAvailable === true) {
1695
        apcu_store($apcVar, $user, 60);
1696
    }
1697
1698
    return $user;
1699
}
1700
1701
/**
1702
 * @param int $userId
1703
 *
1704
 * @return User
1705
 */
1706
function api_get_user_entity($userId)
1707
{
1708
    $userId = (int) $userId;
1709
    $repo = UserManager::getRepository();
1710
1711
    /** @var User $user */
1712
    $user = $repo->find($userId);
1713
1714
    return $user;
1715
}
1716
1717
/**
1718
 * @return User|null
1719
 */
1720
function api_get_current_user()
1721
{
1722
    $isLoggedIn = Container::$container->get('security.authorization_checker')->isGranted('IS_AUTHENTICATED_REMEMBERED');
1723
    if ($isLoggedIn === false) {
1724
        return null;
1725
    }
1726
1727
    $token = Container::$container->get('security.token_storage')->getToken();
1728
1729
    if (null !== $token) {
1730
        return $token->getUser();
1731
    }
1732
1733
    return null;
1734
}
1735
1736
/**
1737
 * Finds all the information about a user from username instead of user id.
1738
 *
1739
 * @param string $username
1740
 *
1741
 * @return mixed $user_info array user_id, lastname, firstname, username, email or false on error
1742
 *
1743
 * @author Yannick Warnier <[email protected]>
1744
 */
1745
function api_get_user_info_from_username($username = '')
1746
{
1747
    if (empty($username)) {
1748
        return false;
1749
    }
1750
    $username = trim($username);
1751
1752
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1753
            WHERE username='".Database::escape_string($username)."'";
1754
    $result = Database::query($sql);
1755
    if (Database::num_rows($result) > 0) {
1756
        $resultArray = Database::fetch_array($result);
1757
1758
        return _api_format_user($resultArray);
1759
    }
1760
1761
    return false;
1762
}
1763
1764
/**
1765
 * Get first user with an email.
1766
 *
1767
 * @param string $email
1768
 *
1769
 * @return array|bool
1770
 */
1771
function api_get_user_info_from_email($email = '')
1772
{
1773
    if (empty($email)) {
1774
        return false;
1775
    }
1776
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1777
            WHERE email ='".Database::escape_string($email)."' LIMIT 1";
1778
    $result = Database::query($sql);
1779
    if (Database::num_rows($result) > 0) {
1780
        $resultArray = Database::fetch_array($result);
1781
1782
        return _api_format_user($resultArray);
1783
    }
1784
1785
    return false;
1786
}
1787
1788
/**
1789
 * @return string
1790
 */
1791
function api_get_course_id()
1792
{
1793
    return Session::read('_cid', null);
1794
}
1795
1796
/**
1797
 * Returns the current course id (integer).
1798
 *
1799
 * @param string $code Optional course code
1800
 *
1801
 * @return int
1802
 */
1803
function api_get_course_int_id($code = null)
1804
{
1805
    if (!empty($code)) {
1806
        $code = Database::escape_string($code);
1807
        $row = Database::select(
1808
            'id',
1809
            Database::get_main_table(TABLE_MAIN_COURSE),
1810
            ['where' => ['code = ?' => [$code]]],
1811
            'first'
1812
        );
1813
1814
        if (is_array($row) && isset($row['id'])) {
1815
            return $row['id'];
1816
        } else {
1817
            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...
1818
        }
1819
    }
1820
1821
    return Session::read('_real_cid', 0);
1822
}
1823
1824
/**
1825
 * Returns the current course directory.
1826
 *
1827
 * This function relies on api_get_course_info()
1828
 *
1829
 * @param string    The course code - optional (takes it from session if not given)
1830
 *
1831
 * @return string The directory where the course is located inside the Chamilo "courses" directory
1832
 *
1833
 * @author Yannick Warnier <[email protected]>
1834
 */
1835
function api_get_course_path($course_code = null)
1836
{
1837
    $info = !empty($course_code) ? api_get_course_info($course_code) : api_get_course_info();
1838
1839
    return $info['path'];
1840
}
1841
1842
/**
1843
 * Gets a course setting from the current course_setting table. Try always using integer values.
1844
 *
1845
 * @param string $settingName The name of the setting we want from the table
1846
 * @param array  $courseInfo
1847
 * @param bool   $force       force checking the value in the database
1848
 *
1849
 * @return mixed The value of that setting in that table. Return -1 if not found.
1850
 */
1851
function api_get_course_setting($settingName, $courseInfo = [], $force = false)
1852
{
1853
    if (empty($courseInfo)) {
1854
        $courseInfo = api_get_course_info();
1855
    }
1856
1857
    if (empty($courseInfo) || empty($settingName)) {
1858
        return -1;
1859
    }
1860
1861
    $courseId = isset($courseInfo['real_id']) && !empty($courseInfo['real_id']) ? $courseInfo['real_id'] : 0;
1862
1863
    if (empty($courseId)) {
1864
        return -1;
1865
    }
1866
1867
    static $courseSettingInfo = [];
1868
1869
    if ($force) {
1870
        $courseSettingInfo = [];
1871
    }
1872
1873
    if (!isset($courseSettingInfo[$courseId])) {
1874
        $table = Database::get_course_table(TABLE_COURSE_SETTING);
1875
        $settingName = Database::escape_string($settingName);
1876
1877
        $sql = "SELECT variable, value FROM $table
1878
                WHERE c_id = $courseId ";
1879
        $res = Database::query($sql);
1880
        if (Database::num_rows($res) > 0) {
1881
            $result = Database::store_result($res, 'ASSOC');
1882
            $courseSettingInfo[$courseId] = array_column($result, 'value', 'variable');
1883
1884
            if (isset($courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'])) {
1885
                $value = $courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'];
1886
                if (!is_null($value)) {
1887
                    $result = explode(',', $value);
1888
                    $courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'] = $result;
1889
                }
1890
            }
1891
        }
1892
    }
1893
1894
    if (isset($courseSettingInfo[$courseId]) && isset($courseSettingInfo[$courseId][$settingName])) {
1895
        return $courseSettingInfo[$courseId][$settingName];
1896
    }
1897
1898
    return -1;
1899
}
1900
1901
/**
1902
 * Gets an anonymous user ID.
1903
 *
1904
 * For some tools that need tracking, like the learnpath tool, it is necessary
1905
 * to have a usable user-id to enable some kind of tracking, even if not
1906
 * perfect. An anonymous ID is taken from the users table by looking for a
1907
 * status of "6" (anonymous).
1908
 *
1909
 * @return int User ID of the anonymous user, or O if no anonymous user found
1910
 */
1911
function api_get_anonymous_id()
1912
{
1913
    // Find if another anon is connected now
1914
    $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
1915
    $tableU = Database::get_main_table(TABLE_MAIN_USER);
1916
    $ip = Database::escape_string(api_get_real_ip());
1917
    $max = (int) api_get_configuration_value('max_anonymous_users');
1918
    if ($max >= 2) {
1919
        $sql = "SELECT * FROM $table as TEL 
1920
                JOIN $tableU as U
1921
                ON U.user_id = TEL.login_user_id
1922
                WHERE TEL.user_ip = '$ip'
1923
                    AND U.status = ".ANONYMOUS."
1924
                    AND U.user_id != 2 ";
1925
1926
        $result = Database::query($sql);
1927
        if (empty(Database::num_rows($result))) {
1928
            $login = uniqid('anon_');
1929
            $anonList = UserManager::get_user_list(['status' => ANONYMOUS], ['registration_date ASC']);
1930
            if (count($anonList) >= $max) {
1931
                foreach ($anonList as $userToDelete) {
1932
                    UserManager::delete_user($userToDelete['user_id']);
1933
                    break;
1934
                }
1935
            }
1936
            $userId = UserManager::create_user(
1937
                $login,
1938
                'anon',
1939
                ANONYMOUS,
1940
                ' anonymous@localhost',
1941
                $login,
1942
                $login
1943
            );
1944
1945
            return $userId;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $userId returns the type false which is incompatible with the documented return type integer.
Loading history...
1946
        } else {
1947
            $row = Database::fetch_array($result, 'ASSOC');
1948
1949
            return $row['user_id'];
1950
        }
1951
    }
1952
1953
    $table = Database::get_main_table(TABLE_MAIN_USER);
1954
    $sql = "SELECT user_id 
1955
            FROM $table 
1956
            WHERE status = ".ANONYMOUS." ";
1957
    $res = Database::query($sql);
1958
    if (Database::num_rows($res) > 0) {
1959
        $row = Database::fetch_array($res, 'ASSOC');
1960
1961
        return $row['user_id'];
1962
    }
1963
1964
    // No anonymous user was found.
1965
    return 0;
1966
}
1967
1968
/**
1969
 * @param string $courseCode
1970
 * @param int    $sessionId
1971
 * @param int    $groupId
1972
 *
1973
 * @return string
1974
 */
1975
function api_get_cidreq_params($courseCode, $sessionId = 0, $groupId = 0)
1976
{
1977
    $courseCode = !empty($courseCode) ? htmlspecialchars($courseCode) : '';
1978
    $sessionId = !empty($sessionId) ? (int) $sessionId : 0;
1979
    $groupId = !empty($groupId) ? (int) $groupId : 0;
1980
1981
    $url = 'cidReq='.$courseCode;
1982
    $url .= '&id_session='.$sessionId;
1983
    $url .= '&gidReq='.$groupId;
1984
1985
    return $url;
1986
}
1987
1988
/**
1989
 * Returns the current course url part including session, group, and gradebook params.
1990
 *
1991
 * @param bool   $addSessionId
1992
 * @param bool   $addGroupId
1993
 * @param string $origin
1994
 *
1995
 * @return string Course & session references to add to a URL
1996
 */
1997
function api_get_cidreq($addSessionId = true, $addGroupId = true, $origin = '')
1998
{
1999
    $courseCode = api_get_course_id();
2000
    $url = empty($courseCode) ? '' : 'cidReq='.htmlspecialchars($courseCode);
2001
    $origin = empty($origin) ? api_get_origin() : Security::remove_XSS($origin);
2002
2003
    if ($addSessionId) {
2004
        if (!empty($url)) {
2005
            $url .= api_get_session_id() == 0 ? '&id_session=0' : '&id_session='.api_get_session_id();
2006
        }
2007
    }
2008
2009
    if ($addGroupId) {
2010
        if (!empty($url)) {
2011
            $url .= api_get_group_id() == 0 ? '&gidReq=0' : '&gidReq='.api_get_group_id();
2012
        }
2013
    }
2014
2015
    if (!empty($url)) {
2016
        $url .= '&gradebook='.(int) api_is_in_gradebook();
2017
        $url .= '&origin='.$origin;
2018
    }
2019
2020
    return $url;
2021
}
2022
2023
/**
2024
 * Get if we visited a gradebook page.
2025
 *
2026
 * @return bool
2027
 */
2028
function api_is_in_gradebook()
2029
{
2030
    return Session::read('in_gradebook', false);
2031
}
2032
2033
/**
2034
 * Set that we are in a page inside a gradebook.
2035
 */
2036
function api_set_in_gradebook()
2037
{
2038
    Session::write('in_gradebook', true);
2039
}
2040
2041
/**
2042
 * Remove gradebook session.
2043
 */
2044
function api_remove_in_gradebook()
2045
{
2046
    Session::erase('in_gradebook');
2047
}
2048
2049
/**
2050
 * Returns the current course info array see api_format_course_array()
2051
 * If the course_code is given, the returned array gives info about that
2052
 * particular course, if none given it gets the course info from the session.
2053
 *
2054
 * @param string $course_code
2055
 *
2056
 * @return array
2057
 */
2058
function api_get_course_info($course_code = null)
2059
{
2060
    if (!empty($course_code)) {
2061
        $course = Container::getCourseRepository()->findOneByCode($course_code);
2062
        if (empty($course)) {
2063
            return [];
2064
        }
2065
2066
        $courseInfo = api_format_course_array($course);
2067
2068
        Session::write('_course', $courseInfo);
2069
2070
        return $courseInfo;
2071
    }
2072
2073
    /*$course_code = Database::escape_string($course_code);
2074
    $courseId = api_get_course_int_id($course_code);
2075
    if (empty($courseId)) {
2076
        return [];
2077
    }
2078
2079
    $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
2080
    $course_cat_table = Database::get_main_table(TABLE_MAIN_CATEGORY);
2081
    $sql = "SELECT
2082
                course.*,
2083
                course_category.code faCode,
2084
                course_category.name faName
2085
            FROM $course_table
2086
            LEFT JOIN $course_cat_table
2087
            ON course.category_code = course_category.code
2088
            WHERE course.id = $courseId";
2089
    $result = Database::query($sql);
2090
    $courseInfo = [];
2091
    if (Database::num_rows($result) > 0) {
2092
        $data = Database::fetch_array($result);
2093
        $courseInfo = api_format_course_array($data);
2094
    }
2095
2096
    return $courseInfo;*/
2097
2098
    $course = Session::read('_course');
2099
    if ($course == '-1') {
2100
        $course = [];
2101
    }
2102
2103
    return $course;
2104
}
2105
2106
/**
2107
 * @param int $courseId
2108
 *
2109
 * @return Course
2110
 */
2111
function api_get_course_entity($courseId = 0)
2112
{
2113
    if (empty($courseId)) {
2114
        $courseId = api_get_course_int_id();
2115
    }
2116
2117
    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

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

3736
    /** @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...
3737
    $message = null,
3738
    $responseCode = 0
3739
) {
3740
    $debug = api_get_setting('server_type') === 'test';
3741
3742
    // Default code is 403 forbidden
3743
    $responseCode = empty($responseCode) ? 403 : $responseCode;
3744
    $message = empty($message) ? get_lang('Not authorized') : $message;
3745
3746
    // Create new exception rendered by template:
3747
    // src/ThemeBundle/Resources/views/Exception/error.html.twig
3748
3749
    // if error is 404 then the template is:
3750
    // src/ThemeBundle/Resources/views/Exception/error404.html.twig
3751
    $exception = new Exception($message);
3752
    $request = Container::getRequest();
3753
    $exception = FlattenException::create($exception, $responseCode);
3754
    $controller = new ExceptionController(Container::getTwig(), $debug);
3755
    $response = $controller->showAction($request, $exception);
3756
    $response->send();
3757
    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...
3758
3759
    $home_url = api_get_path(WEB_PATH);
0 ignored issues
show
Unused Code introduced by
$home_url = api_get_path(WEB_PATH) is not reachable.

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

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

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

    return false;
}

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

Loading history...
3760
    $user_id = api_get_user_id();
3761
    $course = api_get_course_id();
3762
3763
    global $this_section;
3764
3765
    if (CustomPages::enabled() && !isset($user_id)) {
3766
        if (empty($user_id)) {
3767
            // Why the CustomPages::enabled() need to be to set the request_uri
3768
            $_SESSION['request_uri'] = $_SERVER['REQUEST_URI'];
3769
        }
3770
        CustomPages::display(CustomPages::INDEX_UNLOGGED);
3771
    }
3772
3773
    $origin = api_get_origin();
3774
3775
    $msg = null;
3776
    if (isset($message)) {
3777
        $msg = $message;
3778
    } else {
3779
        $msg = Display::return_message(
3780
            get_lang('Sorry, you are not allowed to access this page, or maybe your connection has expired. Please click your browser\'s "Back" button or follow the link below to return to the previous page.').'
3781
            <script>function goBack(){window.history.back();}</script>',
3782
            'error',
3783
            false
3784
        );
3785
        $msg .= '<p class="text-center">
3786
             <a onclick="goBack();" class="btn btn-default" href="'.$home_url.'">'.get_lang('Go back').'</a>
3787
             </p>';
3788
    }
3789
3790
    $msg = Display::div($msg, ['align' => 'center']);
3791
3792
    $show_headers = 0;
3793
    if ($print_headers && $origin != 'learnpath') {
3794
        $show_headers = 1;
3795
    }
3796
3797
    $tpl = new Template(null, $show_headers, $show_headers, false, true, false, true, $responseCode);
3798
    $tpl->assign('hide_login_link', 1);
3799
    $tpl->assign('content', $msg);
3800
3801
    if (($user_id != 0 && !api_is_anonymous()) &&
3802
        (!isset($course) || $course == -1) &&
3803
        empty($_GET['cidReq'])
3804
    ) {
3805
        // if the access is not authorized and there is some login information
3806
        // but the cidReq is not found, assume we are missing course data and send the user
3807
        // to the user_portal
3808
        $tpl->display_one_col_template();
3809
        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...
3810
    }
3811
3812
    if (!empty($_SERVER['REQUEST_URI']) &&
3813
        (
3814
            !empty($_GET['cidReq']) ||
3815
            $this_section == SECTION_MYPROFILE ||
3816
            $this_section == SECTION_PLATFORM_ADMIN
3817
        )
3818
    ) {
3819
        $courseCode = api_get_course_id();
3820
        // Only display form and return to the previous URL if there was a course ID included
3821
        if ($user_id != 0 && !api_is_anonymous()) {
3822
            //if there is a user ID, then the user is not allowed but the session is still there. Say so and exit
3823
            $tpl->assign('content', $msg);
3824
            $tpl->display_one_col_template();
3825
            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...
3826
        }
3827
3828
        if (!is_null($courseCode)) {
3829
            api_set_firstpage_parameter($courseCode);
3830
        }
3831
3832
        // If the user has no user ID, then his session has expired
3833
        $form = api_get_not_allowed_login_form();
3834
3835
        // see same text in auth/gotocourse.php and main_api.lib.php function api_not_allowed (above)
3836
        $content = Display::return_message(get_lang('You are not allowed to see this page. Either your connection has expired or you are trying to access a page for which you do not have the sufficient privileges.'), 'error', false);
3837
3838
        if (!empty($courseCode)) {
3839
            $content .= '<h4>'.get_lang('Please login to go to this course').'</h4>';
3840
        }
3841
3842
        $content .= '<div class="well">';
3843
        $content .= $form->returnForm();
3844
        $content .= '</div>';
3845
        if (!empty($courseCode)) {
3846
            $content .= '<hr/><p style="text-align:center"><a href="'.$home_url.'">'.
3847
                get_lang('Return to Course Homepage').'</a></p>';
3848
        } else {
3849
            $content .= '<hr/><p style="text-align:center"><a href="'.$home_url.'">'.
3850
                get_lang('Back to Home Page.').'</a></p>';
3851
        }
3852
3853
        $tpl->setLoginBodyClass();
3854
        $tpl->assign('content', $content);
3855
        $tpl->display_one_col_template();
3856
        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...
3857
    }
3858
3859
    if ($user_id != 0 && !api_is_anonymous()) {
3860
        $tpl->display_one_col_template();
3861
        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...
3862
    }
3863
3864
    $msg = null;
3865
    // The session is over and we were not in a course,
3866
    // or we try to get directly to a private course without being logged
3867
    $courseId = api_get_course_int_id();
3868
    if (!empty($courseId)) {
3869
        api_set_firstpage_parameter(api_get_course_id());
3870
        $tpl->setLoginBodyClass();
3871
3872
        // see same text in auth/gotocourse.php and main_api.lib.php function api_not_allowed (bellow)
3873
        $msg = Display::return_message(get_lang('You are not allowed to see this page. Either your connection has expired or you are trying to access a page for which you do not have the sufficient privileges.'), 'error', false);
3874
        $msg .= '<h4>'.get_lang('Please login to go to this course').'</h4>';
3875
        $form = api_get_not_allowed_login_form();
3876
        $msg .= '<div class="well">';
3877
        $msg .= $form->returnForm();
3878
        $msg .= '</div>';
3879
        if ($casEnabled) {
3880
            $msg .= "</div>";
3881
        }
3882
    } else {
3883
        // we were not in a course, return to home page
3884
        $msg = Display::return_message(
3885
            get_lang('You are not allowed to see this page. Either your connection has expired or you are trying to access a page for which you do not have the sufficient privileges.'),
3886
            'error',
3887
            false
3888
        );
3889
3890
        $msg .= '<p class="text-center">
3891
                 <a class="btn btn-default" href="'.$home_url.'">'.get_lang('Back to Home Page.').'</a>
3892
                 </p>';
3893
3894
        if (!empty($message)) {
3895
            $msg = $message;
3896
        }
3897
3898
        if (api_is_anonymous()) {
3899
            $form = api_get_not_allowed_login_form();
3900
            $msg .= '<div class="well">';
3901
            $msg .= $form->returnForm();
3902
            $msg .= '</div>';
3903
        }
3904
    }
3905
3906
    $tpl->assign('content', $msg);
3907
    $tpl->display_one_col_template();
3908
    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...
3909
}
3910
3911
/**
3912
 * @return FormValidator
3913
 */
3914
function api_get_not_allowed_login_form()
3915
{
3916
    $action = api_get_self().'?'.Security::remove_XSS($_SERVER['QUERY_STRING']);
3917
    $action = str_replace('&amp;', '&', $action);
3918
    Session::write('redirect_after_not_allow_page', $action);
3919
    $action .= '&redirect_after_not_allow_page=1';
3920
3921
    $form = new FormValidator(
3922
        'formLogin',
3923
        'post',
3924
        $action,
3925
        null,
3926
        ['class' => 'form-stacked']
3927
    );
3928
    $params = [
3929
        'placeholder' => get_lang('Username'),
3930
        'class' => 'col-md-3',
3931
    ];
3932
    if (api_browser_support('autocapitalize')) {
3933
        $params['autocapitalize'] = 'none';
3934
    }
3935
3936
    $form->addElement(
3937
        'text',
3938
        'login',
3939
        null,
3940
        $params
3941
    );
3942
    $form->addElement(
3943
        'password',
3944
        'password',
3945
        null,
3946
        ['placeholder' => get_lang('Password'), 'class' => 'col-md-3']
3947
    ); //new
3948
    $form->addButtonNext(get_lang('Login'), 'submitAuth');
3949
3950
    return $form;
3951
}
3952
3953
/**
3954
 * Gets a UNIX timestamp from a database (MySQL) datetime format string.
3955
 *
3956
 * @param $last_post_datetime standard output date in a sql query
3957
 *
3958
 * @return int timestamp
3959
 *
3960
 * @author Toon Van Hoecke <[email protected]>
3961
 *
3962
 * @version October 2003
3963
 * @desc convert sql date to unix timestamp
3964
 */
3965
function convert_sql_date($last_post_datetime)
3966
{
3967
    list($last_post_date, $last_post_time) = explode(' ', $last_post_datetime);
3968
    list($year, $month, $day) = explode('-', $last_post_date);
3969
    list($hour, $min, $sec) = explode(':', $last_post_time);
3970
3971
    return mktime((int) $hour, (int) $min, (int) $sec, (int) $month, (int) $day, (int) $year);
3972
}
3973
3974
/**
3975
 * Gets item visibility from the item_property table.
3976
 *
3977
 * Getting the visibility is done by getting the last updated visibility entry,
3978
 * using the largest session ID found if session 0 and another was found (meaning
3979
 * the only one that is actually from the session, in case there are results from
3980
 * session 0 *AND* session n).
3981
 *
3982
 * @param array  $_course  Course properties array (result of api_get_course_info())
3983
 * @param string $tool     Tool (learnpath, document, etc)
3984
 * @param int    $id       The item ID in the given tool
3985
 * @param int    $session  The session ID (optional)
3986
 * @param int    $user_id
3987
 * @param string $type
3988
 * @param string $group_id
3989
 *
3990
 * @return int -1 on error, 0 if invisible, 1 if visible
3991
 */
3992
function api_get_item_visibility(
3993
    $_course,
3994
    $tool,
3995
    $id,
3996
    $session = 0,
3997
    $user_id = null,
3998
    $type = null,
3999
    $group_id = null
4000
) {
4001
    if (!is_array($_course) || count($_course) == 0 || empty($tool) || empty($id)) {
4002
        return -1;
4003
    }
4004
4005
    $tool = Database::escape_string($tool);
4006
    $id = (int) $id;
4007
    $session = (int) $session;
4008
    $TABLE_ITEMPROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY);
4009
    $course_id = (int) $_course['real_id'];
4010
4011
    $userCondition = '';
4012
    if (!empty($user_id)) {
4013
        $user_id = (int) $user_id;
4014
        $userCondition = " AND to_user_id = $user_id ";
4015
    }
4016
4017
    $typeCondition = '';
4018
    if (!empty($type)) {
4019
        $type = Database::escape_string($type);
4020
        $typeCondition = " AND lastedit_type = '$type' ";
4021
    }
4022
4023
    $groupCondition = '';
4024
    if (!empty($group_id)) {
4025
        $group_id = (int) $group_id;
4026
        $groupCondition = " AND to_group_id = '$group_id' ";
4027
    }
4028
4029
    $sql = "SELECT visibility
4030
            FROM $TABLE_ITEMPROPERTY
4031
            WHERE
4032
                c_id = $course_id AND
4033
                tool = '$tool' AND
4034
                ref = $id AND
4035
                (session_id = $session OR session_id = 0 OR session_id IS NULL)
4036
                $userCondition $typeCondition $groupCondition
4037
            ORDER BY session_id DESC, lastedit_date DESC
4038
            LIMIT 1";
4039
4040
    $res = Database::query($sql);
4041
    if ($res === false || Database::num_rows($res) == 0) {
4042
        return -1;
4043
    }
4044
    $row = Database::fetch_array($res);
4045
4046
    return (int) $row['visibility'];
4047
}
4048
4049
/**
4050
 * Delete a row in the c_item_property table.
4051
 *
4052
 * @param array  $courseInfo
4053
 * @param string $tool
4054
 * @param int    $itemId
4055
 * @param int    $userId
4056
 * @param int    $groupId    group.iid
4057
 * @param int    $sessionId
4058
 *
4059
 * @return false|null
4060
 */
4061
function api_item_property_delete(
4062
    $courseInfo,
4063
    $tool,
4064
    $itemId,
4065
    $userId,
4066
    $groupId = 0,
4067
    $sessionId = 0
4068
) {
4069
    if (empty($courseInfo)) {
4070
        return false;
4071
    }
4072
4073
    $courseId = (int) $courseInfo['real_id'];
4074
4075
    if (empty($courseId) || empty($tool) || empty($itemId)) {
4076
        return false;
4077
    }
4078
4079
    $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4080
    $tool = Database::escape_string($tool);
4081
    $itemId = intval($itemId);
4082
    $userId = intval($userId);
4083
    $groupId = intval($groupId);
4084
    $sessionId = intval($sessionId);
4085
4086
    $groupCondition = " AND to_group_id = $groupId ";
4087
    if (empty($groupId)) {
4088
        $groupCondition = " AND (to_group_id is NULL OR to_group_id = 0) ";
4089
    }
4090
4091
    $userCondition = " AND to_user_id = $userId ";
4092
    if (empty($userId)) {
4093
        $userCondition = " AND (to_user_id is NULL OR to_user_id = 0) ";
4094
    }
4095
    $sessionCondition = api_get_session_condition($sessionId, true, false, 'session_id');
4096
    $sql = "DELETE FROM $table
4097
            WHERE
4098
                c_id = $courseId AND
4099
                tool  = '$tool' AND
4100
                ref = $itemId
4101
                $sessionCondition
4102
                $userCondition
4103
                $groupCondition
4104
            ";
4105
4106
    Database::query($sql);
4107
}
4108
4109
/**
4110
 * Updates or adds item properties to the Item_propetry table
4111
 * Tool and lastedit_type are language independant strings (langvars->get_lang!).
4112
 *
4113
 * @param array  $_course        array with course properties
4114
 * @param string $tool           tool id, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4115
 * @param int    $item_id        id of the item itself, linked to key of every tool ('id', ...)
4116
 * @param string $last_edit_type add or update action
4117
 *                               (1) message to be translated (in trad4all) : e.g. DocumentAdded, DocumentUpdated;
4118
 *                               (2) "delete"
4119
 *                               (3) "visible"
4120
 *                               (4) "invisible"
4121
 * @param int    $user_id        id of the editing/adding user
4122
 * @param array  $groupInfo      must include group.iid/group.od
4123
 * @param int    $to_user_id     id of the intended user (always has priority over $to_group_id !), only relevant for $type (1)
4124
 * @param string $start_visible  0000-00-00 00:00:00 format
4125
 * @param string $end_visible    0000-00-00 00:00:00 format
4126
 * @param int    $session_id     The session ID, if any, otherwise will default to 0
4127
 *
4128
 * @return bool false if update fails
4129
 *
4130
 * @author Toon Van Hoecke <[email protected]>, Ghent University
4131
 *
4132
 * @version January 2005
4133
 * @desc update the item_properties table (if entry not exists, insert) of the course
4134
 */
4135
function api_item_property_update(
4136
    $_course,
4137
    $tool,
4138
    $item_id,
4139
    $last_edit_type,
4140
    $user_id,
4141
    $groupInfo = [],
4142
    $to_user_id = null,
4143
    $start_visible = '',
4144
    $end_visible = '',
4145
    $session_id = 0
4146
) {
4147
    if (empty($_course)) {
4148
        return false;
4149
    }
4150
4151
    $course_id = $_course['real_id'];
4152
4153
    if (empty($course_id)) {
4154
        return false;
4155
    }
4156
4157
    $to_group_id = 0;
4158
    if (!empty($groupInfo) && isset($groupInfo['iid'])) {
4159
        $to_group_id = (int) $groupInfo['iid'];
4160
    }
4161
4162
    $em = Database::getManager();
4163
4164
    // Definition of variables.
4165
    $tool = Database::escape_string($tool);
4166
    $item_id = (int) $item_id;
4167
    $lastEditTypeNoFilter = $last_edit_type;
4168
    $last_edit_type = Database::escape_string($last_edit_type);
4169
    $user_id = (int) $user_id;
4170
4171
    $startVisible = "NULL";
4172
    if (!empty($start_visible)) {
4173
        $start_visible = Database::escape_string($start_visible);
4174
        $startVisible = "'$start_visible'";
4175
    }
4176
4177
    $endVisible = "NULL";
4178
    if (!empty($end_visible)) {
4179
        $end_visible = Database::escape_string($end_visible);
4180
        $endVisible = "'$end_visible'";
4181
    }
4182
4183
    $to_filter = '';
4184
    $time = api_get_utc_datetime();
4185
4186
    if (!empty($session_id)) {
4187
        $session_id = (int) $session_id;
4188
    } else {
4189
        $session_id = api_get_session_id();
4190
    }
4191
4192
    // Definition of tables.
4193
    $tableItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
4194
4195
    if ($to_user_id <= 0) {
4196
        $to_user_id = null; // No to_user_id set
4197
    }
4198
4199
    if (!is_null($to_user_id)) {
4200
        // $to_user_id has more priority than $to_group_id
4201
        $to_user_id = (int) $to_user_id;
4202
        $to_field = 'to_user_id';
4203
        $to_value = $to_user_id;
4204
    } else {
4205
        // $to_user_id is not set.
4206
        $to_field = 'to_group_id';
4207
        $to_value = $to_group_id;
4208
    }
4209
4210
    $toValueCondition = empty($to_value) ? 'NULL' : "'$to_value'";
4211
    // Set filters for $to_user_id and $to_group_id, with priority for $to_user_id
4212
    $condition_session = " AND session_id = $session_id ";
4213
    if (empty($session_id)) {
4214
        $condition_session = ' AND (session_id = 0 OR session_id IS NULL) ';
4215
    }
4216
4217
    $filter = " c_id = $course_id AND tool = '$tool' AND ref = $item_id $condition_session ";
4218
4219
    // Check whether $to_user_id and $to_group_id are passed in the function call.
4220
    // If both are not passed (both are null) then it is a message for everybody and $to_group_id should be 0 !
4221
    if (is_null($to_user_id) && is_null($to_group_id)) {
4222
        $to_group_id = 0;
4223
    }
4224
4225
    if (!is_null($to_user_id)) {
4226
        // Set filter to intended user.
4227
        $to_filter = " AND to_user_id = $to_user_id $condition_session";
4228
    } else {
4229
        // Set filter to intended group.
4230
        if (($to_group_id != 0) && $to_group_id == strval(intval($to_group_id))) {
4231
            $to_filter = " AND to_group_id = $to_group_id $condition_session";
4232
        }
4233
    }
4234
4235
    // Adding filter if set.
4236
    $filter .= $to_filter;
4237
4238
    // Update if possible
4239
    $set_type = '';
4240
4241
    switch ($lastEditTypeNoFilter) {
4242
        case 'delete':
4243
            // delete = make item only visible for the platform admin.
4244
            $visibility = '2';
4245
            if (!empty($session_id)) {
4246
                // Check whether session id already exist into item_properties for updating visibility or add it.
4247
                $sql = "SELECT session_id FROM $tableItemProperty
4248
                        WHERE
4249
                            c_id = $course_id AND
4250
                            tool = '$tool' AND
4251
                            ref = $item_id AND
4252
                            session_id = $session_id";
4253
                $rs = Database::query($sql);
4254
                if (Database::num_rows($rs) > 0) {
4255
                    $sql = "UPDATE $tableItemProperty
4256
                            SET lastedit_type       = '".str_replace('_', '', ucwords($tool))."Deleted',
4257
                                lastedit_date       = '$time',
4258
                                lastedit_user_id    = $user_id,
4259
                                visibility          = $visibility,
4260
                                session_id          = $session_id $set_type
4261
                            WHERE $filter";
4262
                    $result = Database::query($sql);
4263
                } else {
4264
                    $sql = "INSERT INTO $tableItemProperty (c_id, tool, ref, insert_date, insert_user_id, lastedit_date, lastedit_type, lastedit_user_id, $to_field, visibility, start_visible, end_visible, session_id)
4265
                            VALUES ($course_id, '$tool',$item_id, '$time', $user_id, '$time', '$last_edit_type',$user_id, $toValueCondition, $visibility, $startVisible, $endVisible, $session_id)";
4266
                    $result = Database::query($sql);
4267
                    $id = Database::insert_id();
4268
                    if ($id) {
4269
                        $sql = "UPDATE $tableItemProperty SET id = iid WHERE iid = $id";
4270
                        Database::query($sql);
4271
                    }
4272
                }
4273
            } else {
4274
                $sql = "UPDATE $tableItemProperty
4275
                        SET
4276
                            lastedit_type='".str_replace('_', '', ucwords($tool))."Deleted',
4277
                            lastedit_date='$time',
4278
                            lastedit_user_id = $user_id,
4279
                            visibility = $visibility $set_type
4280
                        WHERE $filter";
4281
                $result = Database::query($sql);
4282
            }
4283
            break;
4284
        case 'visible': // Change item to visible.
4285
            $visibility = '1';
4286
            if (!empty($session_id)) {
4287
                // Check whether session id already exist into item_properties for updating visibility or add it.
4288
                $sql = "SELECT session_id FROM $tableItemProperty
4289
                        WHERE
4290
                            c_id = $course_id AND
4291
                            tool = '$tool' AND
4292
                            ref = $item_id AND
4293
                            session_id = $session_id";
4294
                $rs = Database::query($sql);
4295
                if (Database::num_rows($rs) > 0) {
4296
                    $sql = "UPDATE $tableItemProperty
4297
                            SET
4298
                                lastedit_type='".str_replace('_', '', ucwords($tool))."Visible',
4299
                                lastedit_date='$time',
4300
                                lastedit_user_id = $user_id,
4301
                                visibility = $visibility,
4302
                                session_id = $session_id $set_type
4303
                            WHERE $filter";
4304
                    $result = Database::query($sql);
4305
                } else {
4306
                    $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)
4307
                            VALUES ($course_id, '$tool', $item_id, '$time', $user_id, '$time', '$last_edit_type', $user_id, $toValueCondition, $visibility, $startVisible, $endVisible, $session_id)";
4308
                    $result = Database::query($sql);
4309
                    $id = Database::insert_id();
4310
                    if ($id) {
4311
                        $sql = "UPDATE $tableItemProperty SET id = iid WHERE iid = $id";
4312
                        Database::query($sql);
4313
                    }
4314
                }
4315
            } else {
4316
                $sql = "UPDATE $tableItemProperty
4317
                        SET
4318
                            lastedit_type='".str_replace('_', '', ucwords($tool))."Visible',
4319
                            lastedit_date='$time',
4320
                            lastedit_user_id = $user_id,
4321
                            visibility = $visibility $set_type
4322
                        WHERE $filter";
4323
                $result = Database::query($sql);
4324
            }
4325
            break;
4326
        case 'invisible': // Change item to invisible.
4327
            $visibility = '0';
4328
            if (!empty($session_id)) {
4329
                // Check whether session id already exist into item_properties for updating visibility or add it
4330
                $sql = "SELECT session_id FROM $tableItemProperty
4331
                        WHERE
4332
                            c_id = $course_id AND
4333
                            tool = '$tool' AND
4334
                            ref = $item_id AND
4335
                            session_id = $session_id";
4336
                $rs = Database::query($sql);
4337
                if (Database::num_rows($rs) > 0) {
4338
                    $sql = "UPDATE $tableItemProperty
4339
                            SET
4340
                                lastedit_type = '".str_replace('_', '', ucwords($tool))."Invisible',
4341
                                lastedit_date = '$time',
4342
                                lastedit_user_id = $user_id,
4343
                                visibility = $visibility,
4344
                                session_id = $session_id $set_type
4345
                            WHERE $filter";
4346
                    $result = Database::query($sql);
4347
                } else {
4348
                    $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)
4349
                            VALUES ($course_id, '$tool', $item_id, '$time', $user_id, '$time', '$last_edit_type', $user_id, $toValueCondition, $visibility, $startVisible, $endVisible, $session_id)";
4350
                    $result = Database::query($sql);
4351
                    $id = Database::insert_id();
4352
                    if ($id) {
4353
                        $sql = "UPDATE $tableItemProperty SET id = iid WHERE iid = $id";
4354
                        Database::query($sql);
4355
                    }
4356
                }
4357
            } else {
4358
                $sql = "UPDATE $tableItemProperty
4359
                        SET
4360
                            lastedit_type = '".str_replace('_', '', ucwords($tool))."Invisible',
4361
                            lastedit_date = '$time',
4362
                            lastedit_user_id = $user_id,
4363
                            visibility = $visibility $set_type
4364
                        WHERE $filter";
4365
                $result = Database::query($sql);
4366
            }
4367
            break;
4368
        default: // The item will be added or updated.
4369
            $set_type = ", lastedit_type = '$last_edit_type' ";
4370
            $visibility = '1';
4371
            //$filter .= $to_filter; already added
4372
            $sql = "UPDATE $tableItemProperty
4373
                    SET
4374
                      lastedit_date = '$time',
4375
                      lastedit_user_id = $user_id $set_type
4376
                    WHERE $filter";
4377
            $result = Database::query($sql);
4378
    }
4379
4380
    // Insert if no entries are found (can only happen in case of $last_edit_type switch is 'default').
4381
    if ($result == false || Database::affected_rows($result) == 0) {
4382
        $objCourse = $em->find('ChamiloCoreBundle:Course', intval($course_id));
4383
        $objTime = new DateTime('now', new DateTimeZone('UTC'));
4384
        $objUser = api_get_user_entity($user_id);
4385
        if (empty($objUser)) {
4386
            // Use anonymous
4387
            $user_id = api_get_anonymous_id();
4388
            $objUser = api_get_user_entity($user_id);
4389
        }
4390
4391
        $objGroup = null;
4392
        if (!empty($to_group_id)) {
4393
            $objGroup = $em->find('ChamiloCourseBundle:CGroupInfo', $to_group_id);
4394
        }
4395
4396
        $objToUser = api_get_user_entity($to_user_id);
4397
        $objSession = $em->find('ChamiloCoreBundle:Session', intval($session_id));
4398
4399
        $startVisibleDate = !empty($start_visible) ? new DateTime($start_visible, new DateTimeZone('UTC')) : null;
4400
        $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...
4401
4402
        $cItemProperty = new CItemProperty($objCourse);
4403
        $cItemProperty
4404
            ->setTool($tool)
4405
            ->setRef($item_id)
4406
            ->setInsertDate($objTime)
4407
            ->setInsertUser($objUser)
4408
            ->setLasteditDate($objTime)
4409
            ->setLasteditType($last_edit_type)
4410
            ->setGroup($objGroup)
4411
            ->setToUser($objToUser)
4412
            ->setVisibility($visibility)
4413
            ->setStartVisible($startVisibleDate)
4414
            ->setEndVisible($endVisibleDate)
4415
            ->setSession($objSession);
4416
4417
        $em->persist($cItemProperty);
4418
        $em->flush();
4419
4420
        $id = $cItemProperty->getIid();
4421
4422
        if ($id) {
4423
            $cItemProperty->setId($id);
4424
            $em->merge($cItemProperty);
4425
            $em->flush();
4426
4427
            return false;
4428
        }
4429
    }
4430
4431
    return true;
4432
}
4433
4434
/**
4435
 * Gets item property by tool.
4436
 *
4437
 * @param string    course code
4438
 * @param string    tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4439
 * @param int       id of the item itself, linked to key of every tool ('id', ...), "*" = all items of the tool
4440
 * @param int    $session_id
4441
 * @param string $tool
4442
 * @param string $course_code
4443
 *
4444
 * @return array All fields from c_item_property (all rows found) or empty array
4445
 */
4446
function api_get_item_property_by_tool($tool, $course_code, $session_id = null)
4447
{
4448
    $course_info = api_get_course_info($course_code);
4449
    $tool = Database::escape_string($tool);
4450
4451
    // Definition of tables.
4452
    $item_property_table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4453
    $session_id = (int) $session_id;
4454
    $session_condition = ' AND session_id = '.$session_id;
4455
    if (empty($session_id)) {
4456
        $session_condition = " AND (session_id = 0 OR session_id IS NULL) ";
4457
    }
4458
    $course_id = $course_info['real_id'];
4459
4460
    $sql = "SELECT * FROM $item_property_table
4461
            WHERE
4462
                c_id = $course_id AND
4463
                tool = '$tool'
4464
                $session_condition ";
4465
    $rs = Database::query($sql);
4466
    $list = [];
4467
    if (Database::num_rows($rs) > 0) {
4468
        while ($row = Database::fetch_array($rs, 'ASSOC')) {
4469
            $list[] = $row;
4470
        }
4471
    }
4472
4473
    return $list;
4474
}
4475
4476
/**
4477
 * Gets item property by tool and user.
4478
 *
4479
 * @param int $userId
4480
 * @param int $tool
4481
 * @param int $courseId
4482
 * @param int $session_id
4483
 *
4484
 * @return array
4485
 */
4486
function api_get_item_property_list_by_tool_by_user(
4487
    $userId,
4488
    $tool,
4489
    $courseId,
4490
    $session_id = 0
4491
) {
4492
    $userId = intval($userId);
4493
    $tool = Database::escape_string($tool);
4494
    $session_id = intval($session_id);
4495
    $courseId = intval($courseId);
4496
4497
    // Definition of tables.
4498
    $item_property_table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4499
    $session_condition = ' AND session_id = '.$session_id;
4500
    if (empty($session_id)) {
4501
        $session_condition = " AND (session_id = 0 OR session_id IS NULL) ";
4502
    }
4503
    $sql = "SELECT * FROM $item_property_table
4504
            WHERE
4505
                insert_user_id = $userId AND
4506
                c_id = $courseId AND
4507
                tool = '$tool'
4508
                $session_condition ";
4509
4510
    $rs = Database::query($sql);
4511
    $list = [];
4512
    if (Database::num_rows($rs) > 0) {
4513
        while ($row = Database::fetch_array($rs, 'ASSOC')) {
4514
            $list[] = $row;
4515
        }
4516
    }
4517
4518
    return $list;
4519
}
4520
4521
/**
4522
 * Gets item property id from tool of a course.
4523
 *
4524
 * @param string $course_code course code
4525
 * @param string $tool        tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4526
 * @param int    $ref         id of the item itself, linked to key of every tool ('id', ...), "*" = all items of the tool
4527
 * @param int    $sessionId   Session ID (optional)
4528
 *
4529
 * @return int
4530
 */
4531
function api_get_item_property_id($course_code, $tool, $ref, $sessionId = 0)
4532
{
4533
    $course_info = api_get_course_info($course_code);
4534
    $tool = Database::escape_string($tool);
4535
    $ref = (int) $ref;
4536
4537
    // Definition of tables.
4538
    $tableItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
4539
    $course_id = $course_info['real_id'];
4540
    $sessionId = (int) $sessionId;
4541
    $sessionCondition = " AND session_id = $sessionId ";
4542
    if (empty($sessionId)) {
4543
        $sessionCondition = ' AND (session_id = 0 OR session_id IS NULL) ';
4544
    }
4545
    $sql = "SELECT id FROM $tableItemProperty
4546
            WHERE
4547
                c_id = $course_id AND
4548
                tool = '$tool' AND
4549
                ref = $ref
4550
                $sessionCondition";
4551
    $rs = Database::query($sql);
4552
    $item_property_id = '';
4553
    if (Database::num_rows($rs) > 0) {
4554
        $row = Database::fetch_array($rs);
4555
        $item_property_id = $row['id'];
4556
    }
4557
4558
    return $item_property_id;
4559
}
4560
4561
/**
4562
 * Inserts a record in the track_e_item_property table (No update).
4563
 *
4564
 * @param string $tool
4565
 * @param int    $ref
4566
 * @param string $title
4567
 * @param string $content
4568
 * @param int    $progress
4569
 *
4570
 * @return bool|int
4571
 */
4572
function api_track_item_property_update($tool, $ref, $title, $content, $progress)
4573
{
4574
    $tbl_stats_item_property = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ITEM_PROPERTY);
4575
    $course_id = api_get_course_int_id(); //numeric
4576
    $course_code = api_get_course_id(); //alphanumeric
4577
    $item_property_id = api_get_item_property_id($course_code, $tool, $ref);
4578
    if (!empty($item_property_id)) {
4579
        $sql = "INSERT IGNORE INTO $tbl_stats_item_property SET
4580
                course_id           = '$course_id',
4581
                item_property_id    = '$item_property_id',
4582
                title               = '".Database::escape_string($title)."',
4583
                content             = '".Database::escape_string($content)."',
4584
                progress            = '".intval($progress)."',
4585
                lastedit_date       = '".api_get_utc_datetime()."',
4586
                lastedit_user_id    = '".api_get_user_id()."',
4587
                session_id          = '".api_get_session_id()."'";
4588
        $result = Database::query($sql);
4589
        $affected_rows = Database::affected_rows($result);
4590
4591
        return $affected_rows;
4592
    }
4593
4594
    return false;
4595
}
4596
4597
/**
4598
 * @param string $tool
4599
 * @param int    $ref
4600
 *
4601
 * @return array|resource
4602
 */
4603
function api_get_track_item_property_history($tool, $ref)
4604
{
4605
    $tbl_stats_item_property = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ITEM_PROPERTY);
4606
    $course_id = api_get_course_int_id(); //numeric
4607
    $course_code = api_get_course_id(); //alphanumeric
4608
    $item_property_id = api_get_item_property_id($course_code, $tool, $ref);
4609
    $sql = "SELECT * FROM $tbl_stats_item_property
4610
            WHERE item_property_id = $item_property_id AND course_id = $course_id
4611
            ORDER BY lastedit_date DESC";
4612
    $result = Database::query($sql);
4613
    if ($result === false or $result === null) {
4614
        $result = [];
4615
    } else {
4616
        $result = Database::store_result($result, 'ASSOC');
4617
    }
4618
4619
    return $result;
4620
}
4621
4622
/**
4623
 * Gets item property data from tool of a course id.
4624
 *
4625
 * @param int    $course_id
4626
 * @param string $tool       tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4627
 * @param int    $ref        id of the item itself, linked to key of every tool ('id', ...), "*" = all items of the tool
4628
 * @param int    $session_id
4629
 * @param int    $groupId
4630
 *
4631
 * @return array with all fields from c_item_property, empty array if not found or false if course could not be found
4632
 */
4633
function api_get_item_property_info($course_id, $tool, $ref, $session_id = 0, $groupId = 0)
4634
{
4635
    $courseInfo = api_get_course_info_by_id($course_id);
4636
4637
    if (empty($courseInfo)) {
4638
        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...
4639
    }
4640
4641
    $tool = Database::escape_string($tool);
4642
    $course_id = $courseInfo['real_id'];
4643
    $ref = (int) $ref;
4644
    $session_id = (int) $session_id;
4645
4646
    $sessionCondition = " session_id = $session_id";
4647
    if (empty($session_id)) {
4648
        $sessionCondition = ' (session_id = 0 OR session_id IS NULL) ';
4649
    }
4650
4651
    // Definition of tables.
4652
    $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4653
4654
    $sql = "SELECT * FROM $table
4655
            WHERE
4656
                c_id = $course_id AND
4657
                tool = '$tool' AND
4658
                ref = $ref AND
4659
                $sessionCondition ";
4660
4661
    if (!empty($groupId)) {
4662
        $groupId = (int) $groupId;
4663
        $sql .= " AND to_group_id = $groupId ";
4664
    }
4665
4666
    $rs = Database::query($sql);
4667
    $row = [];
4668
    if (Database::num_rows($rs) > 0) {
4669
        $row = Database::fetch_array($rs, 'ASSOC');
4670
    }
4671
4672
    return $row;
4673
}
4674
4675
/**
4676
 * Displays a combo box so the user can select his/her preferred language.
4677
 *
4678
 * @param string The desired name= value for the select
4679
 * @param bool Whether we use the JQuery Chozen library or not
4680
 * (in some cases, like the indexing language picker, it can alter the presentation)
4681
 *
4682
 * @deprecated
4683
 *
4684
 * @return string
4685
 */
4686
function api_get_languages_combo($name = 'language')
4687
{
4688
    $ret = '';
4689
    $platformLanguage = api_get_setting('platformLanguage');
4690
4691
    // Retrieve a complete list of all the languages.
4692
    $language_list = api_get_languages();
4693
4694
    if (count($language_list) < 2) {
4695
        return $ret;
4696
    }
4697
4698
    // The the current language of the user so that his/her language occurs as selected in the dropdown menu.
4699
    if (isset($_SESSION['user_language_choice'])) {
4700
        $default = $_SESSION['user_language_choice'];
4701
    } else {
4702
        $default = $platformLanguage;
4703
    }
4704
4705
    $ret .= '<select name="'.$name.'" id="language_chosen" class="selectpicker show-tick form-control">';
4706
    foreach ($language_list as $key => $value) {
4707
        if ($key == $default) {
4708
            $selected = ' selected="selected"';
4709
        } else {
4710
            $selected = '';
4711
        }
4712
        $ret .= sprintf('<option value=%s" %s>%s</option>', $key, $selected, $value);
4713
    }
4714
    $ret .= '</select>';
4715
4716
    return $ret;
4717
}
4718
4719
/**
4720
 * Displays a form (drop down menu) so the user can select his/her preferred language.
4721
 * The form works with or without javascript.
4722
 *
4723
 * @param  bool Hide form if only one language available (defaults to false = show the box anyway)
4724
 * @param bool $showAsButton
4725
 *
4726
 * @return string|null Display the box directly
4727
 */
4728
function api_display_language_form($hide_if_no_choice = false, $showAsButton = false)
4729
{
4730
    // Retrieve a complete list of all the languages.
4731
    $language_list = api_get_languages();
4732
    if (count($language_list['name']) <= 1 && $hide_if_no_choice) {
4733
        return; //don't show any form
4734
    }
4735
4736
    // The the current language of the user so that his/her language occurs as selected in the dropdown menu.
4737
    if (isset($_SESSION['user_language_choice'])) {
4738
        $user_selected_language = $_SESSION['user_language_choice'];
4739
    }
4740
    if (empty($user_selected_language)) {
4741
        $user_selected_language = api_get_setting('platformLanguage');
4742
    }
4743
4744
    $currentLanguageId = api_get_language_id($user_selected_language);
4745
    $currentLanguageInfo = api_get_language_info($currentLanguageId);
4746
    $countryCode = languageToCountryIsoCode($currentLanguageInfo['isocode']);
4747
    $url = api_get_self();
4748
    if ($showAsButton) {
4749
        $html = '<div class="btn-group">
4750
              <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
4751
                <span class="flag-icon flag-icon-'.$countryCode.'"></span>
4752
                '.$currentLanguageInfo['original_name'].'
4753
                <span class="caret">
4754
                </span>
4755
              </button>';
4756
    } else {
4757
        $html = '
4758
            <a href="'.$url.'" class="dropdown-toggle" data-toggle="dropdown" role="button">
4759
                <span class="flag-icon flag-icon-'.$countryCode.'"></span> 
4760
                '.$currentLanguageInfo['original_name'].'
4761
                <span class="caret"></span>
4762
            </a>
4763
            ';
4764
    }
4765
4766
    $html .= '<ul class="dropdown-menu" role="menu">';
4767
    foreach ($language_list['all'] as $key => $data) {
4768
        $urlLink = $url.'?language='.$data['english_name'];
4769
        $html .= '<li><a href="'.$urlLink.'"><span class="flag-icon flag-icon-'.languageToCountryIsoCode($data['isocode']).'"></span> '.$data['original_name'].'</a></li>';
4770
    }
4771
    $html .= '</ul>';
4772
4773
    if ($showAsButton) {
4774
        $html .= '</div>';
4775
    }
4776
4777
    return $html;
4778
}
4779
4780
/**
4781
 * @param string $languageIsoCode
4782
 *
4783
 * @return string
4784
 */
4785
function languageToCountryIsoCode($languageIsoCode)
4786
{
4787
    $allow = api_get_configuration_value('language_flags_by_country');
4788
4789
    // @todo save in DB
4790
    switch ($languageIsoCode) {
4791
        case 'ko':
4792
            $country = 'kr';
4793
            break;
4794
        case 'ja':
4795
            $country = 'jp';
4796
            break;
4797
        case 'ca':
4798
            $country = 'es';
4799
            if ($allow) {
4800
                $country = 'catalan';
4801
            }
4802
            break;
4803
        case 'gl': // galego
4804
            $country = 'es';
4805
            if ($allow) {
4806
                $country = 'galician';
4807
            }
4808
            break;
4809
        case 'ka':
4810
            $country = 'ge';
4811
            break;
4812
        case 'sl':
4813
            $country = 'si';
4814
            break;
4815
        case 'eu': // Euskera
4816
            $country = 'es';
4817
            if ($allow) {
4818
                $country = 'basque';
4819
            }
4820
            break;
4821
        case 'cs':
4822
            $country = 'cz';
4823
            break;
4824
        case 'el':
4825
            $country = 'ae';
4826
            break;
4827
        case 'ar':
4828
            $country = 'ae';
4829
            break;
4830
        case 'en_US':
4831
        case 'en':
4832
            $country = 'gb';
4833
            break;
4834
        case 'he':
4835
            $country = 'il';
4836
            break;
4837
        case 'uk': // Ukraine
4838
            $country = 'ua';
4839
            break;
4840
        case 'da':
4841
            $country = 'dk';
4842
            break;
4843
        case 'pt-BR':
4844
            $country = 'br';
4845
            break;
4846
        case 'qu':
4847
            $country = 'pe';
4848
            break;
4849
        case 'sv':
4850
            $country = 'se';
4851
            break;
4852
        case 'zh-TW':
4853
        case 'zh':
4854
            $country = 'cn';
4855
            break;
4856
        default:
4857
            $country = $languageIsoCode;
4858
            break;
4859
    }
4860
    $country = strtolower($country);
4861
4862
    return $country;
4863
}
4864
4865
/**
4866
 * Returns a list of all the languages that are made available by the admin.
4867
 *
4868
 * @return array An array with all languages. Structure of the array is
4869
 *               array['name'] = An array with the name of every language
4870
 *               array['folder'] = An array with the corresponding names of the language-folders in the filesystem
4871
 */
4872
function api_get_languages()
4873
{
4874
    $table = Database::get_main_table(TABLE_MAIN_LANGUAGE);
4875
    $sql = "SELECT * FROM $table WHERE available='1' 
4876
            ORDER BY original_name ASC";
4877
    $result = Database::query($sql);
4878
    $languages = [];
4879
    while ($row = Database::fetch_array($result, 'ASSOC')) {
4880
        $languages[$row['isocode']] = $row['original_name'];
4881
    }
4882
4883
    return $languages;
4884
}
4885
4886
/**
4887
 * Returns a list of all the languages that are made available by the admin.
4888
 *
4889
 * @return array
4890
 */
4891
function api_get_languages_to_array()
4892
{
4893
    $tbl_language = Database::get_main_table(TABLE_MAIN_LANGUAGE);
4894
    $sql = "SELECT * FROM $tbl_language WHERE available='1' ORDER BY original_name ASC";
4895
    $result = Database::query($sql);
4896
    $languages = [];
4897
    while ($row = Database::fetch_array($result)) {
4898
        $languages[$row['dokeos_folder']] = $row['original_name'];
4899
    }
4900
4901
    return $languages;
4902
}
4903
4904
/**
4905
 * Returns the id (the database id) of a language.
4906
 *
4907
 * @param   string  language name (the corresponding name of the language-folder in the filesystem)
4908
 *
4909
 * @return int id of the language
4910
 */
4911
function api_get_language_id($language)
4912
{
4913
    $tbl_language = Database::get_main_table(TABLE_MAIN_LANGUAGE);
4914
    if (empty($language)) {
4915
        return null;
4916
    }
4917
    $language = Database::escape_string($language);
4918
    $sql = "SELECT id FROM $tbl_language
4919
            WHERE dokeos_folder = '$language' LIMIT 1";
4920
    $result = Database::query($sql);
4921
    $row = Database::fetch_array($result);
4922
4923
    return $row['id'];
4924
}
4925
4926
/**
4927
 * Get the language information by its id.
4928
 *
4929
 * @param int $languageId
4930
 *
4931
 * @throws Exception
4932
 *
4933
 * @return array
4934
 */
4935
function api_get_language_info($languageId)
4936
{
4937
    if (empty($languageId)) {
4938
        return [];
4939
    }
4940
4941
    $language = Database::getManager()
4942
        ->find('ChamiloCoreBundle:Language', $languageId);
4943
4944
    if (!$language) {
4945
        return [];
4946
    }
4947
4948
    return [
4949
        'id' => $language->getId(),
4950
        'original_name' => $language->getOriginalName(),
4951
        'english_name' => $language->getEnglishName(),
4952
        'isocode' => $language->getIsocode(),
4953
        'dokeos_folder' => $language->getDokeosFolder(),
4954
        'available' => $language->getAvailable(),
4955
        'parent_id' => $language->getParent() ? $language->getParent()->getId() : null,
4956
    ];
4957
}
4958
4959
/**
4960
 * @param string $code
4961
 *
4962
 * @return \Chamilo\CoreBundle\Entity\Language
4963
 */
4964
function api_get_language_from_iso($code)
4965
{
4966
    $em = Database::getManager();
4967
    $language = $em->getRepository('ChamiloCoreBundle:Language')->findOneBy(['isocode' => $code]);
4968
4969
    return $language;
4970
}
4971
4972
/**
4973
 * Returns the name of the visual (CSS) theme to be applied on the current page.
4974
 * The returned name depends on the platform, course or user -wide settings.
4975
 *
4976
 * @return string The visual theme's name, it is the name of a folder inside web/css/themes
4977
 */
4978
function api_get_visual_theme()
4979
{
4980
    static $visual_theme;
4981
    if (!isset($visual_theme)) {
4982
        // Get style directly from DB
4983
        $styleFromDatabase = api_get_settings_params_simple(
4984
            [
4985
                'variable = ? AND access_url = ?' => [
4986
                    'stylesheets',
4987
                    api_get_current_access_url_id(),
4988
                ],
4989
            ]
4990
        );
4991
        if ($styleFromDatabase) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $styleFromDatabase of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
4992
            $platform_theme = $styleFromDatabase['selected_value'];
4993
        } else {
4994
            $platform_theme = api_get_setting('stylesheets');
4995
        }
4996
4997
        // Platform's theme.
4998
        $visual_theme = $platform_theme;
4999
        if (api_get_setting('user_selected_theme') == 'true') {
5000
            $user_info = api_get_user_info();
5001
            if (isset($user_info['theme'])) {
5002
                $user_theme = $user_info['theme'];
5003
5004
                if (!empty($user_theme)) {
5005
                    $visual_theme = $user_theme;
5006
                    // User's theme.
5007
                }
5008
            }
5009
        }
5010
5011
        $course_id = api_get_course_id();
5012
        if (!empty($course_id)) {
5013
            if (api_get_setting('allow_course_theme') == 'true') {
5014
                $course_theme = api_get_course_setting('course_theme', $course_id);
5015
5016
                if (!empty($course_theme) && $course_theme != -1) {
5017
                    if (!empty($course_theme)) {
5018
                        // Course's theme.
5019
                        $visual_theme = $course_theme;
5020
                    }
5021
                }
5022
5023
                $allow_lp_theme = api_get_course_setting('allow_learning_path_theme');
5024
                if ($allow_lp_theme == 1) {
5025
                    global $lp_theme_css, $lp_theme_config;
5026
                    // These variables come from the file lp_controller.php.
5027
                    if (!$lp_theme_config) {
5028
                        if (!empty($lp_theme_css)) {
5029
                            // LP's theme.
5030
                            $visual_theme = $lp_theme_css;
5031
                        }
5032
                    }
5033
                }
5034
            }
5035
        }
5036
5037
        if (empty($visual_theme)) {
5038
            $visual_theme = 'chamilo';
5039
        }
5040
5041
        global $lp_theme_log;
5042
        if ($lp_theme_log) {
5043
            $visual_theme = $platform_theme;
5044
        }
5045
    }
5046
5047
    return $visual_theme;
5048
}
5049
5050
/**
5051
 * Returns a list of CSS themes currently available in the CSS folder
5052
 * The folder must have a default.css file.
5053
 *
5054
 * @param bool $getOnlyThemeFromVirtualInstance Used by the vchamilo plugin
5055
 *
5056
 * @return array list of themes directories from the css folder
5057
 *               Note: Directory names (names of themes) in the file system should contain ASCII-characters only
5058
 */
5059
function api_get_themes($getOnlyThemeFromVirtualInstance = false)
5060
{
5061
    // This configuration value is set by the vchamilo plugin
5062
    $virtualTheme = api_get_configuration_value('virtual_css_theme_folder');
5063
5064
    $readCssFolder = function ($dir) use ($virtualTheme) {
5065
        $finder = new Finder();
5066
        $themes = $finder->directories()->in($dir)->depth(0)->sortByName();
5067
        $list = [];
5068
        /** @var Symfony\Component\Finder\SplFileInfo $theme */
5069
        foreach ($themes as $theme) {
5070
            $folder = $theme->getFilename();
5071
            // A theme folder is consider if there's a default.css file
5072
            if (!file_exists($theme->getPathname().'/default.css')) {
5073
                continue;
5074
            }
5075
            $name = ucwords(str_replace('_', ' ', $folder));
5076
            if ($folder == $virtualTheme) {
5077
                continue;
5078
            }
5079
            $list[$folder] = $name;
5080
        }
5081
5082
        return $list;
5083
    };
5084
5085
    $dir = api_get_path(SYS_CSS_PATH).'themes/';
5086
    $list = $readCssFolder($dir);
5087
5088
    if (!empty($virtualTheme)) {
5089
        $newList = $readCssFolder($dir.'/'.$virtualTheme);
5090
        if ($getOnlyThemeFromVirtualInstance) {
5091
            return $newList;
5092
        }
5093
        $list = $list + $newList;
5094
        asort($list);
5095
    }
5096
5097
    return $list;
5098
}
5099
5100
/**
5101
 * Find the largest sort value in a given user_course_category
5102
 * This function is used when we are moving a course to a different category
5103
 * and also when a user subscribes to courses (the new course is added at the end of the main category.
5104
 *
5105
 * @author Patrick Cool <[email protected]>, Ghent University
5106
 *
5107
 * @param int $user_course_category the id of the user_course_category
5108
 * @param int $user_id
5109
 *
5110
 * @return int the value of the highest sort of the user_course_category
5111
 */
5112
function api_max_sort_value($user_course_category, $user_id)
5113
{
5114
    $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
5115
    $sql = "SELECT max(sort) as max_sort FROM $tbl_course_user
5116
            WHERE
5117
                user_id='".intval($user_id)."' AND
5118
                relation_type<>".COURSE_RELATION_TYPE_RRHH." AND
5119
                user_course_cat='".intval($user_course_category)."'";
5120
    $result_max = Database::query($sql);
5121
    if (Database::num_rows($result_max) == 1) {
5122
        $row_max = Database::fetch_array($result_max);
5123
5124
        return $row_max['max_sort'];
5125
    }
5126
5127
    return 0;
5128
}
5129
5130
/**
5131
 * Transforms a number of seconds in hh:mm:ss format.
5132
 *
5133
 * @author Julian Prud'homme
5134
 *
5135
 * @param int    $seconds      number of seconds
5136
 * @param string $space
5137
 * @param bool   $showSeconds
5138
 * @param bool   $roundMinutes
5139
 *
5140
 * @return string the formatted time
5141
 */
5142
function api_time_to_hms($seconds, $space = ':', $showSeconds = true, $roundMinutes = false)
5143
{
5144
    // $seconds = -1 means that we have wrong data in the db.
5145
    if ($seconds == -1) {
5146
        return
5147
            get_lang('Unknown').
5148
            Display::return_icon(
5149
                'info2.gif',
5150
                get_lang('The datas about this user were registered when the calculation of time spent on the platform wasn\'t possible.'),
5151
                ['align' => 'absmiddle', 'hspace' => '3px']
5152
            );
5153
    }
5154
5155
    // How many hours ?
5156
    $hours = floor($seconds / 3600);
5157
5158
    // How many minutes ?
5159
    $min = floor(($seconds - ($hours * 3600)) / 60);
5160
5161
    if ($roundMinutes) {
5162
        if ($min >= 45) {
5163
            $min = 45;
5164
        }
5165
5166
        if ($min >= 30 && $min <= 44) {
5167
            $min = 30;
5168
        }
5169
5170
        if ($min >= 15 && $min <= 29) {
5171
            $min = 15;
5172
        }
5173
5174
        if ($min >= 0 && $min <= 14) {
5175
            $min = 0;
5176
        }
5177
    }
5178
5179
    // How many seconds
5180
    $sec = floor($seconds - ($hours * 3600) - ($min * 60));
5181
5182
    if ($hours < 10) {
5183
        $hours = "0$hours";
5184
    }
5185
5186
    if ($sec < 10) {
5187
        $sec = "0$sec";
5188
    }
5189
5190
    if ($min < 10) {
5191
        $min = "0$min";
5192
    }
5193
5194
    $seconds = '';
5195
    if ($showSeconds) {
5196
        $seconds = $space.$sec;
5197
    }
5198
5199
    return $hours.$space.$min.$seconds;
5200
}
5201
5202
/* FILE SYSTEM RELATED FUNCTIONS */
5203
5204
/**
5205
 * Returns the permissions to be assigned to every newly created directory by the web-server.
5206
 * The return value is based on the platform administrator's setting
5207
 * "Administration > Configuration settings > Security > Permissions for new directories".
5208
 *
5209
 * @return int returns the permissions in the format "Owner-Group-Others, Read-Write-Execute", as an integer value
5210
 */
5211
function api_get_permissions_for_new_directories()
5212
{
5213
    static $permissions;
5214
    if (!isset($permissions)) {
5215
        $permissions = trim(api_get_setting('permissions_for_new_directories'));
5216
        // The default value 0777 is according to that in the platform administration panel after fresh system installation.
5217
        $permissions = octdec(!empty($permissions) ? $permissions : '0777');
5218
    }
5219
5220
    return $permissions;
5221
}
5222
5223
/**
5224
 * Returns the permissions to be assigned to every newly created directory by the web-server.
5225
 * The return value is based on the platform administrator's setting
5226
 * "Administration > Configuration settings > Security > Permissions for new files".
5227
 *
5228
 * @return int returns the permissions in the format
5229
 *             "Owner-Group-Others, Read-Write-Execute", as an integer value
5230
 */
5231
function api_get_permissions_for_new_files()
5232
{
5233
    static $permissions;
5234
    if (!isset($permissions)) {
5235
        $permissions = trim(api_get_setting('permissions_for_new_files'));
5236
        // The default value 0666 is according to that in the platform
5237
        // administration panel after fresh system installation.
5238
        $permissions = octdec(!empty($permissions) ? $permissions : '0666');
5239
    }
5240
5241
    return $permissions;
5242
}
5243
5244
/**
5245
 * Deletes a file, or a folder and its contents.
5246
 *
5247
 * @author      Aidan Lister <[email protected]>
5248
 *
5249
 * @version     1.0.3
5250
 *
5251
 * @param string $dirname Directory to delete
5252
 * @param       bool     Deletes only the content or not
5253
 * @param bool $strict if one folder/file fails stop the loop
5254
 *
5255
 * @return bool Returns TRUE on success, FALSE on failure
5256
 *
5257
 * @see http://aidanlister.com/2004/04/recursively-deleting-a-folder-in-php/
5258
 *
5259
 * @author      Yannick Warnier, adaptation for the Chamilo LMS, April, 2008
5260
 * @author      Ivan Tcholakov, a sanity check about Directory class creation has been added, September, 2009
5261
 */
5262
function rmdirr($dirname, $delete_only_content_in_folder = false, $strict = false)
5263
{
5264
    $res = true;
5265
    // A sanity check.
5266
    if (!file_exists($dirname)) {
5267
        return false;
5268
    }
5269
    $php_errormsg = '';
5270
    // Simple delete for a file.
5271
    if (is_file($dirname) || is_link($dirname)) {
5272
        $res = unlink($dirname);
5273
        if ($res === false) {
5274
            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);
5275
        }
5276
5277
        return $res;
5278
    }
5279
5280
    // Loop through the folder.
5281
    $dir = dir($dirname);
5282
    // A sanity check.
5283
    $is_object_dir = is_object($dir);
5284
    if ($is_object_dir) {
5285
        while (false !== $entry = $dir->read()) {
5286
            // Skip pointers.
5287
            if ($entry == '.' || $entry == '..') {
5288
                continue;
5289
            }
5290
5291
            // Recurse.
5292
            if ($strict) {
5293
                $result = rmdirr("$dirname/$entry");
5294
                if ($result == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
5295
                    $res = false;
5296
                    break;
5297
                }
5298
            } else {
5299
                rmdirr("$dirname/$entry");
5300
            }
5301
        }
5302
    }
5303
5304
    // Clean up.
5305
    if ($is_object_dir) {
5306
        $dir->close();
5307
    }
5308
5309
    if ($delete_only_content_in_folder == false) {
5310
        $res = rmdir($dirname);
5311
        if ($res === false) {
5312
            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);
5313
        }
5314
    }
5315
5316
    return $res;
5317
}
5318
5319
// TODO: This function is to be simplified. File access modes to be implemented.
5320
/**
5321
 * function adapted from a php.net comment
5322
 * copy recursively a folder.
5323
 *
5324
 * @param the source folder
5325
 * @param the dest folder
5326
 * @param an array of excluded file_name (without extension)
5327
 * @param copied_files the returned array of copied files
5328
 * @param string $source
5329
 * @param string $dest
5330
 */
5331
function copyr($source, $dest, $exclude = [], $copied_files = [])
5332
{
5333
    if (empty($dest)) {
5334
        return false;
5335
    }
5336
    // Simple copy for a file
5337
    if (is_file($source)) {
5338
        $path_info = pathinfo($source);
5339
        if (!in_array($path_info['filename'], $exclude)) {
5340
            copy($source, $dest);
5341
        }
5342
5343
        return true;
5344
    } elseif (!is_dir($source)) {
5345
        //then source is not a dir nor a file, return
5346
        return false;
5347
    }
5348
5349
    // Make destination directory.
5350
    if (!is_dir($dest)) {
5351
        mkdir($dest, api_get_permissions_for_new_directories());
5352
    }
5353
5354
    // Loop through the folder.
5355
    $dir = dir($source);
5356
    while (false !== $entry = $dir->read()) {
5357
        // Skip pointers
5358
        if ($entry == '.' || $entry == '..') {
5359
            continue;
5360
        }
5361
5362
        // Deep copy directories.
5363
        if ($dest !== "$source/$entry") {
5364
            $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

5364
            $files = copyr("$source/$entry", "$dest/$entry", $exclude, /** @scrutinizer ignore-type */ $copied_files);
Loading history...
5365
        }
5366
    }
5367
    // Clean up.
5368
    $dir->close();
5369
5370
    return true;
5371
}
5372
5373
/**
5374
 * @todo: Using DIRECTORY_SEPARATOR is not recommended, this is an obsolete approach.
5375
 * Documentation header to be added here.
5376
 *
5377
 * @param string $pathname
5378
 * @param string $base_path_document
5379
 * @param int    $session_id
5380
 *
5381
 * @return mixed True if directory already exists, false if a file already exists at
5382
 *               the destination and null if everything goes according to plan
5383
 */
5384
function copy_folder_course_session(
5385
    $pathname,
5386
    $base_path_document,
5387
    $session_id,
5388
    $course_info,
5389
    $document,
5390
    $source_course_id
5391
) {
5392
    $table = Database::get_course_table(TABLE_DOCUMENT);
5393
    $session_id = intval($session_id);
5394
    $source_course_id = intval($source_course_id);
5395
5396
    // Check whether directory already exists.
5397
    if (is_dir($pathname) || empty($pathname)) {
5398
        return true;
5399
    }
5400
5401
    // Ensure that a file with the same name does not already exist.
5402
    if (is_file($pathname)) {
5403
        trigger_error('copy_folder_course_session(): File exists', E_USER_WARNING);
5404
5405
        return false;
5406
    }
5407
5408
    $course_id = $course_info['real_id'];
5409
    $folders = explode(DIRECTORY_SEPARATOR, str_replace($base_path_document.DIRECTORY_SEPARATOR, '', $pathname));
5410
    $new_pathname = $base_path_document;
5411
    $path = '';
5412
5413
    foreach ($folders as $folder) {
5414
        $new_pathname .= DIRECTORY_SEPARATOR.$folder;
5415
        $path .= DIRECTORY_SEPARATOR.$folder;
5416
5417
        if (!file_exists($new_pathname)) {
5418
            $path = Database::escape_string($path);
5419
5420
            $sql = "SELECT * FROM $table
5421
                    WHERE
5422
                        c_id = $source_course_id AND
5423
                        path = '$path' AND
5424
                        filetype = 'folder' AND
5425
                        session_id = '$session_id'";
5426
            $rs1 = Database::query($sql);
5427
            $num_rows = Database::num_rows($rs1);
5428
5429
            if ($num_rows == 0) {
5430
                mkdir($new_pathname, api_get_permissions_for_new_directories());
5431
5432
                // Insert new folder with destination session_id.
5433
                $params = [
5434
                    'c_id' => $course_id,
5435
                    'path' => $path,
5436
                    'comment' => $document->comment,
5437
                    'title' => basename($new_pathname),
5438
                    'filetype' => 'folder',
5439
                    'size' => '0',
5440
                    'session_id' => $session_id,
5441
                ];
5442
                $document_id = Database::insert($table, $params);
5443
                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...
5444
                    $sql = "UPDATE $table SET id = iid WHERE iid = $document_id";
5445
                    Database::query($sql);
5446
5447
                    api_item_property_update(
5448
                        $course_info,
5449
                        TOOL_DOCUMENT,
5450
                        $document_id,
5451
                        'FolderCreated',
5452
                        api_get_user_id(),
5453
                        0,
5454
                        0,
5455
                        null,
5456
                        null,
5457
                        $session_id
5458
                    );
5459
                }
5460
            }
5461
        }
5462
    } // en foreach
5463
}
5464
5465
// TODO: chmodr() is a better name. Some corrections are needed. Documentation header to be added here.
5466
/**
5467
 * @param string $path
5468
 */
5469
function api_chmod_R($path, $filemode)
5470
{
5471
    if (!is_dir($path)) {
5472
        return chmod($path, $filemode);
5473
    }
5474
5475
    $handler = opendir($path);
5476
    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

5476
    while ($file = readdir(/** @scrutinizer ignore-type */ $handler)) {
Loading history...
5477
        if ($file != '.' && $file != '..') {
5478
            $fullpath = "$path/$file";
5479
            if (!is_dir($fullpath)) {
5480
                if (!chmod($fullpath, $filemode)) {
5481
                    return false;
5482
                }
5483
            } else {
5484
                if (!api_chmod_R($fullpath, $filemode)) {
5485
                    return false;
5486
                }
5487
            }
5488
        }
5489
    }
5490
5491
    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

5491
    closedir(/** @scrutinizer ignore-type */ $handler);
Loading history...
5492
5493
    return chmod($path, $filemode);
5494
}
5495
5496
// TODO: Where the following function has been copy/pased from? There is no information about author and license. Style, coding conventions...
5497
/**
5498
 * Parse info file format. (e.g: file.info).
5499
 *
5500
 * Files should use an ini-like format to specify values.
5501
 * White-space generally doesn't matter, except inside values.
5502
 * e.g.
5503
 *
5504
 * @verbatim
5505
 *   key = value
5506
 *   key = "value"
5507
 *   key = 'value'
5508
 *   key = "multi-line
5509
 *
5510
 *   value"
5511
 *   key = 'multi-line
5512
 *
5513
 *   value'
5514
 *   key
5515
 *   =
5516
 *   'value'
5517
 * @endverbatim
5518
 *
5519
 * Arrays are created using a GET-like syntax:
5520
 *
5521
 * @verbatim
5522
 *   key[] = "numeric array"
5523
 *   key[index] = "associative array"
5524
 *   key[index][] = "nested numeric array"
5525
 *   key[index][index] = "nested associative array"
5526
 * @endverbatim
5527
 *
5528
 * PHP constants are substituted in, but only when used as the entire value:
5529
 *
5530
 * Comments should start with a semi-colon at the beginning of a line.
5531
 *
5532
 * This function is NOT for placing arbitrary module-specific settings. Use
5533
 * variable_get() and variable_set() for that.
5534
 *
5535
 * Information stored in the module.info file:
5536
 * - name: The real name of the module for display purposes.
5537
 * - description: A brief description of the module.
5538
 * - dependencies: An array of shortnames of other modules this module depends on.
5539
 * - package: The name of the package of modules this module belongs to.
5540
 *
5541
 * Example of .info file:
5542
 * <code>
5543
 * @verbatim
5544
 *   name = Forum
5545
 *   description = Enables threaded discussions about general topics.
5546
 *   dependencies[] = taxonomy
5547
 *   dependencies[] = comment
5548
 *   package = Core - optional
5549
 *   version = VERSION
5550
 * @endverbatim
5551
 * </code>
5552
 *
5553
 * @param string $filename
5554
 *                         The file we are parsing. Accepts file with relative or absolute path.
5555
 *
5556
 * @return
5557
 *   The info array
5558
 */
5559
function api_parse_info_file($filename)
5560
{
5561
    $info = [];
5562
5563
    if (!file_exists($filename)) {
5564
        return $info;
5565
    }
5566
5567
    $data = file_get_contents($filename);
5568
    if (preg_match_all('
5569
        @^\s*                           # Start at the beginning of a line, ignoring leading whitespace
5570
        ((?:
5571
          [^=;\[\]]|                    # Key names cannot contain equal signs, semi-colons or square brackets,
5572
          \[[^\[\]]*\]                  # unless they are balanced and not nested
5573
        )+?)
5574
        \s*=\s*                         # Key/value pairs are separated by equal signs (ignoring white-space)
5575
        (?:
5576
          ("(?:[^"]|(?<=\\\\)")*")|     # Double-quoted string, which may contain slash-escaped quotes/slashes
5577
          (\'(?:[^\']|(?<=\\\\)\')*\')| # Single-quoted string, which may contain slash-escaped quotes/slashes
5578
          ([^\r\n]*?)                   # Non-quoted string
5579
        )\s*$                           # Stop at the next end of a line, ignoring trailing whitespace
5580
        @msx', $data, $matches, PREG_SET_ORDER)) {
5581
        $key = $value1 = $value2 = $value3 = '';
5582
        foreach ($matches as $match) {
5583
            // Fetch the key and value string.
5584
            $i = 0;
5585
            foreach (['key', 'value1', 'value2', 'value3'] as $var) {
5586
                $$var = isset($match[++$i]) ? $match[$i] : '';
5587
            }
5588
            $value = stripslashes(substr($value1, 1, -1)).stripslashes(substr($value2, 1, -1)).$value3;
5589
5590
            // Parse array syntax.
5591
            $keys = preg_split('/\]?\[/', rtrim($key, ']'));
5592
            $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

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

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

8789
        fclose(/** @scrutinizer ignore-type */ $fp);
Loading history...
8790
    }
8791
8792
    return $isCreated;
8793
}
8794
8795
/**
8796
 * Sends an email
8797
 * Sender name and email can be specified, if not specified
8798
 * name and email of the platform admin are used.
8799
 *
8800
 * @param string    name of recipient
8801
 * @param string    email of recipient
8802
 * @param string    email subject
8803
 * @param string    email body
8804
 * @param string    sender name
8805
 * @param string    sender e-mail
8806
 * @param array     extra headers in form $headers = array($name => $value) to allow parsing
8807
 * @param array     data file (path and filename)
8808
 * @param bool      True for attaching a embedded file inside content html (optional)
8809
 * @param array     Additional parameters
8810
 *
8811
 * @return bool true if mail was sent
8812
 */
8813
function api_mail_html(
8814
    $recipientName,
8815
    $recipientEmail,
8816
    $subject,
8817
    $body,
8818
    $senderName = '',
8819
    $senderEmail = '',
8820
    $extra_headers = [],
8821
    $data_file = [],
8822
    $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

8822
    /** @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...
8823
    $additionalParameters = []
8824
) {
8825
    if (!api_valid_email($recipientEmail)) {
8826
        return false;
8827
    }
8828
8829
    // Default values
8830
    $notification = new Notification();
8831
    $defaultEmail = $notification->getDefaultPlatformSenderEmail();
8832
    $defaultName = $notification->getDefaultPlatformSenderName();
8833
8834
    // If the parameter is set don't use the admin.
8835
    $senderName = !empty($senderName) ? $senderName : $defaultName;
8836
    $senderEmail = !empty($senderEmail) ? $senderEmail : $defaultEmail;
8837
8838
    // Reply to first
8839
    $replyToName = '';
8840
    $replyToEmail = '';
8841
    if (isset($extra_headers['reply_to'])) {
8842
        $replyToEmail = $extra_headers['reply_to']['mail'];
8843
        $replyToName = $extra_headers['reply_to']['name'];
8844
    }
8845
8846
    //If the SMTP configuration only accept one sender
8847
    /*if (isset($platform_email['SMTP_UNIQUE_SENDER']) && $platform_email['SMTP_UNIQUE_SENDER']) {
8848
        $senderName = $platform_email['SMTP_FROM_NAME'];
8849
        $senderEmail = $platform_email['SMTP_FROM_EMAIL'];
8850
        $valid = PHPMailer::validateAddress($senderEmail);
8851
        if ($valid) {
8852
            //force-set Sender to $senderEmail, otherwise SetFrom only does it if it is currently empty
8853
            $mail->Sender = $senderEmail;
8854
        }
8855
    }*/
8856
8857
    /*$mail->SetFrom($senderEmail, $senderName);
8858
    $mail->Subject = $subject;
8859
    $mail->AltBody = strip_tags(
8860
        str_replace('<br />', "\n", api_html_entity_decode($message))
8861
    );*/
8862
8863
    /*if (is_array($extra_headers) && count($extra_headers) > 0) {
8864
        foreach ($extra_headers as $key => $value) {
8865
            switch (strtolower($key)) {
8866
                case 'encoding':
8867
                case 'content-transfer-encoding':
8868
                    $mail->Encoding = $value;
8869
                    break;
8870
                case 'charset':
8871
                    $mail->Charset = $value;
8872
                    break;
8873
                case 'contenttype':
8874
                case 'content-type':
8875
                    $mail->ContentType = $value;
8876
                    break;
8877
                default:
8878
                    $mail->AddCustomHeader($key.':'.$value);
8879
                    break;
8880
            }
8881
        }
8882
    } else {
8883
        if (!empty($extra_headers)) {
8884
            $mail->AddCustomHeader($extra_headers);
8885
        }
8886
    }*/
8887
8888
    // WordWrap the html body (phpMailer only fixes AltBody) FS#2988
8889
    //$mail->Body = $mail->WrapText($mail->Body, $mail->WordWrap);
8890
    try {
8891
        $message = new \Swift_Message($subject);
8892
8893
        $list = api_get_configuration_value('send_all_emails_to');
8894
        if (!empty($list) && isset($list['emails'])) {
8895
            foreach ($list['emails'] as $email) {
8896
                $message->addCc($email);
8897
            }
8898
        }
8899
8900
        // Attachment
8901
        if (!empty($data_file)) {
8902
            foreach ($data_file as $file_attach) {
8903
                if (!empty($file_attach['path']) && !empty($file_attach['filename'])) {
8904
                    //$message->attach(Swift_Attachment::fromPath($file_attach['path'], $file_attach['filename']);
8905
                    $message->attach(
8906
                        Swift_Attachment::fromPath($file_attach['path'])->setFilename($file_attach['filename'])
8907
                    );
8908
                }
8909
            }
8910
        }
8911
8912
        $noReply = api_get_setting('noreply_email_address');
8913
        $automaticEmailText = '';
8914
        if (!empty($noReply)) {
8915
            $automaticEmailText = '<br />'.get_lang('This is an automatic email message. Please do not reply to it.');
8916
        }
8917
8918
        $params = [
8919
            'content' => '',
8920
            'mail_header_style' => api_get_configuration_value('mail_header_style'),
8921
            'mail_content_style' => api_get_configuration_value('mail_content_style'),
8922
            'link' => $additionalParameters['link'] ?? '',
8923
            'automatic_email_text' => $automaticEmailText,
8924
        ];
8925
8926
        $paramsHtml = $paramsText = $params;
8927
8928
        $paramsHtml['content'] = $body;
8929
        $paramsText['content'] = str_replace('<br />', "\n", api_html_entity_decode($body));
8930
8931
        if (!empty($senderEmail)) {
8932
            $message->setFrom([$senderEmail => $senderName]);
8933
        }
8934
8935
        if (!empty($recipientEmail)) {
8936
            $message->setTo([$recipientEmail => $recipientName]);
8937
        }
8938
8939
        if (!empty($replyToEmail)) {
8940
            $message->setReplyTo([$replyToEmail => $replyToName]);
8941
        }
8942
8943
        $message
8944
            ->setBody(
8945
                Container::getTwig()->render(
8946
                    'ChamiloThemeBundle:Mailer:Default/default.html.twig',
8947
                    $paramsHtml
8948
                ),
8949
                'text/html'
8950
            )
8951
            ->addPart(
8952
                Container::getTwig()->render(
8953
                    'ChamiloThemeBundle:Mailer:Default/default.text.twig',
8954
                    $paramsText
8955
                ),
8956
                'text/plain'
8957
            )
8958
            //->setEncoder(\Swift_Encoding::get8BitEncoding())
8959
        ;
8960
8961
        $type = $message->getHeaders()->get('Content-Type');
8962
        $type->setCharset('utf-8');
8963
        Container::getMailer()->send($message);
8964
8965
        return true;
8966
    } catch (Exception $e) {
8967
        error_log($e->getMessage());
8968
    }
8969
8970
    if (!empty($additionalParameters)) {
8971
        $plugin = new AppPlugin();
8972
        $smsPlugin = $plugin->getSMSPluginLibrary();
8973
        if ($smsPlugin) {
0 ignored issues
show
introduced by
$smsPlugin is of type SmsPluginLibraryInterface, thus it always evaluated to true.
Loading history...
8974
            $smsPlugin->send($additionalParameters);
8975
        }
8976
    }
8977
8978
    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...
8979
}
8980
8981
/**
8982
 * @param string $tool       Possible values: GroupManager::GROUP_TOOL_*
8983
 * @param bool   $showHeader
8984
 */
8985
function api_protect_course_group($tool, $showHeader = true)
8986
{
8987
    $groupId = api_get_group_id();
8988
    if (!empty($groupId)) {
8989
        if (api_is_platform_admin()) {
8990
            return true;
8991
        }
8992
8993
        if (api_is_allowed_to_edit(false, true, true)) {
8994
            return true;
8995
        }
8996
8997
        $userId = api_get_user_id();
8998
        $sessionId = api_get_session_id();
8999
        if (!empty($sessionId)) {
9000
            if (api_is_coach($sessionId, api_get_course_int_id())) {
9001
                return true;
9002
            }
9003
9004
            if (api_is_drh()) {
9005
                if (SessionManager::isUserSubscribedAsHRM($sessionId, $userId)) {
9006
                    return true;
9007
                }
9008
            }
9009
        }
9010
9011
        $groupInfo = GroupManager::get_group_properties($groupId);
9012
9013
        // Group doesn't exists
9014
        if (empty($groupInfo)) {
9015
            api_not_allowed($showHeader);
9016
        }
9017
9018
        // Check group access
9019
        $allow = GroupManager::user_has_access(
9020
            $userId,
9021
            $groupInfo['iid'],
9022
            $tool
9023
        );
9024
9025
        if (!$allow) {
9026
            api_not_allowed($showHeader);
9027
        }
9028
    }
9029
}
9030
9031
/**
9032
 * Check if a date is in a date range.
9033
 *
9034
 * @param datetime $startDate
9035
 * @param datetime $endDate
9036
 * @param datetime $currentDate
9037
 *
9038
 * @return bool true if date is in rage, false otherwise
9039
 */
9040
function api_is_date_in_date_range($startDate, $endDate, $currentDate = null)
9041
{
9042
    $startDate = strtotime(api_get_local_time($startDate));
9043
    $endDate = strtotime(api_get_local_time($endDate));
9044
    $currentDate = strtotime(api_get_local_time($currentDate));
9045
9046
    if ($currentDate >= $startDate && $currentDate <= $endDate) {
9047
        return true;
9048
    }
9049
9050
    return false;
9051
}
9052
9053
/**
9054
 * Eliminate the duplicates of a multidimensional array by sending the key.
9055
 *
9056
 * @param array $array multidimensional array
9057
 * @param int   $key   key to find to compare
9058
 *
9059
 * @return array
9060
 */
9061
function api_unique_multidim_array($array, $key)
9062
{
9063
    $temp_array = [];
9064
    $i = 0;
9065
    $key_array = [];
9066
9067
    foreach ($array as $val) {
9068
        if (!in_array($val[$key], $key_array)) {
9069
            $key_array[$i] = $val[$key];
9070
            $temp_array[$i] = $val;
9071
        }
9072
        $i++;
9073
    }
9074
9075
    return $temp_array;
9076
}
9077
9078
/**
9079
 * Limit the access to Session Admins when the limit_session_admin_role
9080
 * configuration variable is set to true.
9081
 */
9082
function api_protect_limit_for_session_admin()
9083
{
9084
    $limitAdmin = api_get_setting('limit_session_admin_role');
9085
    if (api_is_session_admin() && $limitAdmin === 'true') {
9086
        api_not_allowed(true);
9087
    }
9088
}
9089
9090
/**
9091
 * Limits that a session admin has access to list users.
9092
 * When limit_session_admin_list_users configuration variable is set to true.
9093
 */
9094
function api_protect_session_admin_list_users()
9095
{
9096
    $limitAdmin = api_get_configuration_value('limit_session_admin_list_users');
9097
9098
    if (api_is_session_admin() && true === $limitAdmin) {
9099
        api_not_allowed(true);
9100
    }
9101
}
9102
9103
/**
9104
 * @return bool
9105
 */
9106
function api_is_student_view_active()
9107
{
9108
    $studentView = Session::read('studentview');
9109
9110
    return $studentView === 'studentview';
9111
}
9112
9113
/**
9114
 * Adds a file inside the upload/$type/id.
9115
 *
9116
 * @param string $type
9117
 * @param array  $file
9118
 * @param int    $itemId
9119
 * @param string $cropParameters
9120
 *
9121
 * @deprecated use Resources
9122
 *
9123
 * @return array|bool
9124
 */
9125
function api_upload_file($type, $file, $itemId, $cropParameters = '')
9126
{
9127
    $upload = process_uploaded_file($file);
9128
    if ($upload) {
9129
        $name = api_replace_dangerous_char($file['name']);
9130
9131
        // No "dangerous" files
9132
        $name = disable_dangerous_file($name);
9133
9134
        $pathId = '/'.substr((string) $itemId, 0, 1).'/'.$itemId.'/';
9135
        $path = api_get_path(SYS_UPLOAD_PATH).$type.$pathId;
9136
9137
        if (!is_dir($path)) {
9138
            mkdir($path, api_get_permissions_for_new_directories(), true);
9139
        }
9140
9141
        $pathToSave = $path.$name;
9142
        $result = moveUploadedFile($file, $pathToSave);
9143
9144
        if ($result) {
9145
            if (!empty($cropParameters)) {
9146
                $image = new Image($pathToSave);
9147
                $image->crop($cropParameters);
9148
            }
9149
9150
            return ['path_to_save' => $pathId.$name];
9151
        }
9152
9153
        return false;
9154
    }
9155
}
9156
9157
/**
9158
 * @param string $type
9159
 * @param int    $itemId
9160
 * @param string $file
9161
 *
9162
 * @return bool
9163
 */
9164
function api_get_uploaded_web_url($type, $itemId, $file)
9165
{
9166
    return api_get_uploaded_file($type, $itemId, $file, true);
9167
}
9168
9169
/**
9170
 * @param string $type
9171
 * @param int    $itemId
9172
 * @param string $file
9173
 * @param bool   $getUrl
9174
 *
9175
 * @return bool
9176
 */
9177
function api_get_uploaded_file($type, $itemId, $file, $getUrl = false)
9178
{
9179
    $itemId = (int) $itemId;
9180
    $pathId = '/'.substr((string) $itemId, 0, 1).'/'.$itemId.'/';
9181
    $path = api_get_path(SYS_UPLOAD_PATH).$type.$pathId;
9182
    $file = basename($file);
9183
    $file = $path.'/'.$file;
9184
    if (Security::check_abs_path($file, $path) && is_file($file) && file_exists($file)) {
9185
        if ($getUrl) {
9186
            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...
9187
        }
9188
9189
        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...
9190
    }
9191
9192
    return false;
9193
}
9194
9195
/**
9196
 * @param string $type
9197
 * @param int    $itemId
9198
 * @param string $file
9199
 * @param string $title
9200
 */
9201
function api_download_uploaded_file($type, $itemId, $file, $title = '')
9202
{
9203
    $file = api_get_uploaded_file($type, $itemId, $file);
9204
    if ($file) {
9205
        if (Security::check_abs_path($file, api_get_path(SYS_UPLOAD_PATH).$type)) {
9206
            DocumentManager::file_send_for_download($file, true, $title);
9207
            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...
9208
        }
9209
    }
9210
    api_not_allowed(true);
9211
}
9212
9213
/**
9214
 * @param string $type
9215
 * @param string $file
9216
 */
9217
function api_remove_uploaded_file($type, $file)
9218
{
9219
    $typePath = api_get_path(SYS_UPLOAD_PATH).$type;
9220
    $path = $typePath.'/'.$file;
9221
    if (Security::check_abs_path($path, $typePath) && file_exists($path) && is_file($path)) {
9222
        unlink($path);
9223
    }
9224
}
9225
9226
/**
9227
 * @param string $type
9228
 * @param int    $itemId
9229
 * @param string $file
9230
 *
9231
 * @return bool
9232
 */
9233
function api_remove_uploaded_file_by_id($type, $itemId, $file)
9234
{
9235
    $file = api_get_uploaded_file($type, $itemId, $file, false);
9236
    $typePath = api_get_path(SYS_UPLOAD_PATH).$type;
9237
    if (Security::check_abs_path($file, $typePath) && file_exists($file) && is_file($file)) {
9238
        unlink($file);
9239
9240
        return true;
9241
    }
9242
9243
    return false;
9244
}
9245
9246
/**
9247
 * Converts string value to float value.
9248
 *
9249
 * 3.141516 => 3.141516
9250
 * 3,141516 => 3.141516
9251
 *
9252
 * @todo WIP
9253
 *
9254
 * @param string $number
9255
 *
9256
 * @return float
9257
 */
9258
function api_float_val($number)
9259
{
9260
    $number = (float) str_replace(',', '.', trim($number));
9261
9262
    return $number;
9263
}
9264
9265
/**
9266
 * Converts float values
9267
 * Example if $decimals = 2.
9268
 *
9269
 * 3.141516 => 3.14
9270
 * 3,141516 => 3,14
9271
 *
9272
 * @param string $number            number in iso code
9273
 * @param int    $decimals
9274
 * @param string $decimalSeparator
9275
 * @param string $thousandSeparator
9276
 *
9277
 * @return bool|string
9278
 */
9279
function api_number_format($number, $decimals = 0, $decimalSeparator = '.', $thousandSeparator = ',')
9280
{
9281
    $number = api_float_val($number);
9282
9283
    return number_format($number, $decimals, $decimalSeparator, $thousandSeparator);
9284
}
9285
9286
/**
9287
 * Set location url with a exit break by default.
9288
 *
9289
 * @param $url
9290
 * @param bool $exit
9291
 */
9292
function location($url, $exit = true)
9293
{
9294
    header('Location: '.$url);
9295
9296
    if ($exit) {
9297
        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...
9298
    }
9299
}
9300
9301
/**
9302
 * @return string
9303
 */
9304
function api_get_web_url()
9305
{
9306
    if (api_get_setting('server_type') === 'test') {
9307
        return api_get_path(WEB_PATH).'web/app_dev.php/';
9308
    } else {
9309
        return api_get_path(WEB_PATH).'web/';
9310
    }
9311
}
9312
9313
/**
9314
 * @param string $from
9315
 * @param string $to
9316
 *
9317
 * @return string
9318
 */
9319
function api_get_relative_path($from, $to)
9320
{
9321
    // some compatibility fixes for Windows paths
9322
    $from = is_dir($from) ? rtrim($from, '\/').'/' : $from;
9323
    $to = is_dir($to) ? rtrim($to, '\/').'/' : $to;
9324
    $from = str_replace('\\', '/', $from);
9325
    $to = str_replace('\\', '/', $to);
9326
9327
    $from = explode('/', $from);
9328
    $to = explode('/', $to);
9329
    $relPath = $to;
9330
9331
    foreach ($from as $depth => $dir) {
9332
        // find first non-matching dir
9333
        if ($dir === $to[$depth]) {
9334
            // ignore this directory
9335
            array_shift($relPath);
9336
        } else {
9337
            // get number of remaining dirs to $from
9338
            $remaining = count($from) - $depth;
9339
            if ($remaining > 1) {
9340
                // add traversals up to first matching dir
9341
                $padLength = (count($relPath) + $remaining - 1) * -1;
9342
                $relPath = array_pad($relPath, $padLength, '..');
9343
                break;
9344
            } else {
9345
                $relPath[0] = './'.$relPath[0];
9346
            }
9347
        }
9348
    }
9349
9350
    return implode('/', $relPath);
9351
}
9352
9353
/**
9354
 * Unserialize content using Brummann\Polyfill\Unserialize.
9355
 *
9356
 * @param string $type
9357
 * @param string $serialized
9358
 * @param bool   $ignoreErrors. Optional.
9359
 *
9360
 * @return mixed
9361
 */
9362
function api_unserialize_content($type, $serialized, $ignoreErrors = false)
9363
{
9364
    switch ($type) {
9365
        case 'career':
9366
        case 'sequence_graph':
9367
            $allowedClasses = [Graph::class, VerticesMap::class, Vertices::class, Edges::class];
9368
            break;
9369
        case 'lp':
9370
            $allowedClasses = [
9371
                learnpath::class,
9372
                learnpathItem::class,
9373
                aicc::class,
9374
                aiccBlock::class,
9375
                aiccItem::class,
9376
                aiccObjective::class,
9377
                aiccResource::class,
9378
                scorm::class,
9379
                scormItem::class,
9380
                scormMetadata::class,
9381
                scormOrganization::class,
9382
                scormResource::class,
9383
                Link::class,
9384
                LpItem::class,
9385
            ];
9386
            break;
9387
        case 'course':
9388
            $allowedClasses = [
9389
                Course::class,
9390
                Announcement::class,
9391
                Attendance::class,
9392
                CalendarEvent::class,
9393
                CourseCopyLearnpath::class,
9394
                CourseCopyTestCategory::class,
9395
                CourseDescription::class,
9396
                CourseSession::class,
9397
                Document::class,
9398
                Forum::class,
9399
                ForumCategory::class,
9400
                ForumPost::class,
9401
                ForumTopic::class,
9402
                Glossary::class,
9403
                GradeBookBackup::class,
9404
                Link::class,
9405
                LinkCategory::class,
9406
                Quiz::class,
9407
                QuizQuestion::class,
9408
                QuizQuestionOption::class,
9409
                ScormDocument::class,
9410
                Survey::class,
9411
                SurveyInvitation::class,
9412
                SurveyQuestion::class,
9413
                Thematic::class,
9414
                ToolIntro::class,
9415
                Wiki::class,
9416
                Work::class,
9417
                stdClass::class,
9418
            ];
9419
            break;
9420
        case 'not_allowed_classes':
9421
        default:
9422
            $allowedClasses = false;
9423
    }
9424
9425
    if ($ignoreErrors) {
9426
        return @Unserialize::unserialize(
9427
            $serialized,
9428
            ['allowed_classes' => $allowedClasses]
9429
        );
9430
    }
9431
9432
    return Unserialize::unserialize(
9433
        $serialized,
9434
        ['allowed_classes' => $allowedClasses]
9435
    );
9436
}
9437
9438
/**
9439
 * @param string $template
9440
 *
9441
 * @return string
9442
 */
9443
function api_find_template($template)
9444
{
9445
    return Template::findTemplateFilePath($template);
9446
}
9447
9448
/**
9449
 * @return array
9450
 */
9451
function api_get_language_list_for_flag()
9452
{
9453
    $table = Database::get_main_table(TABLE_MAIN_LANGUAGE);
9454
    $sql = "SELECT english_name, isocode FROM $table 
9455
            ORDER BY original_name ASC";
9456
    static $languages = [];
9457
    if (empty($languages)) {
9458
        $result = Database::query($sql);
9459
        while ($row = Database::fetch_array($result)) {
9460
            $languages[$row['english_name']] = $row['isocode'];
9461
        }
9462
        $languages['english'] = 'gb';
9463
    }
9464
9465
    return $languages;
9466
}
9467
9468
/**
9469
 * @param string $name
9470
 *
9471
 * @return \ZipStream\ZipStream
9472
 */
9473
function api_create_zip($name)
9474
{
9475
    $zipStreamOptions = new \ZipStream\Option\Archive();
9476
    $zipStreamOptions->setSendHttpHeaders(true);
9477
    $zipStreamOptions->setContentDisposition('attachment');
9478
    $zipStreamOptions->setContentType('application/x-zip');
9479
9480
    $zip = new \ZipStream\ZipStream($name, $zipStreamOptions);
9481
9482
    return $zip;
9483
}
9484
9485
/**
9486
 * @return string
9487
 */
9488
function api_get_language_translate_html()
9489
{
9490
    $translate = api_get_configuration_value('translate_html');
9491
9492
    if (!$translate) {
9493
        return '';
9494
    }
9495
9496
    $languageList = api_get_languages();
9497
    $hideAll = '';
9498
    foreach ($languageList['all'] as $language) {
9499
        $hideAll .= '
9500
        $("span:lang('.$language['isocode'].')").filter(
9501
            function(e, val) {
9502
                // Only find the spans if they have set the lang                
9503
                if ($(this).attr("lang") == null) {                
9504
                    return false;
9505
                }
9506
                
9507
                // Ignore ckeditor classes
9508
                return !this.className.match(/cke(.*)/);
9509
        }).hide();'."\n";
9510
    }
9511
9512
    $userInfo = api_get_user_info();
9513
    $languageId = api_get_language_id($userInfo['language']);
9514
    $languageInfo = api_get_language_info($languageId);
9515
    $isoCode = 'en';
9516
9517
    if (!empty($languageInfo)) {
9518
        $isoCode = $languageInfo['isocode'];
9519
    }
9520
9521
    return '
9522
            $(function() {
9523
                '.$hideAll.'                 
9524
                var defaultLanguageFromUser = "'.$isoCode.'";   
9525
                                             
9526
                $("span:lang('.$isoCode.')").filter(
9527
                    function() {
9528
                        // Ignore ckeditor classes
9529
                        return !this.className.match(/cke(.*)/);
9530
                }).show();
9531
                
9532
                var defaultLanguage = "";
9533
                var langFromUserFound = false;
9534
                
9535
                $(this).find("span").filter(
9536
                    function() {
9537
                        // Ignore ckeditor classes
9538
                        return !this.className.match(/cke(.*)/);
9539
                }).each(function() {
9540
                    defaultLanguage = $(this).attr("lang");                            
9541
                    if (defaultLanguage) {
9542
                        $(this).before().next("br").remove();                
9543
                        if (defaultLanguageFromUser == defaultLanguage) {
9544
                            langFromUserFound = true;
9545
                        }
9546
                    }
9547
                });
9548
                
9549
                // Show default language
9550
                if (langFromUserFound == false && defaultLanguage) {
9551
                    $("span:lang("+defaultLanguage+")").filter(
9552
                    function() {
9553
                            // Ignore ckeditor classes
9554
                            return !this.className.match(/cke(.*)/);
9555
                    }).show();
9556
                }
9557
            });
9558
    ';
9559
}
9560