Completed
Pull Request — master (#2349)
by Julito
31:02 queued 07:14
created

api_get_plugin_setting()   B

Complexity

Conditions 4
Paths 2

Size

Total Lines 37
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

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

1084
function api_protect_course_script($print_headers = false, $allow_session_admins = false, /** @scrutinizer ignore-unused */ $allow_drh = 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...
1085
{
1086
    $is_allowed_in_course = api_is_allowed_in_course();
1087
1088
    $is_visible = false;
1089
    $course_info = api_get_course_info();
1090
1091
    if (empty($course_info)) {
1092
        api_not_allowed($print_headers);
1093
        return false;
1094
    }
1095
1096
    if (api_is_drh()) {
1097
        return true;
1098
    }
1099
1100
    // Session admin has access to course
1101
    $sessionAccess = api_get_configuration_value('session_admins_access_all_content');
1102
    if ($sessionAccess) {
1103
        $allow_session_admins = true;
1104
    }
1105
1106
    if (api_is_platform_admin($allow_session_admins)) {
1107
        return true;
1108
    }
1109
1110
    if (isset($course_info) && isset($course_info['visibility'])) {
1111
        switch ($course_info['visibility']) {
1112
            default:
1113
            case COURSE_VISIBILITY_CLOSED:
1114
                // Completely closed: the course is only accessible to the teachers. - 0
1115
                if (api_get_user_id() && !api_is_anonymous() && $is_allowed_in_course) {
1116
                    $is_visible = true;
1117
                }
1118
                break;
1119
            case COURSE_VISIBILITY_REGISTERED:
1120
                // Private - access authorized to course members only - 1
1121
                if (api_get_user_id() && !api_is_anonymous() && $is_allowed_in_course) {
1122
                    $is_visible = true;
1123
                }
1124
                break;
1125
            case COURSE_VISIBILITY_OPEN_PLATFORM:
1126
                // Open - access allowed for users registered on the platform - 2
1127
                if (api_get_user_id() && !api_is_anonymous() && $is_allowed_in_course) {
1128
                    $is_visible = true;
1129
                }
1130
                break;
1131
            case COURSE_VISIBILITY_OPEN_WORLD:
1132
                //Open - access allowed for the whole world - 3
1133
                $is_visible = true;
1134
                break;
1135
            case COURSE_VISIBILITY_HIDDEN:
1136
                //Completely closed: the course is only accessible to the teachers. - 0
1137
                if (api_is_platform_admin()) {
1138
                    $is_visible = true;
1139
                }
1140
                break;
1141
        }
1142
1143
        //If password is set and user is not registered to the course then the course is not visible
1144
        if ($is_allowed_in_course == 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...
1145
            isset($course_info['registration_code']) &&
1146
            !empty($course_info['registration_code'])
1147
        ) {
1148
            $is_visible = false;
1149
        }
1150
    }
1151
1152
    // Check session visibility
1153
    $session_id = api_get_session_id();
1154
1155
    if (!empty($session_id)) {
1156
        //$is_allowed_in_course was set in local.inc.php
1157
        if (!$is_allowed_in_course) {
1158
            $is_visible = false;
1159
        }
1160
    }
1161
1162
    if (!$is_visible) {
1163
        api_not_allowed($print_headers);
1164
        return false;
1165
    }
1166
    return true;
1167
}
1168
1169
/**
1170
 * Function used to protect an admin script.
1171
 *
1172
 * The function blocks access when the user has no platform admin rights
1173
 * with an error message printed on default output
1174
 * @param bool Whether to allow session admins as well
1175
 * @param bool Whether to allow HR directors as well
1176
 * @param string An optional message (already passed through get_lang)
1177
 * @return bool True if user is allowed, false otherwise.
1178
 * The function also outputs an error message in case not allowed
1179
 * @author Roan Embrechts (original author)
1180
 */
1181
function api_protect_admin_script($allow_sessions_admins = false, $allow_drh = false, $message = null)
1182
{
1183
    if (!api_is_platform_admin($allow_sessions_admins, $allow_drh)) {
1184
        api_not_allowed(true, $message);
1185
        return false;
1186
    }
1187
    return true;
1188
}
1189
1190
/**
1191
 * Function used to protect a teacher script.
1192
 * The function blocks access when the user has no teacher rights.
1193
 *
1194
 * @author Yoselyn Castillo
1195
 */
1196
function api_protect_teacher_script($allow_sessions_admins = false)
0 ignored issues
show
Unused Code introduced by
The parameter $allow_sessions_admins 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

1196
function api_protect_teacher_script(/** @scrutinizer ignore-unused */ $allow_sessions_admins = 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...
1197
{
1198
    if (!api_is_allowed_to_edit()) {
1199
        api_not_allowed(true);
1200
        return false;
1201
    }
1202
    return true;
1203
}
1204
1205
/**
1206
 * Function used to prevent anonymous users from accessing a script.
1207
 * @param bool|true $printHeaders
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
        return false;
1218
    }
1219
1220
    return true;
1221
}
1222
1223
/**
1224
 * @return array with the navigator name and version
1225
 */
1226
function api_get_navigator()
1227
{
1228
    $navigator = 'Unknown';
1229
    $version = 0;
1230
1231
    if (!isset($_SERVER['HTTP_USER_AGENT'])) {
1232
        return ['name' => 'Unknown', 'version' => '0.0.0'];
1233
    }
1234
1235
    if (strpos($_SERVER['HTTP_USER_AGENT'], 'Opera') !== false) {
1236
        $navigator = 'Opera';
1237
        list(, $version) = explode('Opera', $_SERVER['HTTP_USER_AGENT']);
1238
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== false) {
1239
        $navigator = 'Internet Explorer';
1240
        list(, $version) = explode('MSIE', $_SERVER['HTTP_USER_AGENT']);
1241
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Chrome') !== false) {
1242
        $navigator = 'Chrome';
1243
        list(, $version) = explode('Chrome', $_SERVER['HTTP_USER_AGENT']);
1244
    } elseif (stripos($_SERVER['HTTP_USER_AGENT'], 'safari') !== false) {
1245
        $navigator = 'Safari';
1246
        list(, $version) = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1247
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Gecko') !== false) {
1248
        $navigator = 'Mozilla';
1249
        list(, $version) = explode('; rv:', $_SERVER['HTTP_USER_AGENT']);
1250
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Netscape') !== false) {
1251
        $navigator = 'Netscape';
1252
        list(, $version) = explode('Netscape', $_SERVER['HTTP_USER_AGENT']);
1253
    } elseif (strpos($_SERVER['HTTP_USER_AGENT'], 'Konqueror') !== false) {
1254
        $navigator = 'Konqueror';
1255
        list(, $version) = explode('Konqueror', $_SERVER['HTTP_USER_AGENT']);
1256
    } elseif (stripos($_SERVER['HTTP_USER_AGENT'], 'applewebkit') !== false) {
1257
        $navigator = 'AppleWebKit';
1258
        list(, $version) = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1259
    }
1260
    $version = str_replace('/', '', $version);
1261
    if (strpos($version, '.') === false) {
1262
        $version = number_format(doubleval($version), 1);
1263
    }
1264
    $return = ['name' => $navigator, 'version' => $version];
1265
    return $return;
1266
}
1267
1268
/**
1269
 * @return True if user self registration is allowed, false otherwise.
1270
 */
1271
function api_is_self_registration_allowed()
1272
{
1273
    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...
1274
}
1275
1276
/**
1277
 * This function returns the id of the user which is stored in the $_user array.
1278
 *
1279
 * example: The function can be used to check if a user is logged in
1280
 *          if (api_get_user_id())
1281
 * @return int the id of the current user, 0 if is empty
1282
 */
1283
function api_get_user_id()
1284
{
1285
    $userInfo = Session::read('_user');
1286
    if ($userInfo && isset($userInfo['user_id'])) {
1287
        return (int) $userInfo['user_id'];
1288
    }
1289
    return 0;
1290
}
1291
1292
/**
1293
 * Gets the list of courses a specific user is subscribed to
1294
 * @param int       User ID
1295
 * @param boolean   $fetch_session Whether to get session courses or not - NOT YET IMPLEMENTED
1296
 * @return array    Array of courses in the form [0]=>('code'=>xxx,'db'=>xxx,'dir'=>xxx,'status'=>d)
1297
 * @deprecated use CourseManager::get_courses_list_by_user_id()
1298
 */
1299
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

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

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

1533
                $apcVar = /** @scrutinizer ignore-type */ api_get_configuration_value('apc_prefix').'userinfo_'.$userFromSession['user_id'];
Loading history...
1534
                if (apcu_exists($apcVar)) {
1535
                    if ($updateCache) {
1536
                        apcu_store($apcVar, $userFromSession, 60);
1537
                    }
1538
                    $user = apcu_fetch($apcVar);
1539
                } else {
1540
                    $user = _api_format_user(
1541
                        $userFromSession,
1542
                        $showPassword,
1543
                        $loadAvatars
1544
                    );
1545
                    apcu_store($apcVar, $user, 60);
1546
                }
1547
            } else {
1548
                $user = _api_format_user(
1549
                    $userFromSession,
1550
                    $showPassword,
1551
                    $loadAvatars
1552
                );
1553
            }
1554
1555
            return $user;
1556
        }
1557
1558
        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...
1559
    }
1560
1561
    // Make sure user_id is safe
1562
    $user_id = intval($user_id);
1563
1564
    // Re-use user information if not stale and already stored in APCu
1565
    if ($cacheAvailable === true) {
1566
        $apcVar = api_get_configuration_value('apc_prefix').'userinfo_'.$user_id;
1567
        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...
1568
            $user = apcu_fetch($apcVar);
1569
1570
            return $user;
1571
        }
1572
    }
1573
1574
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1575
            WHERE id = $user_id";
1576
    $result = Database::query($sql);
1577
    if (Database::num_rows($result) > 0) {
1578
        $result_array = Database::fetch_array($result);
1579
        if ($checkIfUserOnline) {
1580
            $use_status_in_platform = user_is_online($user_id);
1581
            $result_array['user_is_online'] = $use_status_in_platform;
1582
            $user_online_in_chat = 0;
1583
1584
            if ($use_status_in_platform) {
1585
                $user_status = UserManager::get_extra_user_data_by_field(
1586
                    $user_id,
1587
                    'user_chat_status',
1588
                    false,
1589
                    true
1590
                );
1591
                if (@intval($user_status['user_chat_status']) == 1) {
1592
                    $user_online_in_chat = 1;
1593
                }
1594
            }
1595
            $result_array['user_is_online_in_chat'] = $user_online_in_chat;
1596
        }
1597
1598
        if ($loadExtraData) {
1599
            $fieldValue = new ExtraFieldValue('user');
1600
            $result_array['extra'] = $fieldValue->getAllValuesForAnItem(
1601
                $user_id,
1602
                $loadOnlyVisibleExtraData
1603
            );
1604
        }
1605
        $user = _api_format_user($result_array, $showPassword, $loadAvatars);
1606
    }
1607
1608
    if ($cacheAvailable === true) {
1609
        apcu_store($apcVar, $user, 60);
1610
    }
1611
1612
    return $user;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $user could also return false which is incompatible with the documented return type array. 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...
1613
}
1614
1615
/**
1616
 * @param int $userId
1617
 * @return User
1618
 */
1619
function api_get_user_entity($userId)
1620
{
1621
    $userId = (int) $userId;
1622
    /** @var \Chamilo\UserBundle\Repository\UserRepository $repo */
1623
    $repo = Database::getManager()->getRepository('ChamiloUserBundle:User');
1624
1625
    return $repo->find($userId);
1626
}
1627
1628
/**
1629
 * Finds all the information about a user from username instead of user id
1630
 * @param string $username
1631
 * @return array $user_info array user_id, lastname, firstname, username, email
1632
 * @author Yannick Warnier <[email protected]>
1633
 */
1634
function api_get_user_info_from_username($username = '')
1635
{
1636
    if (empty($username)) {
1637
        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...
1638
    }
1639
    $username = trim($username);
1640
1641
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1642
            WHERE username='".Database::escape_string($username)."'";
1643
    $result = Database::query($sql);
1644
    if (Database::num_rows($result) > 0) {
1645
        $result_array = Database::fetch_array($result);
1646
        return _api_format_user($result_array);
1647
    }
1648
    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...
1649
}
1650
1651
/**
1652
 * Get first user with an email
1653
 * @param string $email
1654
 * @return array|bool
1655
 */
1656
function api_get_user_info_from_email($email = '')
1657
{
1658
    if (empty($email)) {
1659
        return false;
1660
    }
1661
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1662
            WHERE email ='".Database::escape_string($email)."' LIMIT 1";
1663
    $result = Database::query($sql);
1664
    if (Database::num_rows($result) > 0) {
1665
        $result_array = Database::fetch_array($result);
1666
        return _api_format_user($result_array);
1667
    }
1668
1669
    return false;
1670
}
1671
1672
/**
1673
 * @return string
1674
 */
1675
function api_get_course_id()
1676
{
1677
    return Session::read('_cid', null);
1678
}
1679
1680
/**
1681
 * Returns the current course id (integer)
1682
 * @param   string  $code   Optional course code
1683
 * @return int
1684
 */
1685
function api_get_course_int_id($code = null)
1686
{
1687
    if (!empty($code)) {
1688
        $code = Database::escape_string($code);
1689
        $row = Database::select(
1690
            'id',
1691
            Database::get_main_table(TABLE_MAIN_COURSE),
1692
            ['where'=> ['code = ?' => [$code]]],
1693
            'first'
1694
        );
1695
1696
        if (is_array($row) && isset($row['id'])) {
1697
            return $row['id'];
1698
        } else {
1699
            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...
1700
        }
1701
    }
1702
    return Session::read('_real_cid', 0);
1703
}
1704
1705
/**
1706
 * Returns the current course directory
1707
 *
1708
 * This function relies on api_get_course_info()
1709
 * @param string    The course code - optional (takes it from session if not given)
1710
 * @return string   The directory where the course is located inside the Chamilo "courses" directory
1711
 * @author Yannick Warnier <[email protected]>
1712
 */
1713
function api_get_course_path($course_code = null)
1714
{
1715
    $info = !empty($course_code) ? api_get_course_info($course_code) : api_get_course_info();
1716
    return $info['path'];
1717
}
1718
1719
/**
1720
 * Gets a course setting from the current course_setting table. Try always using integer values.
1721
 * @param string    The name of the setting we want from the table
1722
 * @param string    Optional: course code
1723
 * @param string $setting_name
1724
 * @return mixed    The value of that setting in that table. Return -1 if not found.
1725
 */
1726
function api_get_course_setting($setting_name, $course_code = null)
1727
{
1728
    $course_info = api_get_course_info($course_code);
1729
    $table = Database::get_course_table(TABLE_COURSE_SETTING);
1730
    $setting_name = Database::escape_string($setting_name);
1731
    if (!empty($course_info['real_id']) && !empty($setting_name)) {
1732
        $sql = "SELECT value FROM $table
1733
                WHERE c_id = {$course_info['real_id']} AND variable = '$setting_name'";
1734
        $res = Database::query($sql);
1735
        if (Database::num_rows($res) > 0) {
1736
            $row = Database::fetch_array($res);
1737
            if ($setting_name === 'email_alert_manager_on_new_quiz') {
1738
                if (!is_null($row['value'])) {
1739
                    $result = explode(',', $row['value']);
1740
                    $row['value'] = $result;
1741
                }
1742
            }
1743
            return $row['value'];
1744
        }
1745
    }
1746
    return -1;
1747
}
1748
1749
/**
1750
 * Gets an anonymous user ID
1751
 *
1752
 * For some tools that need tracking, like the learnpath tool, it is necessary
1753
 * to have a usable user-id to enable some kind of tracking, even if not
1754
 * perfect. An anonymous ID is taken from the users table by looking for a
1755
 * status of "6" (anonymous).
1756
 * @return int  User ID of the anonymous user, or O if no anonymous user found
1757
 */
1758
function api_get_anonymous_id()
1759
{
1760
    // Find if another anon is connected now
1761
    $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
1762
    $tableU = Database::get_main_table(TABLE_MAIN_USER);
1763
    $ip = api_get_real_ip();
1764
    $max = api_get_configuration_value('max_anonymous_users');
1765
    if ($max >= 2) {
1766
        $sql = "SELECT * FROM $table as TEL 
1767
                JOIN $tableU as U
1768
                ON U.user_id = TEL.login_user_id
1769
                WHERE TEL.user_ip = '$ip'
1770
                    AND U.status = ".ANONYMOUS."
1771
                    AND U.user_id != 2 ";
1772
1773
        $result = Database::query($sql);
1774
        if (empty(Database::num_rows($result))) {
1775
            $login = uniqid('anon_');
1776
            $anonList = UserManager::get_user_list(['status' => ANONYMOUS], ['registration_date ASC']);
1777
            if (count($anonList) == $max) {
1778
                foreach ($anonList as $userToDelete) {
1779
                    UserManager::delete_user($userToDelete['user_id']);
1780
                    break;
1781
                }
1782
            }
1783
            $userId = UserManager::create_user(
1784
                $login,
1785
                'anon',
1786
                ANONYMOUS,
1787
                ' anonymous@localhost',
1788
                $login,
1789
                $login
1790
            );
1791
            return $userId;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $userId could also return false which is incompatible with the documented return type integer. Did you maybe forget to handle an error condition?

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

Loading history...
1792
        } else {
1793
            $row = Database::fetch_array($result, 'ASSOC');
1794
            return $row['user_id'];
1795
        }
1796
    }
1797
1798
    $table = Database::get_main_table(TABLE_MAIN_USER);
1799
    $sql = "SELECT user_id 
1800
            FROM $table 
1801
            WHERE status = ".ANONYMOUS." ";
1802
    $res = Database::query($sql);
1803
    if (Database::num_rows($res) > 0) {
1804
        $row = Database::fetch_array($res, 'ASSOC');
1805
        return $row['user_id'];
1806
    }
1807
1808
    // No anonymous user was found.
1809
    return 0;
1810
}
1811
1812
/**
1813
 * @param string $courseCode
1814
 * @param int $sessionId
1815
 * @param int $groupId
1816
 * @return string
1817
 */
1818
function api_get_cidreq_params($courseCode, $sessionId = 0, $groupId = 0)
1819
{
1820
    $courseCode = !empty($courseCode) ? htmlspecialchars($courseCode) : '';
1821
    $sessionId = !empty($sessionId) ? (int) $sessionId : 0;
1822
    $groupId = !empty($groupId) ? (int) $groupId : 0;
1823
1824
    $url = 'cidReq='.$courseCode;
1825
    $url .= '&id_session='.$sessionId;
1826
    $url .= '&gidReq='.$groupId;
1827
1828
    return $url;
1829
}
1830
1831
/**
1832
 * Returns the current course url part including session, group, and gradebook params
1833
 *
1834
 * @param bool $addSessionId
1835
 * @param bool $addGroupId
1836
 * @param string $origin
1837
 *
1838
 * @return  string  Course & session references to add to a URL
1839
 *
1840
 */
1841
function api_get_cidreq($addSessionId = true, $addGroupId = true, $origin = '')
1842
{
1843
    $courseCode = api_get_course_id();
1844
    $url = empty($courseCode) ? '' : 'cidReq='.htmlspecialchars($courseCode);
1845
    $origin = empty($origin) ? api_get_origin() : Security::remove_XSS($origin);
1846
1847
    if ($addSessionId) {
1848
        if (!empty($url)) {
1849
            $url .= api_get_session_id() == 0 ? '&id_session=0' : '&id_session='.api_get_session_id();
1850
        }
1851
    }
1852
1853
    if ($addGroupId) {
1854
        if (!empty($url)) {
1855
            $url .= api_get_group_id() == 0 ? '&gidReq=0' : '&gidReq='.api_get_group_id();
1856
        }
1857
    }
1858
1859
    if (!empty($url)) {
1860
        $url .= '&gradebook='.intval(api_is_in_gradebook());
1861
        $url .= '&origin='.$origin;
1862
    }
1863
1864
    return $url;
1865
}
1866
1867
/**
1868
 * Get if we visited a gradebook page
1869
 * @return bool
1870
 */
1871
function api_is_in_gradebook()
1872
{
1873
    return Session::read('in_gradebook', false);
1874
}
1875
1876
/**
1877
 * Set that we are in a page inside a gradebook
1878
 * @return bool
1879
 */
1880
function api_set_in_gradebook()
1881
{
1882
    Session::write('in_gradebook', true);
1883
}
1884
1885
/**
1886
 * Remove gradebook session
1887
 */
1888
function api_remove_in_gradebook()
1889
{
1890
    Session::erase('in_gradebook');
1891
}
1892
1893
/**
1894
 * Returns the current course info array see api_format_course_array()
1895
 * If the course_code is given, the returned array gives info about that
1896
 * particular course, if none given it gets the course info from the session.
1897
 *
1898
 * @param string $course_code
1899
 * @param bool $strict
1900
 *
1901
 * @return array
1902
 */
1903
function api_get_course_info($course_code = null, $strict = false)
0 ignored issues
show
Unused Code introduced by
The parameter $strict 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

1903
function api_get_course_info($course_code = null, /** @scrutinizer ignore-unused */ $strict = 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...
1904
{
1905
    if (!empty($course_code)) {
1906
        $course_code = Database::escape_string($course_code);
1907
        $courseId = api_get_course_int_id($course_code);
1908
1909
        if (empty($courseId)) {
1910
            return [];
1911
        }
1912
1913
        $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
1914
        $course_cat_table = Database::get_main_table(TABLE_MAIN_CATEGORY);
1915
        $sql = "SELECT
1916
                    course.*,
1917
                    course_category.code faCode,
1918
                    course_category.name faName
1919
                FROM $course_table
1920
                LEFT JOIN $course_cat_table
1921
                ON course.category_code = course_category.code
1922
                WHERE course.id = $courseId";
1923
        $result = Database::query($sql);
1924
        $courseInfo = [];
1925
        if (Database::num_rows($result) > 0) {
1926
            $data = Database::fetch_array($result);
1927
            $courseInfo = api_format_course_array($data);
1928
        }
1929
1930
        return $courseInfo;
1931
    }
1932
1933
    global $_course;
1934
    if ($_course == '-1') {
1935
        $_course = [];
1936
    }
1937
1938
    return $_course;
1939
}
1940
1941
/**
1942
 * @param int $courseId
1943
 * @return \Chamilo\CoreBundle\Entity\Course
1944
 */
1945
function api_get_course_entity($courseId)
1946
{
1947
    if (empty($courseId)) {
1948
        $courseId = api_get_course_int_id();
1949
    }
1950
    return CourseManager::getManager()->find($courseId);
1951
}
1952
1953
/**
1954
 * Returns the current course info array.
1955
1956
 * Now if the course_code is given, the returned array gives info about that
1957
 * particular course, not specially the current one.
1958
 * @param int $id Numeric ID of the course
1959
 * @return array The course info as an array formatted by api_format_course_array, including category.name
1960
 */
1961
function api_get_course_info_by_id($id = null)
1962
{
1963
    if (!empty($id)) {
1964
        $id = intval($id);
1965
        $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
1966
        $course_cat_table = Database::get_main_table(TABLE_MAIN_CATEGORY);
1967
        $sql = "SELECT
1968
                    course.*,
1969
                    course_category.code faCode,
1970
                    course_category.name faName
1971
                FROM $course_table
1972
                LEFT JOIN $course_cat_table
1973
                ON course.category_code = course_category.code
1974
                WHERE course.id = $id";
1975
        $result = Database::query($sql);
1976
        $_course = [];
1977
        if (Database::num_rows($result) > 0) {
1978
            $row = Database::fetch_array($result);
1979
            $_course = api_format_course_array($row);
1980
        }
1981
        return $_course;
1982
    }
1983
1984
    global $_course;
1985
    if ($_course == '-1') {
1986
        $_course = [];
1987
    }
1988
    return $_course;
1989
}
1990
1991
/**
1992
 * Reformat the course array (output by api_get_course_info()) in order, mostly,
1993
 * to switch from 'code' to 'id' in the array. This is a legacy feature and is
1994
 * now possibly causing massive confusion as a new "id" field has been added to
1995
 * the course table in 1.9.0.
1996
 * @param $course_data
1997
 * @return array
1998
 * @todo eradicate the false "id"=code field of the $_course array and use the int id
1999
 */
2000
function api_format_course_array($course_data)
2001
{
2002
    if (empty($course_data)) {
2003
        return [];
2004
    }
2005
2006
    $_course = [];
2007
    $_course['id'] = $course_data['code'];
2008
    $_course['real_id'] = $course_data['id'];
2009
2010
    // Added
2011
    $_course['code'] = $course_data['code'];
2012
    $_course['name'] = $course_data['title'];
2013
    $_course['title'] = $course_data['title'];
2014
    $_course['official_code'] = $course_data['visual_code'];
2015
    $_course['visual_code'] = $course_data['visual_code'];
2016
    $_course['sysCode'] = $course_data['code'];
2017
    $_course['path'] = $course_data['directory']; // Use as key in path.
2018
    $_course['directory'] = $course_data['directory'];
2019
    $_course['creation_date'] = $course_data['creation_date'];
2020
    $_course['titular'] = $course_data['tutor_name'];
2021
    $_course['language'] = $course_data['course_language'];
2022
    $_course['extLink']['url'] = $course_data['department_url'];
2023
    $_course['extLink']['name'] = $course_data['department_name'];
2024
    $_course['categoryCode'] = $course_data['faCode'];
2025
    $_course['categoryName'] = $course_data['faName'];
2026
    $_course['visibility'] = $course_data['visibility'];
2027
    $_course['subscribe_allowed'] = $course_data['subscribe'];
2028
    $_course['subscribe'] = $course_data['subscribe'];
2029
    $_course['unsubscribe'] = $course_data['unsubscribe'];
2030
    $_course['course_language'] = $course_data['course_language'];
2031
    $_course['activate_legal'] = isset($course_data['activate_legal']) ? $course_data['activate_legal'] : false;
2032
    $_course['legal'] = $course_data['legal'];
2033
    $_course['show_score'] = $course_data['show_score']; //used in the work tool
2034
    $_course['department_name'] = $course_data['department_name'];
2035
    $_course['department_url'] = $course_data['department_url'];
2036
2037
    $courseSys = api_get_path(SYS_COURSE_PATH).$course_data['directory'];
2038
    $webCourseHome = api_get_path(WEB_COURSE_PATH).$course_data['directory'];
2039
2040
    // Course password
2041
    $_course['registration_code'] = !empty($course_data['registration_code']) ? sha1($course_data['registration_code']) : null;
2042
    $_course['disk_quota'] = $course_data['disk_quota'];
2043
    $_course['course_public_url'] = $webCourseHome.'/index.php';
2044
2045
    if (array_key_exists('add_teachers_to_sessions_courses', $course_data)) {
2046
        $_course['add_teachers_to_sessions_courses'] = $course_data['add_teachers_to_sessions_courses'];
2047
    }
2048
2049
    // Course image
2050
    $_course['course_image_source'] = '';
2051
    if (file_exists($courseSys.'/course-pic85x85.png')) {
2052
        $url_image = $webCourseHome.'/course-pic85x85.png';
2053
        $_course['course_image_source'] = $courseSys.'/course-pic85x85.png';
2054
    } else {
2055
        $url_image = Display::return_icon(
2056
            'course.png',
2057
            null,
2058
            null,
2059
            ICON_SIZE_BIG,
2060
            null,
2061
            true,
2062
            false
2063
        );
2064
    }
2065
    $_course['course_image'] = $url_image;
2066
2067
    // Course large image
2068
    $_course['course_image_large_source'] = '';
2069
    if (file_exists($courseSys.'/course-pic.png')) {
2070
        $url_image = $webCourseHome.'/course-pic.png';
2071
        $_course['course_image_large_source'] = $courseSys.'/course-pic.png';
2072
    } else {
2073
        $url_image = Display::return_icon(
2074
            'session_default.png',
2075
            null,
2076
            null,
2077
            null,
2078
            null,
2079
            true
2080
        );
2081
    }
2082
    $_course['course_image_large'] = $url_image;
2083
2084
    return $_course;
2085
}
2086
2087
/**
2088
 * Returns a difficult to guess password.
2089
 * @param int $length the length of the password
2090
 * @return string the generated password
2091
 */
2092
function api_generate_password($length = 8)
2093
{
2094
    if ($length < 2) {
2095
        $length = 2;
2096
    }
2097
2098
    $charactersLowerCase = 'abcdefghijkmnopqrstuvwxyz';
2099
    $charactersUpperCase = 'ABCDEFGHJKLMNPQRSTUVWXYZ';
2100
    $minNumbers = 2;
2101
    $length = $length - $minNumbers;
2102
    $minLowerCase = round($length / 2);
2103
    $minUpperCase = $length - $minLowerCase;
2104
2105
    $password = '';
2106
    $passwordRequirements = api_get_configuration_value('password_requirements');
2107
2108
    $factory = new RandomLib\Factory();
2109
    $generator = $factory->getGenerator(new SecurityLib\Strength(SecurityLib\Strength::MEDIUM));
2110
2111
    if (!empty($passwordRequirements)) {
2112
        $length = $passwordRequirements['min']['length'];
2113
        $minNumbers = $passwordRequirements['min']['numeric'];
2114
        $minLowerCase = $passwordRequirements['min']['lowercase'];
2115
        $minUpperCase = $passwordRequirements['min']['uppercase'];
2116
2117
        $rest = $length - $minNumbers - $minLowerCase - $minUpperCase;
2118
        // Add the rest to fill the length requirement
2119
        if ($rest > 0) {
2120
            $password .= $generator->generateString($rest, $charactersLowerCase.$charactersUpperCase);
2121
        }
2122
    }
2123
2124
    // Min digits default 2
2125
    for ($i = 0; $i < $minNumbers; $i++) {
2126
        $password .= $generator->generateInt(2, 9);
2127
    }
2128
2129
    // Min lowercase
2130
    $password .= $generator->generateString($minLowerCase, $charactersLowerCase);
2131
2132
    // Min uppercase
2133
    $password .= $generator->generateString($minUpperCase, $charactersUpperCase);
2134
    $password = str_shuffle($password);
2135
2136
    return $password;
2137
}
2138
2139
/**
2140
 * Checks a password to see wether it is OK to use.
2141
 * @param string $password
2142
 * @return boolean if the password is acceptable, false otherwise
2143
 * Notes about what a password "OK to use" is:
2144
 * 1. The password should be at least 5 characters long.
2145
 * 2. Only English letters (uppercase or lowercase, it doesn't matter) and digits are allowed.
2146
 * 3. The password should contain at least 3 letters.
2147
 * 4. It should contain at least 2 digits.
2148
 * Settings will change if the configuration value is set: password_requirements
2149
 */
2150
function api_check_password($password)
2151
{
2152
    $passwordRequirements = Security::getPasswordRequirements();
2153
2154
    $minLength = $passwordRequirements['min']['length'];
2155
    $minNumbers = $passwordRequirements['min']['numeric'];
2156
    // Optional
2157
    $minLowerCase = $passwordRequirements['min']['lowercase'];
2158
    $minUpperCase = $passwordRequirements['min']['uppercase'];
2159
2160
    $minLetters = $minLowerCase + $minUpperCase;
2161
    $passwordLength = api_strlen($password);
2162
2163
    $conditions = [
2164
        'min_length' => $passwordLength >= $minLength
2165
    ];
2166
2167
    $digits = 0;
2168
    $lowerCase = 0;
2169
    $upperCase = 0;
2170
2171
    for ($i = 0; $i < $passwordLength; $i++) {
2172
        $currentCharacterCode = api_ord(api_substr($password, $i, 1));
2173
        if ($currentCharacterCode >= 65 && $currentCharacterCode <= 90) {
2174
            $upperCase++;
2175
        }
2176
2177
        if ($currentCharacterCode >= 97 && $currentCharacterCode <= 122) {
2178
            $lowerCase++;
2179
        }
2180
        if ($currentCharacterCode >= 48 && $currentCharacterCode <= 57) {
2181
            $digits++;
2182
        }
2183
    }
2184
2185
    // Min number of digits
2186
    $conditions['min_numeric'] = $digits >= $minNumbers;
2187
2188
    if (!empty($minUpperCase)) {
2189
        // Uppercase
2190
        $conditions['min_uppercase'] = $upperCase >= $minUpperCase;
2191
    }
2192
2193
    if (!empty($minLowerCase)) {
2194
        // Lowercase
2195
        $conditions['min_lowercase'] = $upperCase >= $minLowerCase;
2196
    }
2197
2198
    // Min letters
2199
    $letters = $upperCase + $lowerCase;
2200
    $conditions['min_letters'] = $letters >= $minLetters;
2201
2202
    $isPasswordOk = true;
2203
    foreach ($conditions as $condition) {
2204
        if ($condition === false) {
2205
            $isPasswordOk = false;
2206
            break;
2207
        }
2208
    }
2209
2210
    if ($isPasswordOk === false) {
2211
        $output = get_lang('NewPasswordRequirementsNotMatched').'<br />';
2212
        $output .= Security::getPasswordRequirementsToString($conditions);
2213
2214
        Display::addFlash(Display::return_message($output, 'warning', false));
2215
    }
2216
2217
    return $isPasswordOk;
2218
}
2219
2220
/**
2221
 * Clears the user ID from the session if it was the anonymous user. Generally
2222
 * used on out-of-tools pages to remove a user ID that could otherwise be used
2223
 * in the wrong context.
2224
 * This function is to be used in conjunction with the api_set_anonymous()
2225
 * function to simulate the user existence in case of an anonymous visit.
2226
 * @param bool      database check switch - passed to api_is_anonymous()
2227
 * @return bool     true if succesfully unregistered, false if not anonymous.
2228
 */
2229
function api_clear_anonymous($db_check = false)
2230
{
2231
    global $_user;
2232
    if (api_is_anonymous($_user['user_id'], $db_check)) {
2233
        unset($_user['user_id']);
2234
        Session::erase('_uid');
2235
        return true;
2236
    }
2237
    return false;
2238
}
2239
2240
/**
2241
 * Returns the status string corresponding to the status code
2242
 * @author Noel Dieschburg
2243
 * @param the int status code
2244
 * @return string
2245
 */
2246
function get_status_from_code($status_code)
2247
{
2248
    switch ($status_code) {
2249
        case STUDENT:
2250
            return get_lang('Student', '');
2251
        case TEACHER:
0 ignored issues
show
Bug introduced by
The constant TEACHER was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2252
            return get_lang('Teacher', '');
2253
        case COURSEMANAGER:
2254
            return get_lang('Manager', '');
2255
        case SESSIONADMIN:
2256
            return get_lang('SessionsAdmin', '');
2257
        case DRH:
2258
            return get_lang('Drh', '');
2259
    }
2260
}
2261
2262
/**
2263
 * Sets the current user as anonymous if it hasn't been identified yet. This
2264
 * function should be used inside a tool only. The function api_clear_anonymous()
2265
 * acts in the opposite direction by clearing the anonymous user's data every
2266
 * time we get on a course homepage or on a neutral page (index, admin, my space)
2267
 * @return bool     true if set user as anonymous, false if user was already logged in or anonymous id could not be found
2268
 */
2269
function api_set_anonymous()
2270
{
2271
    global $_user;
2272
2273
    if (!empty($_user['user_id'])) {
2274
        return false;
2275
    }
2276
2277
    $user_id = api_get_anonymous_id();
2278
    if ($user_id == 0) {
2279
        return false;
2280
    }
2281
2282
    if (isset($_user['is_anonymous'])) {
2283
        return false;
2284
    }
2285
2286
    Session::erase('_user');
2287
    $_user['user_id'] = $user_id;
2288
    $_user['is_anonymous'] = true;
2289
    $GLOBALS['_user'] = $_user;
2290
    Session::write('_user', $_user);
2291
    return true;
2292
}
2293
2294
/**
2295
 * Gets the current Chamilo (not PHP/cookie) session ID
2296
 * @return  int     O if no active session, the session ID otherwise
2297
 */
2298
function api_get_session_id()
2299
{
2300
    return (int) Session::read('id_session', 0);
2301
}
2302
2303
/**
2304
 * Gets the current Chamilo (not social network) group ID
2305
 * @return  int     O if no active session, the session ID otherwise
2306
 */
2307
function api_get_group_id()
2308
{
2309
    return Session::read('_gid', 0);
2310
}
2311
2312
/**
2313
 * Gets the current or given session name
2314
 * @param   int     Session ID (optional)
2315
 * @return  string  The session name, or null if not found
2316
 */
2317
function api_get_session_name($session_id = 0)
2318
{
2319
    if (empty($session_id)) {
2320
        $session_id = api_get_session_id();
2321
        if (empty($session_id)) {
2322
            return null;
2323
        }
2324
    }
2325
    $t = Database::get_main_table(TABLE_MAIN_SESSION);
2326
    $s = "SELECT name FROM $t WHERE id = ".(int) $session_id;
2327
    $r = Database::query($s);
2328
    $c = Database::num_rows($r);
2329
    if ($c > 0) {
2330
        //technically, there can be only one, but anyway we take the first
2331
        $rec = Database::fetch_array($r);
2332
        return $rec['name'];
2333
    }
2334
    return null;
2335
}
2336
2337
/**
2338
 * Gets the session info by id
2339
 * @param int $id       Session ID
2340
 * @return array    information of the session
2341
 */
2342
function api_get_session_info($id)
2343
{
2344
    return SessionManager::fetch($id);
2345
}
2346
2347
/**
2348
 * Gets the session visibility by session id
2349
 * @param int $session_id
2350
 * @param int $courseId
2351
 * @param bool $ignore_visibility_for_admins
2352
 * @return int
2353
 *  0 = session still available,
2354
 *  SESSION_VISIBLE_READ_ONLY = 1,
2355
 *  SESSION_VISIBLE = 2,
2356
 *  SESSION_INVISIBLE = 3
2357
 */
2358
function api_get_session_visibility(
2359
    $session_id,
2360
    $courseId = null,
2361
    $ignore_visibility_for_admins = true
2362
) {
2363
    if (api_is_platform_admin()) {
2364
        if ($ignore_visibility_for_admins) {
2365
            return SESSION_AVAILABLE;
2366
        }
2367
    }
2368
2369
    $now = time();
2370
2371
    if (empty($session_id)) {
2372
        return 0; // Means that the session is still available.
2373
    }
2374
2375
    $session_id = intval($session_id);
2376
    $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
2377
2378
    $result = Database::query("SELECT * FROM $tbl_session WHERE id = $session_id");
2379
2380
    if (Database::num_rows($result) <= 0) {
2381
        return SESSION_INVISIBLE;
2382
    }
2383
2384
    $row = Database::fetch_array($result, 'ASSOC');
2385
    $visibility = $original_visibility = $row['visibility'];
2386
2387
    // I don't care the session visibility.
2388
    if (empty($row['access_start_date']) && empty($row['access_end_date'])) {
2389
        // Session duration per student.
2390
        if (isset($row['duration']) && !empty($row['duration'])) {
2391
            $duration = $row['duration'] * 24 * 60 * 60;
2392
            $courseAccess = CourseManager::getFirstCourseAccessPerSessionAndUser($session_id, api_get_user_id());
2393
2394
            // If there is a session duration but there is no previous
2395
            // access by the user, then the session is still available
2396
            if (count($courseAccess) == 0) {
2397
                return SESSION_AVAILABLE;
2398
            }
2399
2400
            $currentTime = time();
2401
            $firstAccess = isset($courseAccess['login_course_date'])
2402
                ? api_strtotime($courseAccess['login_course_date'], 'UTC')
2403
                : 0;
2404
            $userDurationData = SessionManager::getUserSession(
2405
                api_get_user_id(),
2406
                $session_id
2407
            );
2408
            $userDuration = isset($userDurationData['duration'])
2409
                ? (intval($userDurationData['duration']) * 24 * 60 * 60)
2410
                : 0;
2411
2412
            $totalDuration = $firstAccess + $duration + $userDuration;
2413
2414
            return $totalDuration > $currentTime ? SESSION_AVAILABLE : SESSION_VISIBLE_READ_ONLY;
2415
        }
2416
2417
        return SESSION_AVAILABLE;
2418
    }
2419
    // If start date was set.
2420
    if (!empty($row['access_start_date'])) {
2421
        $visibility = $now > api_strtotime($row['access_start_date'], 'UTC') ? SESSION_AVAILABLE : SESSION_INVISIBLE;
2422
    }
2423
2424
    // If the end date was set.
2425
    if (!empty($row['access_end_date'])) {
2426
        // Only if date_start said that it was ok
2427
        if ($visibility === SESSION_AVAILABLE) {
2428
            $visibility = $now < api_strtotime($row['access_end_date'], 'UTC')
2429
                ? SESSION_AVAILABLE // Date still available
2430
                : $row['visibility']; // Session ends
2431
        }
2432
    }
2433
2434
    /* If I'm a coach the visibility can change in my favor depending in
2435
     the coach dates */
2436
    $isCoach = api_is_coach($session_id, $courseId);
2437
2438
    if ($isCoach) {
2439
        // Test start date.
2440
        if (!empty($row['coach_access_start_date'])) {
2441
            $start = api_strtotime($row['coach_access_start_date'], 'UTC');
2442
            $visibility = $start < $now ? SESSION_AVAILABLE : SESSION_INVISIBLE;
2443
        }
2444
2445
        // Test end date.
2446
        if (!empty($row['coach_access_end_date'])) {
2447
            if ($visibility === SESSION_AVAILABLE) {
2448
                $endDateCoach = api_strtotime($row['coach_access_end_date'], 'UTC');
2449
                $visibility = $endDateCoach >= $now ? SESSION_AVAILABLE : $row['visibility'];
2450
            }
2451
        }
2452
    }
2453
2454
    return $visibility;
2455
}
2456
2457
/**
2458
 * This function returns a (star) session icon if the session is not null and
2459
 * the user is not a student
2460
 * @param int   $session_id
2461
 * @param int   $status_id User status id - if 5 (student), will return empty
2462
 * @return string   Session icon
2463
 */
2464
function api_get_session_image($session_id, $status_id)
2465
{
2466
    $session_id = (int) $session_id;
2467
    $session_img = '';
2468
    if ((int) $status_id != 5) { //check whether is not a student
2469
        if ($session_id > 0) {
2470
            $session_img = "&nbsp;&nbsp;".Display::return_icon(
2471
                    'star.png',
2472
                    get_lang('SessionSpecificResource'),
2473
                    ['align' => 'absmiddle'],
2474
                    ICON_SIZE_SMALL
2475
                );
2476
        }
2477
    }
2478
    return $session_img;
2479
}
2480
2481
/**
2482
 * This function add an additional condition according to the session of the course
2483
 * @param int       $session_id session id
2484
 * @param bool      $and optional, true if more than one condition false if the only condition in the query
2485
 * @param bool      $with_base_content optional, true to accept content with session=0 as well,
2486
 * false for strict session condition
2487
 * @param string $session_field
2488
 * @return string   condition of the session
2489
 */
2490
function api_get_session_condition(
2491
    $session_id,
2492
    $and = true,
2493
    $with_base_content = false,
2494
    $session_field = 'session_id'
2495
) {
2496
    $session_id = intval($session_id);
2497
2498
    if (empty($session_field)) {
2499
        $session_field = "session_id";
2500
    }
2501
    // Condition to show resources by session
2502
    $condition_add = $and ? " AND " : " WHERE ";
2503
2504
    if ($with_base_content) {
2505
        $condition_session = $condition_add." ( $session_field = $session_id OR $session_field = 0 OR $session_field IS NULL) ";
2506
    } else {
2507
        if (empty($session_id)) {
2508
            $condition_session = $condition_add." ($session_field = $session_id OR $session_field IS NULL)";
2509
        } else {
2510
            $condition_session = $condition_add." $session_field = $session_id ";
2511
        }
2512
    }
2513
    return $condition_session;
2514
}
2515
2516
/**
2517
 * Returns the value of a setting from the web-adjustable admin config settings.
2518
 *
2519
 * WARNING true/false are stored as string, so when comparing you need to check e.g.
2520
 * if (api_get_setting('show_navigation_menu') == 'true') //CORRECT
2521
 * instead of
2522
 * if (api_get_setting('show_navigation_menu') == true) //INCORRECT
2523
 * @param string    $variable The variable name
2524
 * @param string    $key The subkey (sub-variable) if any. Defaults to NULL
2525
 * @return string
2526
 * @author René Haentjens
2527
 * @author Bart Mollet
2528
 */
2529
function api_get_setting($variable)
2530
{
2531
    $variable = trim($variable);
2532
2533
    switch ($variable) {
2534
        case 'header_extra_content':
2535
            $filename = api_get_path(SYS_PATH).api_get_home_path().'header_extra_content.txt';
2536
            if (file_exists($filename)) {
2537
                $value = file_get_contents($filename);
2538
                return $value ;
2539
            } else {
2540
                return '';
2541
            }
2542
            break;
2543
        case 'footer_extra_content':
2544
            $filename = api_get_path(SYS_PATH).api_get_home_path().'footer_extra_content.txt';
2545
            if (file_exists($filename)) {
2546
                $value = file_get_contents($filename);
2547
                return $value ;
2548
            } else {
2549
                return '';
2550
            }
2551
            break;
2552
        case 'server_type':
2553
            $test = ['dev', 'test'];
2554
            $environment = Container::getEnvironment();
2555
            if (in_array($environment, $test)) {
2556
                return 'test';
2557
            }
2558
            return 'prod';
2559
        case 'stylesheets':
2560
            $variable = 'platform.theme';
2561
        // deprecated settings
2562
        // no break
2563
        case 'openid_authentication':
2564
        case 'sso_authentication':
2565
        case 'service_ppt2lp':
2566
        case 'add_cas_login_button_cas_button_label':
2567
        case 'add_cas_login_button_cas_button_comment':
2568
        case 'add_cas_login_button_cas_image_url':
2569
        case 'add_cas_logout_button_cas_logout_label':
2570
        case 'add_cas_logout_button_cas_logout_comment':
2571
        case 'add_cas_logout_button_cas_logout_image_url':
2572
        case 'add_facebook_login_button_facebook_button_url':
2573
        case 'add_shibboleth_login_button_shibboleth_button_label':
2574
        case 'add_shibboleth_login_button_shibboleth_button_comment':
2575
        case 'add_shibboleth_login_button_shibboleth_image_url':
2576
        case 'formLogin_hide_unhide_label':
2577
            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...
2578
            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...
2579
        case 'tool_visible_by_default_at_creation':
2580
            $values = Container::getSettingsManager()->getSetting($variable);
2581
            $newResult = [];
2582
            foreach ($values as $parameter) {
2583
                $newResult[$parameter] = 'true';
2584
            }
2585
            return $newResult;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $newResult returns the type array|string[] which is incompatible with the documented return type string.
Loading history...
2586
            break;
2587
        default:
2588
            /** @var \Doctrine\ORM\EntityManager $em */
2589
            return Container::getSettingsManager()->getSetting($variable);
2590
    }
2591
2592
    // Old code
2593
    var_dump($variable);
0 ignored issues
show
Security Debugging Code introduced by
var_dump($variable) looks like debug code. Are you sure you do not want to remove it?
Loading history...
Unused Code introduced by
var_dump($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...
2594
2595
    global $_setting;
2596
    if ($variable == 'header_extra_content') {
2597
        $filename = api_get_home_path().'header_extra_content.txt';
2598
        if (file_exists($filename)) {
2599
            $value = file_get_contents($filename);
2600
            return $value;
2601
        } else {
2602
            return '';
2603
        }
2604
    }
2605
    if ($variable == 'footer_extra_content') {
2606
        $filename = api_get_home_path().'footer_extra_content.txt';
2607
        if (file_exists($filename)) {
2608
            $value = file_get_contents($filename);
2609
            return $value;
2610
        } else {
2611
            return '';
2612
        }
2613
    }
2614
    $value = null;
2615
    if (is_null($key)) {
2616
        $value = ((isset($_setting[$variable]) && $_setting[$variable] != '') ? $_setting[$variable] : null);
2617
    } else {
2618
        if (isset($_setting[$variable][$key])) {
2619
            $value = $_setting[$variable][$key];
2620
        }
2621
    }
2622
2623
    return $value;
2624
}
2625
2626
/**
2627
 * @param string $plugin
2628
 * @param string $variable
2629
 * @return string
2630
 */
2631
function api_get_plugin_setting($plugin, $variable)
2632
{
2633
    $variableName = $plugin.'_'.$variable;
2634
    $params = [
2635
        'category = ? AND subkey = ? AND variable = ?' => [
2636
            'Plugins',
2637
            $plugin,
2638
            $variableName,
2639
        ],
2640
    ];
2641
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2642
    $result = Database::select(
2643
        'selected_value',
2644
        $table,
2645
        ['where' => $params],
2646
        'one'
2647
    );
2648
    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...
2649
        $result = $result['selected_value'];
2650
        return $result;
2651
    }
2652
2653
    return null;
2654
    /// Old code
2655
2656
    $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...
2657
    $result = api_get_setting($variableName);
2658
2659
    if (isset($result[$plugin])) {
2660
        $value = $result[$plugin];
2661
        if (@unserialize($value) !== false) {
2662
            $value = unserialize($value);
2663
        }
2664
        return $value;
2665
    }
2666
2667
    return null;
2668
}
2669
2670
/**
2671
 * Returns the value of a setting from the web-adjustable admin config settings.
2672
 **/
2673
function api_get_settings_params($params)
2674
{
2675
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2676
    $result = Database::select('*', $table, ['where' => $params]);
2677
    return $result;
2678
}
2679
2680
function api_get_settings_params_simple($params)
2681
{
2682
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2683
    $result = Database::select('*', $table, ['where' => $params], 'one');
2684
    return $result;
2685
}
2686
2687
/**
2688
 * Returns the value of a setting from the web-adjustable admin config settings.
2689
 **/
2690
function api_delete_settings_params($params)
2691
{
2692
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2693
    $result = Database::delete($table, $params);
2694
    return $result;
2695
}
2696
2697
/**
2698
 * Returns an escaped version of $_SERVER['PHP_SELF'] to avoid XSS injection
2699
 * @return string   Escaped version of $_SERVER['PHP_SELF']
2700
 */
2701
function api_get_self()
2702
{
2703
    return htmlentities($_SERVER['PHP_SELF']);
2704
}
2705
2706
/* USER PERMISSIONS */
2707
2708
/**
2709
 * Checks whether current user is a platform administrator
2710
 * @param boolean $allowSessionAdmins Whether session admins should be considered admins or not
2711
 * @param boolean $allowDrh Whether HR directors should be considered admins or not
2712
 * @return boolean True if the user has platform admin rights,
2713
 * false otherwise.
2714
 * @see usermanager::is_admin(user_id) for a user-id specific function
2715
 */
2716
function api_is_platform_admin($allowSessionAdmins = false, $allowDrh = false)
2717
{
2718
    $isAdmin = Session::read('is_platformAdmin');
2719
    if ($isAdmin) {
2720
        return true;
2721
    }
2722
    $user = api_get_user_info();
2723
    return
2724
        isset($user['status']) &&
2725
        (
2726
            ($allowSessionAdmins && $user['status'] == SESSIONADMIN) ||
2727
            ($allowDrh && $user['status'] == DRH)
2728
        );
2729
}
2730
2731
/**
2732
 * Checks whether the user given as user id is in the admin table.
2733
 * @param int $user_id If none provided, will use current user
2734
 * @param int $url URL ID. If provided, also check if the user is active on given URL
2735
 * @return bool True if the user is admin, false otherwise
2736
 */
2737
function api_is_platform_admin_by_id($user_id = null, $url = null)
2738
{
2739
    $user_id = intval($user_id);
2740
    if (empty($user_id)) {
2741
        $user_id = api_get_user_id();
2742
    }
2743
    $admin_table = Database::get_main_table(TABLE_MAIN_ADMIN);
2744
    $sql = "SELECT * FROM $admin_table WHERE user_id = $user_id";
2745
    $res = Database::query($sql);
2746
    $is_admin = Database::num_rows($res) === 1;
2747
    if (!$is_admin || !isset($url)) {
2748
        return $is_admin;
2749
    }
2750
    // We get here only if $url is set
2751
    $url = intval($url);
2752
    $url_user_table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
2753
    $sql = "SELECT * FROM $url_user_table
2754
            WHERE access_url_id = $url AND user_id = $user_id";
2755
    $res = Database::query($sql);
2756
    $result = Database::num_rows($res) === 1;
2757
2758
    return $result;
2759
}
2760
2761
/**
2762
 * Returns the user's numeric status ID from the users table
2763
 * @param int $user_id If none provided, will use current user
2764
 * @return int User's status (1 for teacher, 5 for student, etc)
2765
 */
2766
function api_get_user_status($user_id = null)
2767
{
2768
    $user_id = intval($user_id);
2769
    if (empty($user_id)) {
2770
        $user_id = api_get_user_id();
2771
    }
2772
    $table = Database::get_main_table(TABLE_MAIN_USER);
2773
    $sql = "SELECT status FROM $table WHERE user_id = $user_id ";
2774
    $result = Database::query($sql);
2775
    $status = null;
2776
    if (Database::num_rows($result)) {
2777
        $row = Database::fetch_array($result);
2778
        $status = $row['status'];
2779
    }
2780
    return $status;
2781
}
2782
2783
/**
2784
 * Checks whether current user is allowed to create courses
2785
 * @return boolean True if the user has course creation rights,
2786
 * false otherwise.
2787
 */
2788
function api_is_allowed_to_create_course()
2789
{
2790
    if (api_is_platform_admin()) {
2791
        return true;
2792
    }
2793
2794
    // Teachers can only create courses
2795
    if (api_is_teacher()) {
2796
        if (api_get_setting('allow_users_to_create_courses') === 'true') {
2797
            return true;
2798
        } else {
2799
            return false;
2800
        }
2801
    }
2802
2803
    return Session::read('is_allowedCreateCourse');
2804
}
2805
2806
/**
2807
 * Checks whether the current user is a course administrator
2808
 * @return boolean True if current user is a course administrator
2809
 */
2810
function api_is_course_admin()
2811
{
2812
    if (api_is_platform_admin()) {
2813
        return true;
2814
    }
2815
    return Session::read('is_courseAdmin');
2816
}
2817
2818
/**
2819
 * Checks whether the current user is a course coach
2820
 * Based on the presence of user in session.id_coach (session general coach)
2821
 * @return bool True if current user is a course coach
2822
 */
2823
function api_is_session_general_coach()
2824
{
2825
    return Session::read('is_session_general_coach');
2826
}
2827
2828
/**
2829
 * Checks whether the current user is a course tutor
2830
 * Based on the presence of user in session_rel_course_rel_user.user_id with status = 2
2831
 * @return bool     True if current user is a course tutor
2832
 */
2833
function api_is_course_tutor()
2834
{
2835
    return Session::read('is_courseTutor');
2836
}
2837
2838
/**
2839
 * @param int $user_id
2840
 * @param int $courseId
2841
 * @param int $session_id
2842
 * @return bool
2843
 */
2844
function api_is_course_session_coach($user_id, $courseId, $session_id)
2845
{
2846
    $session_table = Database::get_main_table(TABLE_MAIN_SESSION);
2847
    $session_rel_course_rel_user_table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2848
2849
    $user_id = intval($user_id);
2850
    $session_id = intval($session_id);
2851
    $courseId = intval($courseId);
2852
2853
    $sql = "SELECT DISTINCT session.id
2854
            FROM $session_table
2855
            INNER JOIN $session_rel_course_rel_user_table session_rc_ru
2856
            ON session.id = session_rc_ru.session_id
2857
            WHERE
2858
                session_rc_ru.user_id = '".$user_id."'  AND
2859
                session_rc_ru.c_id = '$courseId' AND
2860
                session_rc_ru.status = 2 AND
2861
                session_rc_ru.session_id = '$session_id'";
2862
    $result = Database::query($sql);
2863
2864
    return Database::num_rows($result) > 0;
2865
}
2866
2867
/**
2868
 * Checks whether the current user is a course or session coach
2869
 * @param int $session_id
2870
 * @param int $courseId
2871
 * @param bool  Check whether we are in student view and, if we are, return false
2872
 * @return boolean True if current user is a course or session coach
2873
 */
2874
function api_is_coach($session_id = 0, $courseId = null, $check_student_view = true)
2875
{
2876
    $userId = api_get_user_id();
2877
2878
    if (!empty($session_id)) {
2879
        $session_id = intval($session_id);
2880
    } else {
2881
        $session_id = api_get_session_id();
2882
    }
2883
2884
    // The student preview was on
2885
    if ($check_student_view && api_is_student_view_active()) {
2886
        return false;
2887
    }
2888
2889
    if (!empty($courseId)) {
2890
        $courseId = intval($courseId);
2891
    } else {
2892
        $courseId = api_get_course_int_id();
2893
    }
2894
2895
    $session_table = Database::get_main_table(TABLE_MAIN_SESSION);
2896
    $session_rel_course_rel_user_table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2897
    $sessionIsCoach = null;
2898
2899
    if (!empty($courseId)) {
2900
        $sql = "SELECT DISTINCT s.id, name, access_start_date, access_end_date
2901
                FROM $session_table s
2902
                INNER JOIN $session_rel_course_rel_user_table session_rc_ru
2903
                ON session_rc_ru.session_id = s.id AND session_rc_ru.user_id = '".$userId."'
2904
                WHERE
2905
                    session_rc_ru.c_id = '$courseId' AND
2906
                    session_rc_ru.status = 2 AND
2907
                    session_rc_ru.session_id = '$session_id'";
2908
        $result = Database::query($sql);
2909
        $sessionIsCoach = Database::store_result($result);
2910
    }
2911
2912
    if (!empty($session_id)) {
2913
        $sql = "SELECT DISTINCT id, name, access_start_date, access_end_date
2914
                FROM $session_table
2915
                WHERE session.id_coach = $userId AND id = $session_id
2916
                ORDER BY access_start_date, access_end_date, name";
2917
        $result = Database::query($sql);
2918
        if (!empty($sessionIsCoach)) {
2919
            $sessionIsCoach = array_merge(
2920
                $sessionIsCoach,
2921
                Database::store_result($result)
2922
            );
2923
        } else {
2924
            $sessionIsCoach = Database::store_result($result);
2925
        }
2926
    }
2927
2928
    return count($sessionIsCoach) > 0;
2929
}
2930
2931
/**
2932
 * Checks whether the current user is a session administrator
2933
 * @return boolean True if current user is a course administrator
2934
 */
2935
function api_is_session_admin()
2936
{
2937
    $user = api_get_user_info();
2938
    return isset($user['status']) && $user['status'] == SESSIONADMIN;
2939
}
2940
2941
/**
2942
 * Checks whether the current user is a human resources manager
2943
 * @return boolean True if current user is a human resources manager
2944
 */
2945
function api_is_drh()
2946
{
2947
    $user = api_get_user_info();
2948
    return isset($user['status']) && $user['status'] == DRH;
2949
}
2950
2951
/**
2952
 * Checks whether the current user is a student
2953
 * @return boolean True if current user is a human resources manager
2954
 */
2955
function api_is_student()
2956
{
2957
    $user = api_get_user_info();
2958
    return isset($user['status']) && $user['status'] == STUDENT;
2959
}
2960
2961
/**
2962
 * Checks whether the current user has the status 'teacher'
2963
 * @return boolean True if current user is a human resources manager
2964
 */
2965
function api_is_teacher()
2966
{
2967
    $user = api_get_user_info();
2968
    return isset($user['status']) && $user['status'] == COURSEMANAGER;
2969
}
2970
2971
/**
2972
 * Checks whether the current user is a invited user
2973
 * @return boolean
2974
 */
2975
function api_is_invitee()
2976
{
2977
    $user = api_get_user_info();
2978
2979
    return isset($user['status']) && $user['status'] == INVITEE;
2980
}
2981
2982
/**
2983
 * This function checks whether a session is assigned into a category
2984
 * @param int       - session id
2985
 * @param string    - category name
2986
 * @return bool     - true if is found, otherwise false
2987
 */
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...
2988
function api_is_session_in_category($session_id, $category_name)
2989
{
2990
    $session_id = intval($session_id);
2991
    $category_name = Database::escape_string($category_name);
2992
    $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
2993
    $tbl_session_category = Database::get_main_table(TABLE_MAIN_SESSION_CATEGORY);
2994
2995
    $sql = "SELECT 1
2996
            FROM $tbl_session
2997
            WHERE $session_id IN (
2998
                SELECT s.id FROM $tbl_session s, $tbl_session_category sc
2999
                WHERE
3000
                  s.session_category_id = sc.id AND
3001
                  sc.name LIKE '%$category_name'
3002
            )";
3003
    $rs = Database::query($sql);
3004
3005
    if (Database::num_rows($rs) > 0) {
3006
        return true;
3007
    } else {
3008
        return false;
3009
    }
3010
}
3011
3012
/**
3013
 * Displays the title of a tool.
3014
 * Normal use: parameter is a string:
3015
 * api_display_tool_title("My Tool")
3016
 *
3017
 * Optionally, there can be a subtitle below
3018
 * the normal title, and / or a supra title above the normal title.
3019
 *
3020
 * e.g. supra title:
3021
 * group
3022
 * GROUP PROPERTIES
3023
 *
3024
 * e.g. subtitle:
3025
 * AGENDA
3026
 * calender & events tool
3027
 *
3028
 * @author Hugues Peeters <[email protected]>
3029
 * @param  mixed $title_element - it could either be a string or an array
3030
 *                               containing 'supraTitle', 'mainTitle',
3031
 *                               'subTitle'
3032
 * @return void
3033
 */
3034
function api_display_tool_title($title_element)
3035
{
3036
    if (is_string($title_element)) {
3037
        $tit = $title_element;
3038
        unset($title_element);
3039
        $title_element['mainTitle'] = $tit;
3040
    }
3041
    echo '<h3>';
3042
    if (!empty($title_element['supraTitle'])) {
3043
        echo '<small>'.$title_element['supraTitle'].'</small><br />';
3044
    }
3045
    if (!empty($title_element['mainTitle'])) {
3046
        echo $title_element['mainTitle'];
3047
    }
3048
    if (!empty($title_element['subTitle'])) {
3049
        echo '<br /><small>'.$title_element['subTitle'].'</small>';
3050
    }
3051
    echo '</h3>';
3052
}
3053
3054
/**
3055
 * Displays options for switching between student view and course manager view
3056
 *
3057
 * Changes in version 1.2 (Patrick Cool)
3058
 * Student view switch now behaves as a real switch. It maintains its current state until the state
3059
 * is changed explicitly
3060
 *
3061
 * Changes in version 1.1 (Patrick Cool)
3062
 * student view now works correctly in subfolders of the document tool
3063
 * student view works correctly in the new links tool
3064
 *
3065
 * Example code for using this in your tools:
3066
 * //if ($is_courseAdmin && api_get_setting('student_view_enabled') == 'true') {
3067
 * //   display_tool_view_option($isStudentView);
3068
 * //}
3069
 * //and in later sections, use api_is_allowed_to_edit()
3070
 *
3071
 * @author Roan Embrechts
3072
 * @author Patrick Cool
3073
 * @author Julio Montoya, changes added in Chamilo
3074
 * @version 1.2
3075
 * @todo rewrite code so it is easier to understand
3076
 */
3077
function api_display_tool_view_option()
3078
{
3079
    if (api_get_setting('student_view_enabled') != 'true') {
3080
        return '';
3081
    }
3082
3083
    $sourceurl = '';
3084
    $is_framed = false;
3085
    // Exceptions apply for all multi-frames pages
3086
    if (strpos($_SERVER['REQUEST_URI'], 'chat/chat_banner.php') !== false) {
3087
        // The chat is a multiframe bit that doesn't work too well with the student_view, so do not show the link
3088
        return '';
3089
    }
3090
3091
    // Uncomment to remove student view link from document view page
3092
    if (strpos($_SERVER['REQUEST_URI'], 'lp/lp_header.php') !== false) {
3093
        if (empty($_GET['lp_id'])) {
3094
            return '';
3095
        }
3096
        $sourceurl = substr($_SERVER['REQUEST_URI'], 0, strpos($_SERVER['REQUEST_URI'], '?'));
3097
        $sourceurl = str_replace(
3098
            'lp/lp_header.php',
3099
            'lp/lp_controller.php?'.api_get_cidreq().'&action=view&lp_id='.intval($_GET['lp_id']).'&isStudentView='.($_SESSION['studentview'] == 'studentview' ? 'false' : 'true'),
3100
            $sourceurl
3101
        );
3102
        //showinframes doesn't handle student view anyway...
3103
        //return '';
3104
        $is_framed = true;
3105
    }
3106
3107
    // Check whether the $_SERVER['REQUEST_URI'] contains already url parameters (thus a questionmark)
3108
    if (!$is_framed) {
3109
        if (strpos($_SERVER['REQUEST_URI'], '?') === false) {
3110
            $sourceurl = api_get_self().'?'.api_get_cidreq();
3111
        } else {
3112
            $sourceurl = $_SERVER['REQUEST_URI'];
3113
        }
3114
    }
3115
3116
    $output_string = '';
3117
    if (!empty($_SESSION['studentview'])) {
3118
        if ($_SESSION['studentview'] == 'studentview') {
3119
            // We have to remove the isStudentView=true from the $sourceurl
3120
            $sourceurl = str_replace('&isStudentView=true', '', $sourceurl);
3121
            $sourceurl = str_replace('&isStudentView=false', '', $sourceurl);
3122
            $output_string .= '<a class="btn btn-primary btn-sm" href="'.$sourceurl.'&isStudentView=false" target="_self">'.
3123
                Display::returnFontAwesomeIcon('eye').' '.get_lang('SwitchToTeacherView').'</a>';
3124
        } elseif ($_SESSION['studentview'] == 'teacherview') {
3125
            // Switching to teacherview
3126
            $sourceurl = str_replace('&isStudentView=true', '', $sourceurl);
3127
            $sourceurl = str_replace('&isStudentView=false', '', $sourceurl);
3128
            $output_string .= '<a class="btn btn-default btn-sm" href="'.$sourceurl.'&isStudentView=true" target="_self">'.
3129
                Display::returnFontAwesomeIcon('eye').' '.get_lang('SwitchToStudentView').'</a>';
3130
        }
3131
    } else {
3132
        $output_string .= '<a class="btn btn-default btn-sm" href="'.$sourceurl.'&isStudentView=true" target="_self">'.
3133
            Display::returnFontAwesomeIcon('eye').' '.get_lang('SwitchToStudentView').'</a>';
3134
    }
3135
    $html = Display::tag('div', $output_string, ['class'=>'view-options']);
3136
    return $html;
3137
}
3138
3139
// TODO: This is for the permission section.
3140
/**
3141
 * Function that removes the need to directly use is_courseAdmin global in
3142
 * tool scripts. It returns true or false depending on the user's rights in
3143
 * this particular course.
3144
 * Optionally checking for tutor and coach roles here allows us to use the
3145
 * student_view feature altogether with these roles as well.
3146
 * @param bool  Whether to check if the user has the tutor role
3147
 * @param bool  Whether to check if the user has the coach role
3148
 * @param bool  Whether to check if the user has the session coach role
3149
 * @param bool  check the student view or not
3150
 *
3151
 * @author Roan Embrechts
3152
 * @author Patrick Cool
3153
 * @author Julio Montoya
3154
 * @version 1.1, February 2004
3155
 * @return boolean true: the user has the rights to edit, false: he does not
3156
 */
3157
3158
function api_is_allowed_to_edit(
3159
    $tutor = false,
3160
    $coach = false,
3161
    $session_coach = false,
3162
    $check_student_view = true
3163
) {
3164
    $sessionId = api_get_session_id();
3165
    $is_allowed_coach_to_edit = api_is_coach(null, null, $check_student_view);
3166
    $session_visibility = api_get_session_visibility($sessionId);
3167
3168
    // Admins can edit anything.
3169
    if (api_is_platform_admin(false)) {
3170
        //The student preview was on
3171
        if ($check_student_view && api_is_student_view_active()) {
3172
            return false;
3173
        } else {
3174
            return true;
3175
        }
3176
    }
3177
3178
    $is_courseAdmin = api_is_course_admin();
3179
3180
    if (!$is_courseAdmin && $tutor) {
3181
        // If we also want to check if the user is a tutor...
3182
        $is_courseAdmin = $is_courseAdmin || api_is_course_tutor();
3183
    }
3184
3185
    if (!$is_courseAdmin && $coach) {
3186
        // If we also want to check if the user is a coach...';
3187
        // Check if session visibility is read only for coaches.
3188
        if ($session_visibility == SESSION_VISIBLE_READ_ONLY) {
3189
            $is_allowed_coach_to_edit = false;
3190
        }
3191
3192
        if (api_get_setting('allow_coach_to_edit_course_session') == 'true') {
3193
            // Check if coach is allowed to edit a course.
3194
            $is_courseAdmin = $is_courseAdmin || $is_allowed_coach_to_edit;
3195
        }
3196
    }
3197
3198
    if (!$is_courseAdmin && $session_coach) {
3199
        $is_courseAdmin = $is_courseAdmin || $is_allowed_coach_to_edit;
3200
    }
3201
3202
    // Check if the student_view is enabled, and if so, if it is activated.
3203
    if (api_get_setting('student_view_enabled') == 'true') {
3204
        if (!empty($sessionId)) {
3205
            // Check if session visibility is read only for coaches.
3206
            if ($session_visibility == SESSION_VISIBLE_READ_ONLY) {
3207
                $is_allowed_coach_to_edit = false;
3208
            }
3209
3210
            if (api_get_setting('allow_coach_to_edit_course_session') == 'true') {
3211
                // Check if coach is allowed to edit a course.
3212
                $is_allowed = $is_allowed_coach_to_edit;
3213
            } else {
3214
                $is_allowed = false;
3215
            }
3216
            if ($check_student_view) {
3217
                $is_allowed = $is_allowed && $_SESSION['studentview'] != 'studentview';
3218
            }
3219
        } else {
3220
            if ($check_student_view) {
3221
                $is_allowed = $is_courseAdmin && $_SESSION['studentview'] != 'studentview';
3222
            } else {
3223
                $is_allowed = $is_courseAdmin;
3224
            }
3225
        }
3226
3227
        return $is_allowed;
3228
    } else {
3229
        return $is_courseAdmin;
3230
    }
3231
}
3232
3233
/**
3234
 * Returns true if user is a course coach of at least one course in session
3235
 * @param int $sessionId
3236
 * @return bool
3237
 */
3238
function api_is_coach_of_course_in_session($sessionId)
3239
{
3240
    if (api_is_platform_admin()) {
3241
        return true;
3242
    }
3243
3244
    $userId = api_get_user_id();
3245
    $courseList = UserManager::get_courses_list_by_session(
3246
        $userId,
3247
        $sessionId
3248
    );
3249
3250
    // Session visibility.
3251
    $visibility = api_get_session_visibility(
3252
        $sessionId,
3253
        null,
3254
        false
3255
    );
3256
3257
    if ($visibility != SESSION_VISIBLE && !empty($courseList)) {
3258
        // Course Coach session visibility.
3259
        $blockedCourseCount = 0;
3260
        $closedVisibilityList = [
3261
            COURSE_VISIBILITY_CLOSED,
3262
            COURSE_VISIBILITY_HIDDEN
3263
        ];
3264
3265
        foreach ($courseList as $course) {
3266
            // Checking session visibility
3267
            $sessionCourseVisibility = api_get_session_visibility(
3268
                $sessionId,
3269
                $course['real_id']
3270
            );
3271
3272
            $courseIsVisible = !in_array(
3273
                $course['visibility'],
3274
                $closedVisibilityList
3275
            );
3276
            if ($courseIsVisible === false || $sessionCourseVisibility == SESSION_INVISIBLE) {
3277
                $blockedCourseCount++;
3278
            }
3279
        }
3280
3281
        // If all courses are blocked then no show in the list.
3282
        if ($blockedCourseCount === count($courseList)) {
3283
            $visibility = SESSION_INVISIBLE;
3284
        } else {
3285
            $visibility = SESSION_VISIBLE;
3286
        }
3287
    }
3288
3289
    switch ($visibility) {
3290
        case SESSION_VISIBLE_READ_ONLY:
3291
        case SESSION_VISIBLE:
3292
        case SESSION_AVAILABLE:
3293
            return true;
3294
            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...
3295
        case SESSION_INVISIBLE:
3296
            return false;
3297
    }
3298
3299
    return false;
3300
}
3301
3302
/**
3303
 * Checks if a student can edit contents in a session depending
3304
 * on the session visibility
3305
 * @param bool $tutor  Whether to check if the user has the tutor role
3306
 * @param bool  $coach Whether to check if the user has the coach role
3307
 * @return boolean true: the user has the rights to edit, false: he does not
3308
 */
3309
function api_is_allowed_to_session_edit($tutor = false, $coach = false)
3310
{
3311
    if (api_is_allowed_to_edit($tutor, $coach)) {
3312
        // If I'm a teacher, I will return true in order to not affect the normal behaviour of Chamilo tools.
3313
        return true;
3314
    } else {
3315
        $sessionId = api_get_session_id();
3316
3317
        if ($sessionId == 0) {
3318
            // I'm not in a session so i will return true to not affect the normal behaviour of Chamilo tools.
3319
            return true;
3320
        } else {
3321
            // I'm in a session and I'm a student
3322
            // Get the session visibility
3323
            $session_visibility = api_get_session_visibility($sessionId);
3324
            // if 5 the session is still available
3325
            //@todo We could load the session_rel_course_rel_user permission to increase the level of detail.
3326
            //echo api_get_user_id();
3327
            //echo api_get_course_id();
3328
3329
            switch ($session_visibility) {
3330
                case SESSION_VISIBLE_READ_ONLY: // 1
3331
                    return false;
3332
                case SESSION_VISIBLE:           // 2
3333
                    return true;
3334
                case SESSION_INVISIBLE:         // 3
3335
                    return false;
3336
                case SESSION_AVAILABLE:         //5
3337
                    return true;
3338
            }
3339
        }
3340
    }
3341
}
3342
3343
/**
3344
 * Checks whether the user is allowed in a specific tool for a specific action
3345
 * @param string $tool the tool we are checking if the user has a certain permission
3346
 * @param string $action the action we are checking (add, edit, delete, move, visibility)
3347
 * @return bool
3348
 * @author Patrick Cool <[email protected]>, Ghent University
3349
 * @author Julio Montoya
3350
 * @version 1.0
3351
 */
3352
function api_is_allowed($tool, $action, $task_id = 0)
3353
{
3354
    $_user = api_get_user_info();
3355
    $_course = api_get_course_info();
3356
3357
    if (api_is_course_admin()) {
3358
        return true;
3359
    }
3360
3361
    if (is_array($_course) and count($_course) > 0) {
3362
        require_once api_get_path(SYS_CODE_PATH).'permissions/permissions_functions.inc.php';
3363
3364
        // Getting the permissions of this user.
3365
        if ($task_id == 0) {
3366
            $user_permissions = get_permissions('user', $_user['user_id']);
3367
            $_SESSION['total_permissions'][$_course['code']] = $user_permissions;
3368
        }
3369
3370
        // Getting the permissions of the task.
3371
        if ($task_id != 0) {
3372
            $task_permissions = get_permissions('task', $task_id);
3373
            /* !!! */$_SESSION['total_permissions'][$_course['code']] = $task_permissions;
3374
        }
3375
        //print_r($_SESSION['total_permissions']);
3376
3377
        // Getting the permissions of the groups of the user
3378
        //$groups_of_user = GroupManager::get_group_ids($_course['db_name'], $_user['user_id']);
3379
3380
        //foreach($groups_of_user as $group)
3381
        //   $this_group_permissions = get_permissions('group', $group);
3382
3383
        // Getting the permissions of the courseroles of the user
3384
        $user_courserole_permissions = get_roles_permissions('user', $_user['user_id']);
3385
3386
        // Getting the permissions of the platformroles of the user
3387
        //$user_platformrole_permissions = get_roles_permissions('user', $_user['user_id'], ', platform');
3388
3389
        // Getting the permissions of the roles of the groups of the user
3390
        //foreach($groups_of_user as $group)
3391
        //    $this_group_courserole_permissions = get_roles_permissions('group', $group);
3392
3393
        // Getting the permissions of the platformroles of the groups of the user
3394
        //foreach($groups_of_user as $group)
3395
        //    $this_group_platformrole_permissions = get_roles_permissions('group', $group, 'platform');
3396
    }
3397
3398
    // If the permissions are limited, we have to map the extended ones to the limited ones.
3399
    if (api_get_setting('permissions') == 'limited') {
3400
        if ($action == 'Visibility') {
3401
            $action = 'Edit';
3402
        }
3403
        if ($action == 'Move') {
3404
            $action = 'Edit';
3405
        }
3406
    }
3407
3408
    // The session that contains all the permissions already exists for this course
3409
    // so there is no need to requery everything.
3410
    //my_print_r($_SESSION['total_permissions'][$_course['code']][$tool]);
3411
    if (is_array($_SESSION['total_permissions'][$_course['code']][$tool])) {
3412
        if (in_array($action, $_SESSION['total_permissions'][$_course['code']][$tool])) {
3413
            return true;
3414
        } else {
3415
            return false;
3416
        }
3417
    }
3418
}
3419
3420
/**
3421
 * Tells whether this user is an anonymous user
3422
 * @param int  $user_id      User ID (optional, will take session ID if not provided)
3423
 * @param bool $db_check     Whether to check in the database (true) or simply in
3424
 * the session (false) to see if the current user is the anonymous user
3425
 * @return bool     true if this user is anonymous, false otherwise
3426
 */
3427
function api_is_anonymous($user_id = null, $db_check = false)
3428
{
3429
    if (!isset($user_id)) {
3430
        $user_id = api_get_user_id();
3431
    }
3432
3433
    if ($db_check) {
3434
        $info = api_get_user_info($user_id);
3435
        if ($info['status'] == ANONYMOUS) {
3436
            return true;
3437
        }
3438
    }
3439
3440
    $_user = api_get_user_info();
3441
3442
    if (isset($_user['status']) && $_user['status'] == ANONYMOUS) {
3443
        //if ($_user['user_id'] == 0) {
3444
        // In some cases, api_set_anonymous doesn't seem to be triggered in local.inc.php. Make sure it is.
3445
        // Occurs in agenda for admin links - YW
3446
        global $use_anonymous;
3447
        if (isset($use_anonymous) && $use_anonymous) {
3448
            api_set_anonymous();
3449
        }
3450
3451
        return true;
3452
    }
3453
3454
    return (isset($_user['is_anonymous']) && $_user['is_anonymous'] === true) || $_user === false;
3455
}
3456
3457
/**
3458
 * Displays message "You are not allowed here..." and exits the entire script.
3459
 * @param bool   $print_headers    Whether or not to print headers (default = false -> does not print them)
3460
 * @param string $message
3461
 * @param int $responseCode
3462
 */
3463
function api_not_allowed(
3464
    $print_headers = false,
3465
    $message = null,
3466
    $responseCode = 0
3467
) {
3468
    if (api_get_setting('sso_authentication') === 'true') {
3469
        global $osso;
3470
        if ($osso) {
3471
            $osso->logout();
3472
        }
3473
    }
3474
    $home_url = api_get_path(WEB_PATH);
3475
    $user_id = api_get_user_id();
3476
    $course = api_get_course_id();
3477
3478
    global $this_section;
3479
3480
    if (CustomPages::enabled() && !isset($user_id)) {
3481
        if (empty($user_id)) {
3482
            // Why the CustomPages::enabled() need to be to set the request_uri
3483
            $_SESSION['request_uri'] = $_SERVER['REQUEST_URI'];
3484
        }
3485
        CustomPages::display(CustomPages::INDEX_UNLOGGED);
3486
    }
3487
3488
    $origin = api_get_origin();
3489
3490
    $msg = null;
3491
    if (isset($message)) {
3492
        $msg = $message;
3493
    } else {
3494
        $msg = Display::return_message(
3495
            get_lang('NotAllowedClickBack').'
3496
            <script>function goBack(){window.history.back();}</script>',
3497
            'error',
3498
            false
3499
        );
3500
        $msg .= '<p class="text-center">
3501
             <a onclick="goBack();" class="btn btn-default" href="'.$home_url.'">'.get_lang('GoBack').'</a>
3502
             </p>';
3503
    }
3504
3505
    $msg = Display::div($msg, ['align'=>'center']);
3506
3507
    $show_headers = 0;
3508
    if ($print_headers && $origin != 'learnpath') {
3509
        $show_headers = 1;
3510
    }
3511
3512
    $tpl = new Template(null, $show_headers, $show_headers, false, true, false, true, $responseCode);
3513
    $tpl->assign('hide_login_link', 1);
3514
    $tpl->assign('content', $msg);
3515
3516
    if (($user_id != 0 && !api_is_anonymous()) &&
3517
        (!isset($course) || $course == -1) &&
3518
        empty($_GET['cidReq'])
3519
    ) {
3520
        // if the access is not authorized and there is some login information
3521
        // but the cidReq is not found, assume we are missing course data and send the user
3522
        // to the user_portal
3523
        $tpl->display_one_col_template();
3524
        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...
3525
    }
3526
3527
    if (!empty($_SERVER['REQUEST_URI']) &&
3528
        (
3529
            !empty($_GET['cidReq']) ||
3530
            $this_section == SECTION_MYPROFILE ||
3531
            $this_section == SECTION_PLATFORM_ADMIN
3532
        )
3533
    ) {
3534
        $courseCode = api_get_course_id();
3535
        // Only display form and return to the previous URL if there was a course ID included
3536
        if ($user_id != 0 && !api_is_anonymous()) {
3537
            //if there is a user ID, then the user is not allowed but the session is still there. Say so and exit
3538
            $tpl->assign('content', $msg);
3539
            $tpl->display_one_col_template();
3540
            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...
3541
        }
3542
3543
        if (!is_null($courseCode)) {
3544
            api_set_firstpage_parameter($courseCode);
3545
        }
3546
3547
        // If the user has no user ID, then his session has expired
3548
        $form = api_get_not_allowed_login_form();
3549
3550
        // see same text in auth/gotocourse.php and main_api.lib.php function api_not_allowed (above)
3551
        $content = Display::return_message(get_lang('NotAllowed'), 'error', false);
3552
3553
        if (!empty($courseCode)) {
3554
            $content .= '<h4>'.get_lang('LoginToGoToThisCourse').'</h4>';
3555
        }
3556
3557
        if (api_is_cas_activated()) {
3558
            $content .= Display::return_message(sprintf(get_lang('YouHaveAnInstitutionalAccount'), api_get_setting("Institution")), '', false);
3559
            $content .= Display::div(
3560
                "<br/><a href='".get_cas_direct_URL(api_get_course_id())."'>".sprintf(get_lang('LoginWithYourAccount'), api_get_setting("Institution"))."</a><br/><br/>",
3561
                ['align' => 'center']
3562
            );
3563
            $content .= Display::return_message(get_lang('YouDontHaveAnInstitutionAccount'));
3564
            $content .= "<p style='text-align:center'><a href='#' onclick='$(this).parent().next().toggle()'>".get_lang('LoginWithExternalAccount')."</a></p>";
3565
            $content .= "<div style='display:none;'>";
3566
        }
3567
        $content .= '<div class="well">';
3568
        $content .= $form->returnForm();
3569
        $content .= '</div>';
3570
        if (api_is_cas_activated()) {
3571
            $content .= "</div>";
3572
        }
3573
3574
        if (!empty($courseCode)) {
3575
            $content .= '<hr/><p style="text-align:center"><a href="'.$home_url.'">'.
3576
                get_lang('ReturnToCourseHomepage').'</a></p>';
3577
        } else {
3578
            $content .= '<hr/><p style="text-align:center"><a href="'.$home_url.'">'.
3579
                get_lang('BackHome').'</a></p>';
3580
        }
3581
3582
        $tpl->setLoginBodyClass();
3583
        $tpl->assign('content', $content);
3584
        $tpl->display_one_col_template();
3585
        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...
3586
    }
3587
3588
    if ($user_id != 0 && !api_is_anonymous()) {
3589
        $tpl->display_one_col_template();
3590
        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...
3591
    }
3592
3593
    $msg = null;
3594
    // The session is over and we were not in a course,
3595
    // or we try to get directly to a private course without being logged
3596
    $courseId = api_get_course_int_id();
3597
    if (!empty($courseId)) {
3598
        api_set_firstpage_parameter(api_get_course_id());
3599
        $tpl->setLoginBodyClass();
3600
3601
        // see same text in auth/gotocourse.php and main_api.lib.php function api_not_allowed (bellow)
3602
        $msg = Display::return_message(get_lang('NotAllowed'), 'error', false);
3603
        $msg .= '<h4>'.get_lang('LoginToGoToThisCourse').'</h4>';
3604
        $casEnabled = api_is_cas_activated();
3605
        if ($casEnabled) {
3606
            $msg .= Display::return_message(
3607
                sprintf(get_lang('YouHaveAnInstitutionalAccount'), api_get_setting("Institution")),
3608
                '',
3609
                false
3610
            );
3611
            $msg .= Display::div("<br/><a href='".get_cas_direct_URL(api_get_course_int_id())."'>".getCASLogoHTML()." ".sprintf(get_lang('LoginWithYourAccount'), api_get_setting("Institution"))."</a><br/><br/>", ['align'=>'center']);
3612
            $msg .= Display::return_message(get_lang('YouDontHaveAnInstitutionAccount'));
3613
            $msg .= "<p style='text-align:center'><a href='#' onclick='$(this).parent().next().toggle()'>".get_lang('LoginWithExternalAccount')."</a></p>";
3614
            $msg .= "<div style='display:none;'>";
3615
        }
3616
        $form = api_get_not_allowed_login_form();
3617
        $msg .= '<div class="well">';
3618
        $msg .= $form->returnForm();
3619
        $msg .= '</div>';
3620
        if ($casEnabled) {
3621
            $msg .= "</div>";
3622
        }
3623
    } else {
3624
        // we were not in a course, return to home page
3625
        $msg = Display::return_message(
3626
            get_lang('NotAllowed'),
3627
            'error',
3628
            false
3629
        );
3630
3631
        $msg .= '<p class="text-center">
3632
                 <a class="btn btn-default" href="'.$home_url.'">'.get_lang('BackHome').'</a>
3633
                 </p>';
3634
3635
        if (!empty($message)) {
3636
            $msg = $message;
3637
        }
3638
3639
        if (api_is_anonymous()) {
3640
            $form = api_get_not_allowed_login_form();
3641
            $msg .= '<div class="well">';
3642
            $msg .= $form->returnForm();
3643
            $msg .= '</div>';
3644
        }
3645
    }
3646
3647
    $tpl->assign('content', $msg);
3648
    $tpl->display_one_col_template();
3649
    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...
3650
}
3651
3652
/**
3653
 * @return FormValidator
3654
 */
3655
function api_get_not_allowed_login_form()
3656
{
3657
    $action = api_get_self().'?'.Security::remove_XSS($_SERVER['QUERY_STRING']);
3658
    $action = str_replace('&amp;', '&', $action);
3659
    Session::write('redirect_after_not_allow_page', $action);
3660
    $action .= '&redirect_after_not_allow_page=1';
3661
3662
    $form = new FormValidator(
3663
        'formLogin',
3664
        'post',
3665
        $action,
3666
        null,
3667
        ['class' => 'form-stacked']
3668
    );
3669
    $params = [
3670
        'placeholder' => get_lang('UserName'),
3671
        'class' => 'col-md-3'
3672
    ];
3673
    if (api_browser_support('autocapitalize')) {
3674
        $params['autocapitalize'] = 'none';
3675
    }
3676
3677
    $form->addElement(
3678
        'text',
3679
        'login',
3680
        null,
3681
        $params
3682
    );
3683
    $form->addElement(
3684
        'password',
3685
        'password',
3686
        null,
3687
        ['placeholder' => get_lang('Password'), 'class' => 'col-md-3']
3688
    ); //new
3689
    $form->addButtonNext(get_lang('LoginEnter'), 'submitAuth');
3690
3691
    return $form;
3692
}
3693
3694
/**
3695
 * Gets a UNIX timestamp from a database (MySQL) datetime format string
3696
 * @param $last_post_datetime standard output date in a sql query
3697
 * @return integer timestamp
3698
 * @author Toon Van Hoecke <[email protected]>
3699
 * @version October 2003
3700
 * @desc convert sql date to unix timestamp
3701
 */
3702
function convert_sql_date($last_post_datetime)
3703
{
3704
    list($last_post_date, $last_post_time) = explode(' ', $last_post_datetime);
3705
    list($year, $month, $day) = explode('-', $last_post_date);
3706
    list($hour, $min, $sec) = explode(':', $last_post_time);
3707
    return mktime((int) $hour, (int) $min, (int) $sec, (int) $month, (int) $day, (int) $year);
3708
}
3709
3710
/**
3711
 * Gets item visibility from the item_property table
3712
 *
3713
 * Getting the visibility is done by getting the last updated visibility entry,
3714
 * using the largest session ID found if session 0 and another was found (meaning
3715
 * the only one that is actually from the session, in case there are results from
3716
 * session 0 *AND* session n).
3717
 * @param array     Course properties array (result of api_get_course_info())
3718
 * @param string    Tool (learnpath, document, etc)
3719
 * @param int       The item ID in the given tool
3720
 * @param int       The session ID (optional)
3721
 * @param string $tool
3722
 * @param integer $user_id
3723
 * @param string $type
3724
 * @return int      -1 on error, 0 if invisible, 1 if visible
3725
 */
3726
function api_get_item_visibility(
3727
    $_course,
3728
    $tool,
3729
    $id,
3730
    $session = 0,
3731
    $user_id = null,
3732
    $type = null,
3733
    $group_id = null
3734
) {
3735
    if (!is_array($_course) || count($_course) == 0 || empty($tool) || empty($id)) {
3736
        return -1;
3737
    }
3738
3739
    $tool = Database::escape_string($tool);
3740
    $id = intval($id);
3741
    $session = (int) $session;
3742
    $TABLE_ITEMPROPERTY = Database::get_course_table(TABLE_ITEM_PROPERTY);
3743
    $course_id = intval($_course['real_id']);
3744
3745
    $userCondition = '';
3746
    if (!empty($user_id)) {
3747
        $user_id = intval($user_id);
3748
        $userCondition = " AND to_user_id = $user_id ";
3749
    }
3750
3751
    $typeCondition = '';
3752
    if (!empty($type)) {
3753
        $type = Database::escape_string($type);
3754
        $typeCondition = " AND lastedit_type = '$type' ";
3755
    }
3756
3757
    $groupCondition = '';
3758
    if (!empty($group_id)) {
3759
        $group_id = intval($group_id);
3760
        $groupCondition = " AND to_group_id = '$group_id' ";
3761
    }
3762
3763
    $sql = "SELECT visibility
3764
            FROM $TABLE_ITEMPROPERTY
3765
            WHERE
3766
                c_id = $course_id AND
3767
                tool = '$tool' AND
3768
                ref = $id AND
3769
                (session_id = $session OR session_id = 0 OR session_id IS NULL)
3770
                $userCondition $typeCondition $groupCondition
3771
            ORDER BY session_id DESC, lastedit_date DESC
3772
            LIMIT 1";
3773
3774
    $res = Database::query($sql);
3775
    if ($res === false || Database::num_rows($res) == 0) {
3776
        return -1;
3777
    }
3778
    $row = Database::fetch_array($res);
3779
3780
    return $row['visibility'];
3781
}
3782
3783
/**
3784
 * Delete a row in the c_item_property table
3785
 *
3786
 * @param array $courseInfo
3787
 * @param string $tool
3788
 * @param int $itemId
3789
 * @param int $userId
3790
 * @param int $groupId group.iid
3791
 * @param int $sessionId
3792
 * @return false|null
3793
 */
3794
function api_item_property_delete(
3795
    $courseInfo,
3796
    $tool,
3797
    $itemId,
3798
    $userId,
3799
    $groupId = 0,
3800
    $sessionId = 0
3801
) {
3802
    if (empty($courseInfo)) {
3803
        return false;
3804
    }
3805
3806
    $courseId = intval($courseInfo['real_id']);
3807
3808
    if (empty($courseId) || empty($tool) || empty($itemId)) {
3809
        return false;
3810
    }
3811
3812
    $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
3813
    $tool = Database::escape_string($tool);
3814
    $itemId = intval($itemId);
3815
    $userId = intval($userId);
3816
    $groupId = intval($groupId);
3817
    $sessionId = intval($sessionId);
3818
3819
    $groupCondition = " AND to_group_id = $groupId ";
3820
    if (empty($groupId)) {
3821
        $groupCondition = " AND (to_group_id is NULL OR to_group_id = 0) ";
3822
    }
3823
3824
    $userCondition = " AND to_user_id = $userId ";
3825
    if (empty($userId)) {
3826
        $userCondition = " AND (to_user_id is NULL OR to_user_id = 0) ";
3827
    }
3828
    $sessionCondition = api_get_session_condition($sessionId, true, false, 'session_id');
3829
    $sql = "DELETE FROM $table
3830
            WHERE
3831
                c_id = $courseId AND
3832
                tool  = '$tool' AND
3833
                ref = $itemId
3834
                $sessionCondition
3835
                $userCondition
3836
                $groupCondition
3837
            ";
3838
3839
    Database::query($sql);
3840
}
3841
3842
/**
3843
 * Updates or adds item properties to the Item_propetry table
3844
 * Tool and lastedit_type are language independant strings (langvars->get_lang!)
3845
 *
3846
 * @param array $_course array with course properties
3847
 * @param string $tool tool id, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
3848
 * @param int $item_id id of the item itself, linked to key of every tool ('id', ...)
3849
 * @param string $last_edit_type add or update action
3850
 * (1) message to be translated (in trad4all) : e.g. DocumentAdded, DocumentUpdated;
3851
 * (2) "delete"
3852
 * (3) "visible"
3853
 * (4) "invisible"
3854
 * @param int $user_id id of the editing/adding user
3855
 * @param array $groupInfo must include group.iid/group.od
3856
 * @param int $to_user_id id of the intended user (always has priority over $to_group_id !), only relevant for $type (1)
3857
 * @param string $start_visible 0000-00-00 00:00:00 format
3858
 * @param string $end_visible 0000-00-00 00:00:00 format
3859
 * @param int $session_id The session ID, if any, otherwise will default to 0
3860
 * @return boolean False if update fails.
3861
 * @author Toon Van Hoecke <[email protected]>, Ghent University
3862
 * @version January 2005
3863
 * @desc update the item_properties table (if entry not exists, insert) of the course
3864
 */
3865
function api_item_property_update(
3866
    $_course,
3867
    $tool,
3868
    $item_id,
3869
    $last_edit_type,
3870
    $user_id,
3871
    $groupInfo = [],
3872
    $to_user_id = null,
3873
    $start_visible = '',
3874
    $end_visible = '',
3875
    $session_id = 0
3876
) {
3877
    if (empty($_course)) {
3878
        return false;
3879
    }
3880
3881
    $course_id = $_course['real_id'];
3882
3883
    if (empty($course_id)) {
3884
        return false;
3885
    }
3886
3887
    $to_group_id = 0;
3888
    if (!empty($groupInfo) && isset($groupInfo['iid'])) {
3889
        $to_group_id = $groupInfo['iid'];
3890
    }
3891
3892
    $em = Database::getManager();
3893
3894
    // Definition of variables.
3895
    $tool = Database::escape_string($tool);
3896
    $item_id = intval($item_id);
3897
    $lastEditTypeNoFilter = $last_edit_type;
3898
    $last_edit_type = Database::escape_string($last_edit_type);
3899
    $user_id = intval($user_id);
3900
3901
    $startVisible = "NULL";
3902
    if (!empty($start_visible)) {
3903
        $start_visible = Database::escape_string($start_visible);
3904
        $startVisible = "'$start_visible'";
3905
    }
3906
3907
    $endVisible = "NULL";
3908
    if (!empty($end_visible)) {
3909
        $end_visible = Database::escape_string($end_visible);
3910
        $endVisible = "'$end_visible'";
3911
    }
3912
3913
    $to_filter = '';
3914
    $time = api_get_utc_datetime();
3915
3916
    if (!empty($session_id)) {
3917
        $session_id = intval($session_id);
3918
    } else {
3919
        $session_id = api_get_session_id();
3920
    }
3921
3922
    // Definition of tables.
3923
    $tableItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
3924
3925
    if ($to_user_id <= 0) {
3926
        $to_user_id = null; // No to_user_id set
3927
    }
3928
3929
    if (!is_null($to_user_id)) {
3930
        // $to_user_id has more priority than $to_group_id
3931
        $to_user_id = intval($to_user_id);
3932
        $to_field = 'to_user_id';
3933
        $to_value = $to_user_id;
3934
    } else {
3935
        // $to_user_id is not set.
3936
        $to_field = 'to_group_id';
3937
        $to_value = $to_group_id;
3938
    }
3939
3940
    $toValueCondition = empty($to_value) ? "NULL" : "'$to_value'";
3941
    // Set filters for $to_user_id and $to_group_id, with priority for $to_user_id
3942
    $condition_session = " AND session_id = $session_id ";
3943
    if (empty($session_id)) {
3944
        $condition_session = " AND (session_id = 0 OR session_id IS NULL) ";
3945
    }
3946
3947
    $filter = " c_id = $course_id AND tool = '$tool' AND ref = $item_id $condition_session ";
3948
3949
    // Check whether $to_user_id and $to_group_id are passed in the function call.
3950
    // If both are not passed (both are null) then it is a message for everybody and $to_group_id should be 0 !
3951
    if (is_null($to_user_id) && is_null($to_group_id)) {
3952
        $to_group_id = 0;
3953
    }
3954
3955
    if (!is_null($to_user_id)) {
3956
        // Set filter to intended user.
3957
        $to_filter = " AND to_user_id = $to_user_id $condition_session";
3958
    } else {
3959
        // Set filter to intended group.
3960
        if (($to_group_id != 0) && $to_group_id == strval(intval($to_group_id))) {
3961
            $to_filter = " AND to_group_id = $to_group_id $condition_session";
3962
        }
3963
    }
3964
3965
    // Adding filter if set.
3966
    $filter .= $to_filter;
3967
3968
    // Update if possible
3969
    $set_type = '';
3970
3971
    switch ($lastEditTypeNoFilter) {
3972
        case 'delete':
3973
            // delete = make item only visible for the platform admin.
3974
            $visibility = '2';
3975
            if (!empty($session_id)) {
3976
                // Check whether session id already exist into item_properties for updating visibility or add it.
3977
                $sql = "SELECT session_id FROM $tableItemProperty
3978
                        WHERE
3979
                            c_id = $course_id AND
3980
                            tool = '$tool' AND
3981
                            ref = $item_id AND
3982
                            session_id = $session_id";
3983
                $rs = Database::query($sql);
3984
                if (Database::num_rows($rs) > 0) {
3985
                    $sql = "UPDATE $tableItemProperty
3986
                            SET lastedit_type       = '".str_replace('_', '', ucwords($tool))."Deleted',
3987
                                lastedit_date       = '$time',
3988
                                lastedit_user_id    = $user_id,
3989
                                visibility          = $visibility,
3990
                                session_id          = $session_id $set_type
3991
                            WHERE $filter";
3992
                    $result = Database::query($sql);
3993
                } else {
3994
                    $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)
3995
                            VALUES ($course_id, '$tool',$item_id, '$time', $user_id, '$time', '$last_edit_type',$user_id, $toValueCondition, $visibility, $startVisible, $endVisible, $session_id)";
3996
                    $result = Database::query($sql);
3997
                    $id = Database::insert_id();
3998
                    if ($id) {
3999
                        $sql = "UPDATE $tableItemProperty SET id = iid WHERE iid = $id";
4000
                        Database::query($sql);
4001
                    }
4002
                }
4003
            } else {
4004
                $sql = "UPDATE $tableItemProperty
4005
                        SET
4006
                            lastedit_type='".str_replace('_', '', ucwords($tool))."Deleted',
4007
                            lastedit_date='$time',
4008
                            lastedit_user_id = $user_id,
4009
                            visibility = $visibility $set_type
4010
                        WHERE $filter";
4011
                $result = Database::query($sql);
4012
            }
4013
            break;
4014
        case 'visible': // Change item to visible.
4015
            $visibility = '1';
4016
            if (!empty($session_id)) {
4017
                // Check whether session id already exist into item_properties for updating visibility or add it.
4018
                $sql = "SELECT session_id FROM $tableItemProperty
4019
                        WHERE
4020
                            c_id = $course_id AND
4021
                            tool = '$tool' AND
4022
                            ref = $item_id AND
4023
                            session_id = $session_id";
4024
                $rs = Database::query($sql);
4025
                if (Database::num_rows($rs) > 0) {
4026
                    $sql = "UPDATE $tableItemProperty
4027
                            SET
4028
                                lastedit_type='".str_replace('_', '', ucwords($tool))."Visible',
4029
                                lastedit_date='$time',
4030
                                lastedit_user_id = $user_id,
4031
                                visibility = $visibility,
4032
                                session_id = $session_id $set_type
4033
                            WHERE $filter";
4034
                    $result = Database::query($sql);
4035
                } else {
4036
                    $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)
4037
                            VALUES ($course_id, '$tool', $item_id, '$time', $user_id, '$time', '$last_edit_type', $user_id, $toValueCondition, $visibility, $startVisible, $endVisible, $session_id)";
4038
                    $result = Database::query($sql);
4039
                    $id = Database::insert_id();
4040
                    if ($id) {
4041
                        $sql = "UPDATE $tableItemProperty SET id = iid WHERE iid = $id";
4042
                        Database::query($sql);
4043
                    }
4044
                }
4045
            } else {
4046
                $sql = "UPDATE $tableItemProperty
4047
                        SET
4048
                            lastedit_type='".str_replace('_', '', ucwords($tool))."Visible',
4049
                            lastedit_date='$time',
4050
                            lastedit_user_id = $user_id,
4051
                            visibility = $visibility $set_type
4052
                        WHERE $filter";
4053
                $result = Database::query($sql);
4054
            }
4055
            break;
4056
        case 'invisible': // Change item to invisible.
4057
            $visibility = '0';
4058
            if (!empty($session_id)) {
4059
                // Check whether session id already exist into item_properties for updating visibility or add it
4060
                $sql = "SELECT session_id FROM $tableItemProperty
4061
                        WHERE
4062
                            c_id = $course_id AND
4063
                            tool = '$tool' AND
4064
                            ref = $item_id AND
4065
                            session_id = $session_id";
4066
                $rs = Database::query($sql);
4067
                if (Database::num_rows($rs) > 0) {
4068
                    $sql = "UPDATE $tableItemProperty
4069
                            SET
4070
                                lastedit_type = '".str_replace('_', '', ucwords($tool))."Invisible',
4071
                                lastedit_date = '$time',
4072
                                lastedit_user_id = $user_id,
4073
                                visibility = $visibility,
4074
                                session_id = $session_id $set_type
4075
                            WHERE $filter";
4076
                    $result = Database::query($sql);
4077
                } else {
4078
                    $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)
4079
                            VALUES ($course_id, '$tool', $item_id, '$time', $user_id, '$time', '$last_edit_type', $user_id, $toValueCondition, $visibility, $startVisible, $endVisible, $session_id)";
4080
                    $result = Database::query($sql);
4081
                    $id = Database::insert_id();
4082
                    if ($id) {
4083
                        $sql = "UPDATE $tableItemProperty SET id = iid WHERE iid = $id";
4084
                        Database::query($sql);
4085
                    }
4086
                }
4087
            } else {
4088
                $sql = "UPDATE $tableItemProperty
4089
                        SET
4090
                            lastedit_type = '".str_replace('_', '', ucwords($tool))."Invisible',
4091
                            lastedit_date = '$time',
4092
                            lastedit_user_id = $user_id,
4093
                            visibility = $visibility $set_type
4094
                        WHERE $filter";
4095
                $result = Database::query($sql);
4096
            }
4097
            break;
4098
        default: // The item will be added or updated.
4099
            $set_type = ", lastedit_type = '$last_edit_type' ";
4100
            $visibility = '1';
4101
            //$filter .= $to_filter; already added
4102
            $sql = "UPDATE $tableItemProperty
4103
                    SET
4104
                      lastedit_date = '$time',
4105
                      lastedit_user_id = $user_id $set_type
4106
                    WHERE $filter";
4107
            $result = Database::query($sql);
4108
    }
4109
4110
    // Insert if no entries are found (can only happen in case of $last_edit_type switch is 'default').
4111
    if ($result == false || Database::affected_rows($result) == 0) {
4112
        $objCourse = $em->find('ChamiloCoreBundle:Course', intval($course_id));
4113
        $objTime = new DateTime('now', new DateTimeZone('UTC'));
4114
        $objUser = api_get_user_entity($user_id);
4115
        if (empty($objUser)) {
4116
            // Use anonymous
4117
            $user_id = api_get_anonymous_id();
4118
            $objUser = api_get_user_entity($user_id);
4119
        }
4120
        $objGroup = $em->find('ChamiloCourseBundle:CGroupInfo', intval($to_group_id));
4121
        $objToUser = api_get_user_entity($to_user_id);
4122
        $objSession = $em->find('ChamiloCoreBundle:Session', intval($session_id));
4123
4124
        $startVisibleDate = !empty($start_visible) ? new DateTime($start_visible, new DateTimeZone('UTC')) : null;
4125
        $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...
4126
4127
        $cItemProperty = new CItemProperty($objCourse);
4128
        $cItemProperty
4129
            ->setTool($tool)
4130
            ->setRef($item_id)
4131
            ->setInsertDate($objTime)
4132
            ->setInsertUser($objUser)
4133
            ->setLasteditDate($objTime)
4134
            ->setLasteditType($last_edit_type)
4135
            ->setGroup($objGroup)
4136
            ->setToUser($objToUser)
4137
            ->setVisibility($visibility)
4138
            ->setStartVisible($startVisibleDate)
4139
            ->setEndVisible($endVisibleDate)
4140
            ->setSession($objSession);
4141
4142
        $em->persist($cItemProperty);
4143
        $em->flush();
4144
4145
        $id = $cItemProperty->getIid();
4146
4147
        if ($id) {
4148
            $cItemProperty->setId($id);
4149
            $em->merge($cItemProperty);
4150
            $em->flush();
4151
4152
            return false;
4153
        }
4154
    }
4155
4156
    return true;
4157
}
4158
4159
/**
4160
 * Gets item property by tool
4161
 * @param string    course code
4162
 * @param string    tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4163
 * @param int       id of the item itself, linked to key of every tool ('id', ...), "*" = all items of the tool
4164
 * @param int $session_id
4165
 * @param string $tool
4166
 * @param string $course_code
4167
 * @return array All fields from c_item_property (all rows found) or empty array
4168
 */
4169
function api_get_item_property_by_tool($tool, $course_code, $session_id = null)
4170
{
4171
    $course_info = api_get_course_info($course_code);
4172
    $tool = Database::escape_string($tool);
4173
4174
    // Definition of tables.
4175
    $item_property_table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4176
    $session_id = intval($session_id);
4177
    $session_condition = ' AND session_id = '.$session_id;
4178
    if (empty($session_id)) {
4179
        $session_condition = " AND (session_id = 0 OR session_id IS NULL) ";
4180
    }
4181
    $course_id = $course_info['real_id'];
4182
4183
    $sql = "SELECT * FROM $item_property_table
4184
            WHERE
4185
                c_id = $course_id AND
4186
                tool = '$tool'
4187
                $session_condition ";
4188
    $rs = Database::query($sql);
4189
    $list = [];
4190
    if (Database::num_rows($rs) > 0) {
4191
        while ($row = Database::fetch_array($rs, 'ASSOC')) {
4192
            $list[] = $row;
4193
        }
4194
    }
4195
    return $list;
4196
}
4197
4198
/**
4199
 * Gets item property by tool and user
4200
 * @param int $userId
4201
 * @param int $tool
4202
 * @param int $courseId
4203
 * @param int $session_id
4204
 * @return array
4205
 */
4206
function api_get_item_property_list_by_tool_by_user(
4207
    $userId,
4208
    $tool,
4209
    $courseId,
4210
    $session_id = 0
4211
) {
4212
    $userId = intval($userId);
4213
    $tool = Database::escape_string($tool);
4214
    $session_id = intval($session_id);
4215
    $courseId = intval($courseId);
4216
4217
    // Definition of tables.
4218
    $item_property_table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4219
    $session_condition = ' AND session_id = '.$session_id;
4220
    if (empty($session_id)) {
4221
        $session_condition = " AND (session_id = 0 OR session_id IS NULL) ";
4222
    }
4223
    $sql = "SELECT * FROM $item_property_table
4224
            WHERE
4225
                insert_user_id = $userId AND
4226
                c_id = $courseId AND
4227
                tool = '$tool'
4228
                $session_condition ";
4229
4230
    $rs = Database::query($sql);
4231
    $list = [];
4232
    if (Database::num_rows($rs) > 0) {
4233
        while ($row = Database::fetch_array($rs, 'ASSOC')) {
4234
            $list[] = $row;
4235
        }
4236
    }
4237
4238
    return $list;
4239
}
4240
4241
/**
4242
 * Gets item property id from tool of a course
4243
 * @param string $course_code course code
4244
 * @param string $tool tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4245
 * @param int $ref id of the item itself, linked to key of every tool ('id', ...), "*" = all items of the tool
4246
 * @param int $sessionId Session ID (optional)
4247
 * @return int
4248
 */
4249
function api_get_item_property_id($course_code, $tool, $ref, $sessionId = 0)
4250
{
4251
    $course_info = api_get_course_info($course_code);
4252
    $tool = Database::escape_string($tool);
4253
    $ref = intval($ref);
4254
4255
    // Definition of tables.
4256
    $tableItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
4257
    $course_id = $course_info['real_id'];
4258
    $sessionId = (int) $sessionId;
4259
    $sessionCondition = " AND session_id = $sessionId ";
4260
    if (empty($sessionId)) {
4261
        $sessionCondition = " AND (session_id = 0 OR session_id IS NULL) ";
4262
    }
4263
    $sql = "SELECT id FROM $tableItemProperty
4264
            WHERE
4265
                c_id = $course_id AND
4266
                tool = '$tool' AND
4267
                ref = $ref
4268
                $sessionCondition";
4269
    $rs = Database::query($sql);
4270
    $item_property_id = '';
4271
    if (Database::num_rows($rs) > 0) {
4272
        $row = Database::fetch_array($rs);
4273
        $item_property_id = $row['id'];
4274
    }
4275
    return $item_property_id;
4276
}
4277
4278
/**
4279
 * Inserts a record in the track_e_item_property table (No update)
4280
 * @param string $tool
4281
 * @param int $ref
4282
 * @param string $title
4283
 * @param string $content
4284
 * @param int $progress
4285
 * @return bool|int
4286
 */
4287
function api_track_item_property_update($tool, $ref, $title, $content, $progress)
4288
{
4289
    $tbl_stats_item_property = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ITEM_PROPERTY);
4290
    $course_id = api_get_course_int_id(); //numeric
4291
    $course_code = api_get_course_id(); //alphanumeric
4292
    $item_property_id = api_get_item_property_id($course_code, $tool, $ref);
4293
    if (!empty($item_property_id)) {
4294
        $sql = "INSERT IGNORE INTO $tbl_stats_item_property SET
4295
                course_id           = '$course_id',
4296
                item_property_id    = '$item_property_id',
4297
                title               = '".Database::escape_string($title)."',
4298
                content             = '".Database::escape_string($content)."',
4299
                progress            = '".intval($progress)."',
4300
                lastedit_date       = '".api_get_utc_datetime()."',
4301
                lastedit_user_id    = '".api_get_user_id()."',
4302
                session_id          = '".api_get_session_id()."'";
4303
        $result = Database::query($sql);
4304
        $affected_rows = Database::affected_rows($result);
4305
4306
        return $affected_rows;
4307
    }
4308
4309
    return false;
4310
}
4311
4312
/**
4313
 * @param string $tool
4314
 * @param int $ref
4315
 * @return array|resource
4316
 */
4317
function api_get_track_item_property_history($tool, $ref)
4318
{
4319
    $tbl_stats_item_property = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ITEM_PROPERTY);
4320
    $course_id = api_get_course_int_id(); //numeric
4321
    $course_code = api_get_course_id(); //alphanumeric
4322
    $item_property_id = api_get_item_property_id($course_code, $tool, $ref);
4323
    $sql = "SELECT * FROM $tbl_stats_item_property
4324
            WHERE item_property_id = $item_property_id AND course_id = $course_id
4325
            ORDER BY lastedit_date DESC";
4326
    $result = Database::query($sql);
4327
    if ($result === false or $result === null) {
4328
        $result = [];
4329
    } else {
4330
        $result = Database::store_result($result, 'ASSOC');
4331
    }
4332
4333
    return $result;
4334
}
4335
4336
/**
4337
 * Gets item property data from tool of a course id
4338
 * @param int $course_id
4339
 * @param string $tool   tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4340
 * @param int $ref id of the item itself, linked to key of every tool ('id', ...), "*" = all items of the tool
4341
 * @param int $session_id
4342
 * @param int $groupId
4343
 *
4344
 * @return array with all fields from c_item_property, empty array if not found or false if course could not be found
4345
 */
4346
function api_get_item_property_info($course_id, $tool, $ref, $session_id = 0, $groupId = 0)
4347
{
4348
    $courseInfo = api_get_course_info_by_id($course_id);
4349
4350
    if (empty($courseInfo)) {
4351
        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...
4352
    }
4353
4354
    $tool = Database::escape_string($tool);
4355
    $ref = intval($ref);
4356
    $course_id = $courseInfo['real_id'];
4357
    $session_id = intval($session_id);
4358
4359
    $sessionCondition = " session_id = $session_id";
4360
    if (empty($session_id)) {
4361
        $sessionCondition = " (session_id = 0 OR session_id IS NULL) ";
4362
    }
4363
4364
    // Definition of tables.
4365
    $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4366
4367
    $sql = "SELECT * FROM $table
4368
            WHERE
4369
                c_id = $course_id AND
4370
                tool = '$tool' AND
4371
                ref = $ref AND
4372
                $sessionCondition ";
4373
4374
    if (!empty($groupId)) {
4375
        $groupId = intval($groupId);
4376
        $sql .= " AND to_group_id = $groupId ";
4377
    }
4378
4379
    $rs  = Database::query($sql);
4380
    $row = [];
4381
    if (Database::num_rows($rs) > 0) {
4382
        $row = Database::fetch_array($rs, 'ASSOC');
4383
    }
4384
4385
    return $row;
4386
}
4387
4388
/**
4389
 * Displays a combo box so the user can select his/her preferred language.
4390
 * @param string The desired name= value for the select
4391
 * @param bool Whether we use the JQuery Chozen library or not
4392
 * (in some cases, like the indexing language picker, it can alter the presentation)
4393
 * @return string
4394
 */
4395
function api_get_languages_combo($name = 'language')
4396
{
4397
    $ret = '';
4398
    $platformLanguage = api_get_setting('platformLanguage');
4399
4400
    // Retrieve a complete list of all the languages.
4401
    $language_list = api_get_languages();
4402
4403
    if (count($language_list['name']) < 2) {
4404
        return $ret;
4405
    }
4406
4407
    // The the current language of the user so that his/her language occurs as selected in the dropdown menu.
4408
    if (isset($_SESSION['user_language_choice'])) {
4409
        $default = $_SESSION['user_language_choice'];
4410
    } else {
4411
        $default = $platformLanguage;
4412
    }
4413
4414
    $languages = $language_list['name'];
4415
    $folder = $language_list['folder'];
4416
4417
    $ret .= '<select name="'.$name.'" id="language_chosen" class="selectpicker show-tick form-control">';
4418
    foreach ($languages as $key => $value) {
4419
        if ($folder[$key] == $default) {
4420
            $selected = ' selected="selected"';
4421
        } else {
4422
            $selected = '';
4423
        }
4424
        $ret .= sprintf('<option value=%s" %s>%s</option>', $folder[$key], $selected, $value);
4425
    }
4426
    $ret .= '</select>';
4427
4428
    return $ret;
4429
}
4430
4431
/**
4432
 * Displays a form (drop down menu) so the user can select his/her preferred language.
4433
 * The form works with or without javascript
4434
 * @param  boolean Hide form if only one language available (defaults to false = show the box anyway)
4435
 * @param bool $showAsButton
4436
 * @return null|string Display the box directly
4437
 */
4438
function api_display_language_form($hide_if_no_choice = false, $showAsButton = false)
4439
{
4440
    // Retrieve a complete list of all the languages.
4441
    $language_list = api_get_languages();
4442
4443
    if (count($language_list) <= 1 && $hide_if_no_choice) {
4444
        return; //don't show any form
4445
    }
4446
4447
    // The the current language of the user so that his/her language occurs as selected in the dropdown menu.
4448
    if (isset($_SESSION['user_language_choice'])) {
4449
        $user_selected_language = $_SESSION['user_language_choice'];
4450
    }
4451
    if (empty($user_selected_language)) {
4452
        $user_selected_language = api_get_setting('platformLanguage');
4453
    }
4454
4455
    $currentLanguageId = api_get_language_id($user_selected_language);
4456
    $currentLanguageInfo = api_get_language_info($currentLanguageId);
4457
    $countryCode = languageToCountryIsoCode($currentLanguageInfo['isocode']);
4458
    $url = api_get_self();
4459
    if ($showAsButton) {
4460
        $html = '<div class="btn-group">
4461
              <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
4462
                <span class="flag-icon flag-icon-'.$countryCode.'"></span>
4463
                '.$currentLanguageInfo['original_name'].'
4464
                <span class="caret">
4465
                </span>
4466
              </button>';
4467
    } else {
4468
        $html = '
4469
            <a href="'.$url.'" class="dropdown-toggle" data-toggle="dropdown" role="button">
4470
                <span class="flag-icon flag-icon-'.$countryCode.'"></span> 
4471
                '.$currentLanguageInfo['original_name'].'
4472
                <span class="caret"></span>
4473
            </a>
4474
            ';
4475
    }
4476
4477
    $html .= '<ul class="dropdown-menu" role="menu">';
4478
    foreach ($language_list['all'] as $key => $data) {
4479
        $urlLink = $url.'?language='.$data['english_name'];
4480
        $html .= '<li><a href="'.$urlLink.'"><span class="flag-icon flag-icon-'.languageToCountryIsoCode($data['isocode']).'"></span> '.$data['original_name'].'</a></li>';
4481
    }
4482
    $html .= '</ul>';
4483
4484
    if ($showAsButton) {
4485
        $html .= '</div>';
4486
    }
4487
4488
    return $html;
4489
}
4490
4491
/**
4492
 * @param string $languageIsoCode
4493
 * @return string
4494
 */
4495
function languageToCountryIsoCode($languageIsoCode)
4496
{
4497
    // @todo save in DB
4498
    switch ($languageIsoCode) {
4499
        case 'ko':
4500
            $country = 'kr';
4501
            break;
4502
        case 'ja':
4503
            $country = 'jp';
4504
            break;
4505
        case 'ca':
4506
            $country = 'es';
4507
            break;
4508
        case 'gl':
4509
            $country = 'es';
4510
            break;
4511
        case 'ka':
4512
            $country = 'ge';
4513
            break;
4514
        case 'sl':
4515
            $country = 'si';
4516
            break;
4517
        case 'eu':
4518
            $country = 'es';
4519
            break;
4520
        case 'cs':
4521
            $country = 'cz';
4522
            break;
4523
        case 'el':
4524
            $country = 'ae';
4525
            break;
4526
        case 'ar':
4527
            $country = 'ae';
4528
            break;
4529
        case 'en':
4530
            $country = 'gb';
4531
            break;
4532
        case 'he':
4533
            $country = 'il';
4534
            break;
4535
        case 'uk':
4536
            $country = 'ua'; //Ukraine
4537
            break;
4538
        case 'da':
4539
            $country = 'dk';
4540
            break;
4541
        case 'pt-BR':
4542
            $country = 'br';
4543
            break;
4544
        case 'qu':
4545
            $country = 'pe';
4546
            break;
4547
        case 'sv':
4548
            $country = 'se';
4549
            break;
4550
        case 'zh-TW':
4551
        case 'zh':
4552
            $country = 'cn';
4553
            break;
4554
        default:
4555
            $country = $languageIsoCode;
4556
            break;
4557
    }
4558
    $country = strtolower($country);
4559
    return $country;
4560
}
4561
4562
4563
/**
4564
 * Returns a list of all the languages that are made available by the admin.
4565
 * @return array An array with all languages. Structure of the array is
4566
 *  array['name'] = An array with the name of every language
4567
 *  array['folder'] = An array with the corresponding names of the language-folders in the filesystem
4568
 */
4569
function api_get_languages()
4570
{
4571
    $tbl_language = Database::get_main_table(TABLE_MAIN_LANGUAGE);
4572
    $sql = "SELECT * FROM $tbl_language WHERE available='1' 
4573
            ORDER BY original_name ASC";
4574
    $result = Database::query($sql);
4575
    $language_list = [];
4576
    while ($row = Database::fetch_array($result)) {
4577
        $language_list[$row['isocode']] = $row['original_name'];
4578
    }
4579
    return $language_list;
4580
}
4581
4582
/**
4583
 * Returns a list of all the languages that are made available by the admin.
4584
 * @return array
4585
 */
4586
function api_get_languages_to_array()
4587
{
4588
    $tbl_language = Database::get_main_table(TABLE_MAIN_LANGUAGE);
4589
    $sql = "SELECT * FROM $tbl_language WHERE available='1' ORDER BY original_name ASC";
4590
    $result = Database::query($sql);
4591
    $languages = [];
4592
    while ($row = Database::fetch_array($result)) {
4593
        $languages[$row['dokeos_folder']] = $row['original_name'];
4594
    }
4595
    return $languages;
4596
}
4597
4598
/**
4599
 * Returns the id (the database id) of a language
4600
 * @param   string  language name (the corresponding name of the language-folder in the filesystem)
4601
 * @return  int     id of the language
4602
 */
4603
function api_get_language_id($language)
4604
{
4605
    $tbl_language = Database::get_main_table(TABLE_MAIN_LANGUAGE);
4606
    if (empty($language)) {
4607
        return null;
4608
    }
4609
    $language = Database::escape_string($language);
4610
    $sql = "SELECT id FROM $tbl_language
4611
            WHERE dokeos_folder = '$language' LIMIT 1";
4612
    $result = Database::query($sql);
4613
    $row = Database::fetch_array($result);
4614
    return $row['id'];
4615
}
4616
4617
/**
4618
 * Gets language of the requested type for the current user. Types are :
4619
 * user_profil_lang : profile language of current user
4620
 * user_select_lang : language selected by user at login
4621
 * course_lang : language of the current course
4622
 * platform_lang : default platform language
4623
 * @param string $lang_type
4624
 * @return string
4625
 **/
4626
function api_get_language_from_type($lang_type)
4627
{
4628
    $return = false;
4629
    switch ($lang_type) {
4630
        case 'platform_lang':
4631
            $temp_lang = api_get_setting('platformLanguage');
4632
            if (!empty($temp_lang)) {
4633
                $return = $temp_lang;
4634
            }
4635
            break;
4636
        case 'user_profil_lang':
4637
            $_user = api_get_user_info();
4638
            if (isset($_user['language']) && !empty($_user['language'])) {
4639
                $return = $_user['language'];
4640
            }
4641
            break;
4642
        case 'user_selected_lang':
4643
            if (isset($_SESSION['user_language_choice']) && !empty($_SESSION['user_language_choice'])) {
4644
                $return = $_SESSION['user_language_choice'];
4645
            }
4646
            break;
4647
        case 'course_lang':
4648
            global $_course;
4649
            $cidReq = null;
4650
            if (empty($_course)) {
4651
                // Code modified because the local.inc.php file it's declarated after this work
4652
                // causing the function api_get_course_info() returns a null value
4653
                $cidReq = isset($_GET["cidReq"]) ? Database::escape_string($_GET["cidReq"]) : null;
4654
                $cDir = (!empty($_GET['cDir']) ? $_GET['cDir'] : null);
4655
                if (empty($cidReq) && !empty($cDir)) {
4656
                    $c = CourseManager::getCourseCodeFromDirectory($cDir);
4657
                    if ($c) {
4658
                        $cidReq = $c;
4659
                    }
4660
                }
4661
            }
4662
            $_course = api_get_course_info($cidReq);
4663
            if (isset($_course['language']) && !empty($_course['language'])) {
4664
                $return = $_course['language'];
4665
                $showCourseInUserLanguage = api_get_course_setting('show_course_in_user_language');
4666
                if ($showCourseInUserLanguage == 1) {
4667
                    $userInfo = api_get_user_info();
4668
                    if (isset($userInfo['language'])) {
4669
                        $return = $userInfo['language'];
4670
                    }
4671
                }
4672
            }
4673
            break;
4674
        default:
4675
            $return = false;
4676
            break;
4677
    }
4678
4679
    return $return;
4680
}
4681
4682
/**
4683
 * Get the language information by its id
4684
 * @param int $languageId
4685
 * @return array
4686
 */
4687
function api_get_language_info($languageId)
4688
{
4689
    $language = Database::getManager()
4690
        ->find('ChamiloCoreBundle:Language', intval($languageId));
4691
4692
    if (!$language) {
4693
        return [];
4694
    }
4695
4696
    return [
4697
        'id' => $language->getId(),
4698
        'original_name' => $language->getOriginalName(),
4699
        'english_name' => $language->getEnglishName(),
4700
        'isocode' => $language->getIsocode(),
4701
        'dokeos_folder' => $language->getDokeosFolder(),
4702
        'available' => $language->getAvailable(),
4703
        'parent_id' => $language->getParent() ? $language->getParent()->getId() : null
4704
    ];
4705
}
4706
4707
/**
4708
 * Returns the name of the visual (CSS) theme to be applied on the current page.
4709
 * The returned name depends on the platform, course or user -wide settings.
4710
 * @return string The visual theme's name, it is the name of a folder inside web/css/themes
4711
 */
4712
function api_get_visual_theme()
4713
{
4714
    static $visual_theme;
4715
    if (!isset($visual_theme)) {
4716
        // Get style directly from DB
4717
        $styleFromDatabase = api_get_settings_params_simple(
4718
            [
4719
                'variable = ? AND access_url = ?' => [
4720
                    'stylesheets',
4721
                    api_get_current_access_url_id(),
4722
                ],
4723
            ]
4724
        );
4725
        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...
4726
            $platform_theme = $styleFromDatabase['selected_value'];
4727
        } else {
4728
            $platform_theme = api_get_setting('stylesheets');
4729
        }
4730
4731
        // Platform's theme.
4732
        $visual_theme = $platform_theme;
4733
        if (api_get_setting('user_selected_theme') == 'true') {
4734
            $user_info = api_get_user_info();
4735
            if (isset($user_info['theme'])) {
4736
                $user_theme = $user_info['theme'];
4737
4738
                if (!empty($user_theme)) {
4739
                    $visual_theme = $user_theme;
4740
                    // User's theme.
4741
                }
4742
            }
4743
        }
4744
4745
        $course_id = api_get_course_id();
4746
        if (!empty($course_id) && $course_id != -1) {
4747
            if (api_get_setting('allow_course_theme') == 'true') {
4748
                $course_theme = api_get_course_setting('course_theme');
4749
4750
                if (!empty($course_theme) && $course_theme != -1) {
4751
                    if (!empty($course_theme)) {
4752
                        // Course's theme.
4753
                        $visual_theme = $course_theme;
4754
                    }
4755
                }
4756
4757
                $allow_lp_theme = api_get_course_setting('allow_learning_path_theme');
4758
                if ($allow_lp_theme == 1) {
4759
                    global $lp_theme_css, $lp_theme_config;
4760
                    // These variables come from the file lp_controller.php.
4761
                    if (!$lp_theme_config) {
4762
                        if (!empty($lp_theme_css)) {
4763
                            // LP's theme.
4764
                            $visual_theme = $lp_theme_css;
4765
                        }
4766
                    }
4767
                }
4768
            }
4769
        }
4770
4771
        if (empty($visual_theme)) {
4772
            $visual_theme = 'chamilo';
4773
        }
4774
4775
        global $lp_theme_log;
4776
        if ($lp_theme_log) {
4777
            $visual_theme = $platform_theme;
4778
        }
4779
    }
4780
4781
    return $visual_theme;
4782
}
4783
4784
/**
4785
 * Returns a list of CSS themes currently available in the CSS folder
4786
 * The folder must have a default.css file
4787
 * @param bool $getOnlyThemeFromVirtualInstance Used by the vchamilo plugin
4788
 * @return array        List of themes directories from the css folder
4789
 * Note: Directory names (names of themes) in the file system should contain ASCII-characters only.
4790
 */
4791
function api_get_themes($getOnlyThemeFromVirtualInstance = false)
4792
{
4793
    // This configuration value is set by the vchamilo plugin
4794
    $virtualTheme = api_get_configuration_value('virtual_css_theme_folder');
4795
4796
    $readCssFolder = function ($dir) use ($virtualTheme) {
4797
        $finder = new Finder();
4798
        $themes = $finder->directories()->in($dir)->depth(0)->sortByName();
4799
        $list = [];
4800
        /** @var Symfony\Component\Finder\SplFileInfo $theme */
4801
        foreach ($themes as $theme) {
4802
            $folder = $theme->getFilename();
4803
            // A theme folder is consider if there's a default.css file
4804
            if (!file_exists($theme->getPathname().'/default.css')) {
4805
                continue;
4806
            }
4807
            $name = ucwords(str_replace('_', ' ', $folder));
4808
            if ($folder == $virtualTheme) {
4809
                continue;
4810
            }
4811
            $list[$folder] = $name;
4812
        }
4813
        return $list;
4814
    };
4815
4816
    $dir = api_get_path(SYS_CSS_PATH).'themes/';
4817
    $list = $readCssFolder($dir);
4818
4819
    if (!empty($virtualTheme)) {
4820
        $newList = $readCssFolder($dir.'/'.$virtualTheme);
4821
        if ($getOnlyThemeFromVirtualInstance) {
4822
            return $newList;
4823
        }
4824
        $list = $list + $newList;
4825
        asort($list);
4826
    }
4827
4828
    return $list;
4829
}
4830
4831
/**
4832
 * Find the largest sort value in a given user_course_category
4833
 * This function is used when we are moving a course to a different category
4834
 * and also when a user subscribes to courses (the new course is added at the end of the main category
4835
 * @author Patrick Cool <[email protected]>, Ghent University
4836
 * @param int $user_course_category the id of the user_course_category
4837
 * @param integer $user_id
4838
 * @return int the value of the highest sort of the user_course_category
4839
 */
4840
function api_max_sort_value($user_course_category, $user_id)
4841
{
4842
    $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4843
    $sql = "SELECT max(sort) as max_sort FROM $tbl_course_user
4844
            WHERE
4845
                user_id='".intval($user_id)."' AND
4846
                relation_type<>".COURSE_RELATION_TYPE_RRHH." AND
4847
                user_course_cat='".intval($user_course_category)."'";
4848
    $result_max = Database::query($sql);
4849
    if (Database::num_rows($result_max) == 1) {
4850
        $row_max = Database::fetch_array($result_max);
4851
        return $row_max['max_sort'];
4852
    }
4853
    return 0;
4854
}
4855
4856
/**
4857
 * Transforms a number of seconds in hh:mm:ss format
4858
 * @author Julian Prud'homme
4859
 * @param integer the number of seconds
4860
 * @return string the formated time
4861
 */
4862
function api_time_to_hms($seconds)
4863
{
4864
    // $seconds = -1 means that we have wrong data in the db.
4865
    if ($seconds == -1) {
4866
        return
4867
            get_lang('Unknown').
4868
            Display::return_icon(
4869
                'info2.gif',
4870
                get_lang('WrongDatasForTimeSpentOnThePlatform'),
4871
                ['align' => 'absmiddle', 'hspace' => '3px']
4872
            );
4873
    }
4874
4875
    // How many hours ?
4876
    $hours = floor($seconds / 3600);
4877
4878
    // How many minutes ?
4879
    $min = floor(($seconds - ($hours * 3600)) / 60);
4880
4881
    // How many seconds
4882
    $sec = floor($seconds - ($hours * 3600) - ($min * 60));
4883
4884
    if ($sec < 10) {
4885
        $sec = "0$sec";
4886
    }
4887
4888
    if ($min < 10) {
4889
        $min = "0$min";
4890
    }
4891
4892
    return "$hours:$min:$sec";
4893
}
4894
4895
/* FILE SYSTEM RELATED FUNCTIONS */
4896
4897
/**
4898
 * Returns the permissions to be assigned to every newly created directory by the web-server.
4899
 * The return value is based on the platform administrator's setting
4900
 * "Administration > Configuration settings > Security > Permissions for new directories".
4901
 * @return int  Returns the permissions in the format "Owner-Group-Others, Read-Write-Execute", as an integer value.
4902
 */
4903
function api_get_permissions_for_new_directories()
4904
{
4905
    static $permissions;
4906
    if (!isset($permissions)) {
4907
        $permissions = trim(api_get_setting('permissions_for_new_directories'));
4908
        // The default value 0777 is according to that in the platform administration panel after fresh system installation.
4909
        $permissions = octdec(!empty($permissions) ? $permissions : '0777');
4910
    }
4911
    return $permissions;
4912
}
4913
4914
/**
4915
 * Returns the permissions to be assigned to every newly created directory by the web-server.
4916
 * The return value is based on the platform administrator's setting
4917
 * "Administration > Configuration settings > Security > Permissions for new files".
4918
 * @return int Returns the permissions in the format
4919
 * "Owner-Group-Others, Read-Write-Execute", as an integer value.
4920
 */
4921
function api_get_permissions_for_new_files()
4922
{
4923
    static $permissions;
4924
    if (!isset($permissions)) {
4925
        $permissions = trim(api_get_setting('permissions_for_new_files'));
4926
        // The default value 0666 is according to that in the platform
4927
        // administration panel after fresh system installation.
4928
        $permissions = octdec(!empty($permissions) ? $permissions : '0666');
4929
    }
4930
    return $permissions;
4931
}
4932
4933
/**
4934
 * Deletes a file, or a folder and its contents
4935
 *
4936
 * @author      Aidan Lister <[email protected]>
4937
 * @version     1.0.3
4938
 * @param       string   $dirname    Directory to delete
4939
 * @param       bool     Deletes only the content or not
4940
 * @param       bool     $strict if one folder/file fails stop the loop
4941
 * @return      bool     Returns TRUE on success, FALSE on failure
4942
 * @link http://aidanlister.com/2004/04/recursively-deleting-a-folder-in-php/
4943
 * @author      Yannick Warnier, adaptation for the Chamilo LMS, April, 2008
4944
 * @author      Ivan Tcholakov, a sanity check about Directory class creation has been added, September, 2009
4945
 */
4946
function rmdirr($dirname, $delete_only_content_in_folder = false, $strict = false)
4947
{
4948
    $res = true;
4949
    // A sanity check.
4950
    if (!file_exists($dirname)) {
4951
        return false;
4952
    }
4953
    $php_errormsg = '';
4954
    // Simple delete for a file.
4955
    if (is_file($dirname) || is_link($dirname)) {
4956
        $res = unlink($dirname);
4957
        if ($res === false) {
4958
            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);
4959
        }
4960
        return $res;
4961
    }
4962
4963
    // Loop through the folder.
4964
    $dir = dir($dirname);
4965
    // A sanity check.
4966
    $is_object_dir = is_object($dir);
4967
    if ($is_object_dir) {
4968
        while (false !== $entry = $dir->read()) {
4969
            // Skip pointers.
4970
            if ($entry == '.' || $entry == '..') {
4971
                continue;
4972
            }
4973
4974
            // Recurse.
4975
            if ($strict) {
4976
                $result = rmdirr("$dirname/$entry");
4977
                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...
4978
                    $res = false;
4979
                    break;
4980
                }
4981
            } else {
4982
                rmdirr("$dirname/$entry");
4983
            }
4984
        }
4985
    }
4986
4987
    // Clean up.
4988
    if ($is_object_dir) {
4989
        $dir->close();
4990
    }
4991
4992
    if ($delete_only_content_in_folder == false) {
4993
        $res = rmdir($dirname);
4994
        if ($res === false) {
4995
            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);
4996
        }
4997
    }
4998
    return $res;
4999
}
5000
5001
// TODO: This function is to be simplified. File access modes to be implemented.
5002
/**
5003
 * function adapted from a php.net comment
5004
 * copy recursively a folder
5005
 * @param the source folder
5006
 * @param the dest folder
5007
 * @param an array of excluded file_name (without extension)
5008
 * @param copied_files the returned array of copied files
5009
 * @param string $source
5010
 * @param string $dest
5011
 */
5012
function copyr($source, $dest, $exclude = [], $copied_files = [])
5013
{
5014
    if (empty($dest)) {
5015
        return false;
5016
    }
5017
    // Simple copy for a file
5018
    if (is_file($source)) {
5019
        $path_info = pathinfo($source);
5020
        if (!in_array($path_info['filename'], $exclude)) {
5021
            copy($source, $dest);
5022
        }
5023
        return true;
5024
    } elseif (!is_dir($source)) {
5025
        //then source is not a dir nor a file, return
5026
        return false;
5027
    }
5028
5029
    // Make destination directory.
5030
    if (!is_dir($dest)) {
5031
        mkdir($dest, api_get_permissions_for_new_directories());
5032
    }
5033
5034
    // Loop through the folder.
5035
    $dir = dir($source);
5036
    while (false !== $entry = $dir->read()) {
5037
        // Skip pointers
5038
        if ($entry == '.' || $entry == '..') {
5039
            continue;
5040
        }
5041
5042
        // Deep copy directories.
5043
        if ($dest !== "$source/$entry") {
5044
            $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

5044
            $files = copyr("$source/$entry", "$dest/$entry", $exclude, /** @scrutinizer ignore-type */ $copied_files);
Loading history...
5045
        }
5046
    }
5047
    // Clean up.
5048
    $dir->close();
5049
    return true;
5050
}
5051
5052
// TODO: Using DIRECTORY_SEPARATOR is not recommended, this is an obsolete approach. Documentation header to be added here.
5053
/**
5054
 * @param string $pathname
5055
 * @param string $base_path_document
5056
 * @param integer $session_id
5057
 */
5058
function copy_folder_course_session(
5059
    $pathname,
5060
    $base_path_document,
5061
    $session_id,
5062
    $course_info,
5063
    $document,
5064
    $source_course_id
5065
) {
5066
    $table = Database::get_course_table(TABLE_DOCUMENT);
5067
    $session_id = intval($session_id);
5068
    $source_course_id = intval($source_course_id);
5069
5070
    // Check whether directory already exists.
5071
    if (is_dir($pathname) || empty($pathname)) {
5072
        return true;
5073
    }
5074
5075
    // Ensure that a file with the same name does not already exist.
5076
    if (is_file($pathname)) {
5077
        trigger_error('copy_folder_course_session(): File exists', E_USER_WARNING);
5078
        return false;
5079
    }
5080
5081
    $course_id = $course_info['real_id'];
5082
    $folders = explode(DIRECTORY_SEPARATOR, str_replace($base_path_document.DIRECTORY_SEPARATOR, '', $pathname));
5083
    $new_pathname = $base_path_document;
5084
    $path = '';
5085
5086
    foreach ($folders as $folder) {
5087
        $new_pathname .= DIRECTORY_SEPARATOR.$folder;
5088
        $path .= DIRECTORY_SEPARATOR.$folder;
5089
5090
        if (!file_exists($new_pathname)) {
5091
            $path = Database::escape_string($path);
5092
5093
            $sql = "SELECT * FROM $table
5094
                    WHERE
5095
                        c_id = $source_course_id AND
5096
                        path = '$path' AND
5097
                        filetype = 'folder' AND
5098
                        session_id = '$session_id'";
5099
            $rs1 = Database::query($sql);
5100
            $num_rows = Database::num_rows($rs1);
5101
5102
            if ($num_rows == 0) {
5103
                mkdir($new_pathname, api_get_permissions_for_new_directories());
5104
5105
                // Insert new folder with destination session_id.
5106
                $params = [
5107
                    'c_id' => $course_id,
5108
                    'path' => $path,
5109
                    'comment' => $document->comment,
5110
                    'title' => basename($new_pathname),
5111
                    'filetype' => 'folder',
5112
                    'size' => '0',
5113
                    'session_id' => $session_id
5114
                ];
5115
                $document_id = Database::insert($table, $params);
5116
                if ($document_id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $document_id of type integer|false 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...
5117
                    $sql = "UPDATE $table SET id = iid WHERE iid = $document_id";
5118
                    Database::query($sql);
5119
5120
                    api_item_property_update(
5121
                        $course_info,
5122
                        TOOL_DOCUMENT,
5123
                        $document_id,
5124
                        'FolderCreated',
5125
                        api_get_user_id(),
5126
                        0,
5127
                        0,
5128
                        null,
5129
                        null,
5130
                        $session_id
5131
                    );
5132
                }
5133
            }
5134
        }
5135
    } // en foreach
5136
}
5137
5138
// TODO: chmodr() is a better name. Some corrections are needed. Documentation header to be added here.
5139
/**
5140
 * @param string $path
5141
 */
5142
function api_chmod_R($path, $filemode)
5143
{
5144
    if (!is_dir($path)) {
5145
        return chmod($path, $filemode);
5146
    }
5147
5148
    $handler = opendir($path);
5149
    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

5149
    while ($file = readdir(/** @scrutinizer ignore-type */ $handler)) {
Loading history...
5150
        if ($file != '.' && $file != '..') {
5151
            $fullpath = "$path/$file";
5152
            if (!is_dir($fullpath)) {
5153
                if (!chmod($fullpath, $filemode)) {
5154
                    return false;
5155
                }
5156
            } else {
5157
                if (!api_chmod_R($fullpath, $filemode)) {
5158
                    return false;
5159
                }
5160
            }
5161
        }
5162
    }
5163
5164
    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

5164
    closedir(/** @scrutinizer ignore-type */ $handler);
Loading history...
5165
    return chmod($path, $filemode);
5166
}
5167
5168
5169
// TODO: Where the following function has been copy/pased from? There is no information about author and license. Style, coding conventions...
5170
/**
5171
 * Parse info file format. (e.g: file.info)
5172
 *
5173
 * Files should use an ini-like format to specify values.
5174
 * White-space generally doesn't matter, except inside values.
5175
 * e.g.
5176
 *
5177
 * @verbatim
5178
 *   key = value
5179
 *   key = "value"
5180
 *   key = 'value'
5181
 *   key = "multi-line
5182
 *
5183
 *   value"
5184
 *   key = 'multi-line
5185
 *
5186
 *   value'
5187
 *   key
5188
 *   =
5189
 *   'value'
5190
 * @endverbatim
5191
 *
5192
 * Arrays are created using a GET-like syntax:
5193
 *
5194
 * @verbatim
5195
 *   key[] = "numeric array"
5196
 *   key[index] = "associative array"
5197
 *   key[index][] = "nested numeric array"
5198
 *   key[index][index] = "nested associative array"
5199
 * @endverbatim
5200
 *
5201
 * PHP constants are substituted in, but only when used as the entire value:
5202
 *
5203
 * Comments should start with a semi-colon at the beginning of a line.
5204
 *
5205
 * This function is NOT for placing arbitrary module-specific settings. Use
5206
 * variable_get() and variable_set() for that.
5207
 *
5208
 * Information stored in the module.info file:
5209
 * - name: The real name of the module for display purposes.
5210
 * - description: A brief description of the module.
5211
 * - dependencies: An array of shortnames of other modules this module depends on.
5212
 * - package: The name of the package of modules this module belongs to.
5213
 *
5214
 * Example of .info file:
5215
 * <code>
5216
 * @verbatim
5217
 *   name = Forum
5218
 *   description = Enables threaded discussions about general topics.
5219
 *   dependencies[] = taxonomy
5220
 *   dependencies[] = comment
5221
 *   package = Core - optional
5222
 *   version = VERSION
5223
 * @endverbatim
5224
 * </code>
5225
 * @param string $filename
5226
 *   The file we are parsing. Accepts file with relative or absolute path.
5227
 * @return
5228
 *   The info array.
5229
 */
5230
function api_parse_info_file($filename)
5231
{
5232
    $info = [];
5233
5234
    if (!file_exists($filename)) {
5235
        return $info;
5236
    }
5237
5238
    $data = file_get_contents($filename);
5239
    if (preg_match_all('
5240
        @^\s*                           # Start at the beginning of a line, ignoring leading whitespace
5241
        ((?:
5242
          [^=;\[\]]|                    # Key names cannot contain equal signs, semi-colons or square brackets,
5243
          \[[^\[\]]*\]                  # unless they are balanced and not nested
5244
        )+?)
5245
        \s*=\s*                         # Key/value pairs are separated by equal signs (ignoring white-space)
5246
        (?:
5247
          ("(?:[^"]|(?<=\\\\)")*")|     # Double-quoted string, which may contain slash-escaped quotes/slashes
5248
          (\'(?:[^\']|(?<=\\\\)\')*\')| # Single-quoted string, which may contain slash-escaped quotes/slashes
5249
          ([^\r\n]*?)                   # Non-quoted string
5250
        )\s*$                           # Stop at the next end of a line, ignoring trailing whitespace
5251
        @msx', $data, $matches, PREG_SET_ORDER)) {
5252
        $key = $value1 = $value2 = $value3 = '';
5253
        foreach ($matches as $match) {
5254
            // Fetch the key and value string.
5255
            $i = 0;
5256
            foreach (['key', 'value1', 'value2', 'value3'] as $var) {
5257
                $$var = isset($match[++$i]) ? $match[$i] : '';
5258
            }
5259
            $value = stripslashes(substr($value1, 1, -1)).stripslashes(substr($value2, 1, -1)).$value3;
5260
5261
            // Parse array syntax.
5262
            $keys = preg_split('/\]?\[/', rtrim($key, ']'));
5263
            $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

5263
            $last = array_pop(/** @scrutinizer ignore-type */ $keys);
Loading history...
5264
            $parent = &$info;
5265
5266
            // Create nested arrays.
5267
            foreach ($keys as $key) {
5268
                if ($key == '') {
5269
                    $key = count($parent);
5270
                }
5271
                if (!isset($parent[$key]) || !is_array($parent[$key])) {
5272
                    $parent[$key] = [];
5273
                }
5274
                $parent = &$parent[$key];
5275
            }
5276
5277
            // Handle PHP constants.
5278
            if (defined($value)) {
5279
                $value = constant($value);
5280
            }
5281
5282
            // Insert actual value.
5283
            if ($last == '') {
5284
                $last = count($parent);
5285
            }
5286
            $parent[$last] = $value;
5287
        }
5288
    }
5289
    return $info;
5290
}
5291
5292
/**
5293
 * Gets Chamilo version from the configuration files
5294
 * @return string   A string of type "1.8.4", or an empty string if the version could not be found
5295
 */
5296
function api_get_version()
5297
{
5298
    return (string) api_get_configuration_value('system_version');
5299
}
5300
5301
/**
5302
 * Gets the software name (the name/brand of the Chamilo-based customized system)
5303
 * @return string
5304
 */
5305
function api_get_software_name()
5306
{
5307
    $name = api_get_configuration_value('software_name');
5308
    if (!empty($name)) {
5309
        return $name;
5310
    } else {
5311
        return 'Chamilo';
5312
    }
5313
}
5314
5315
/**
5316
 * Checks whether status given in parameter exists in the platform
5317
 * @param mixed the status (can be either int either string)
5318
 * @return boolean if the status exists, else returns false
5319
 */
5320
function api_status_exists($status_asked)
5321
{
5322
    global $_status_list;
5323
    return in_array($status_asked, $_status_list) ? true : isset($_status_list[$status_asked]);
5324
}
5325
5326
/**
5327
 * Checks whether status given in parameter exists in the platform. The function
5328
 * returns the status ID or false if it does not exist, but given the fact there
5329
 * is no "0" status, the return value can be checked against
5330
 * if(api_status_key()) to know if it exists.
5331
 * @param   mixed   The status (can be either int or string)
5332
 * @return  mixed   Status ID if exists, false otherwise
5333
 */
5334
function api_status_key($status)
5335
{
5336
    global $_status_list;
5337
    return isset($_status_list[$status]) ? $status : array_search($status, $_status_list);
5338
}
5339
5340
/**
5341
 * Gets the status langvars list
5342
 * @return string[] the list of status with their translations
5343
 */
5344
function api_get_status_langvars()
5345
{
5346
    return [
5347
        COURSEMANAGER => get_lang('Teacher', ''),
5348
        SESSIONADMIN => get_lang('SessionsAdmin', ''),
5349
        DRH => get_lang('Drh', ''),
5350
        STUDENT => get_lang('Student', ''),
5351
        ANONYMOUS => get_lang('Anonymous', ''),
5352
        STUDENT_BOSS => get_lang('RoleStudentBoss', ''),
5353
        INVITEE => get_lang('Invited'),
5354
    ];
5355
}
5356
5357
/**
5358
 * The function that retrieves all the possible settings for a certain config setting
5359
 * @author Patrick Cool <[email protected]>, Ghent University
5360
 */
5361
function api_get_settings_options($var)
5362
{
5363
    $table_settings_options = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
5364
    $var = Database::escape_string($var);
5365
    $sql = "SELECT * FROM $table_settings_options
5366
            WHERE variable = '$var'
5367
            ORDER BY id";
5368
    $result = Database::query($sql);
5369
    $settings_options_array = [];
5370
    while ($row = Database::fetch_array($result, 'ASSOC')) {
5371
        $settings_options_array[] = $row;
5372
    }
5373
    return $settings_options_array;
5374
}
5375
5376
/**
5377
 * @param array $params
5378
 */
5379
function api_set_setting_option($params)
5380
{
5381
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
5382
    if (empty($params['id'])) {
5383
        Database::insert($table, $params);
5384
    } else {
5385
        Database::update($table, $params, ['id = ? '=> $params['id']]);
5386
    }
5387
}
5388
5389
/**
5390
 * @param array $params
5391
 */
5392
function api_set_setting_simple($params)
5393
{
5394
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5395
    $url_id = api_get_current_access_url_id();
5396
5397
    if (empty($params['id'])) {
5398
        $params['access_url'] = $url_id;
5399
        Database::insert($table, $params);
5400
    } else {
5401
        Database::update($table, $params, ['id = ? '=> [$params['id']]]);
5402
    }
5403
}
5404
5405
/**
5406
 * @param int $id
5407
 */
5408
function api_delete_setting_option($id)
5409
{
5410
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
5411
    if (!empty($id)) {
5412
        Database::delete($table, ['id = ? '=> $id]);
5413
    }
5414
}
5415
5416
/**
5417
 * Sets a platform configuration setting to a given value
5418
 * @param string    The variable we want to update
5419
 * @param string    The value we want to record
5420
 * @param string    The sub-variable if any (in most cases, this will remain null)
5421
 * @param string    The category if any (in most cases, this will remain null)
5422
 * @param int       The access_url for which this parameter is valid
5423
 * @param string $cat
5424
 * @return bool|null
5425
 */
5426
function api_set_setting($var, $value, $subvar = null, $cat = null, $access_url = 1)
5427
{
5428
    if (empty($var)) {
5429
        return false;
5430
    }
5431
    $t_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5432
    $var = Database::escape_string($var);
5433
    $value = Database::escape_string($value);
5434
    $access_url = (int) $access_url;
5435
    if (empty($access_url)) {
5436
        $access_url = 1;
5437
    }
5438
    $select = "SELECT id FROM $t_settings WHERE variable = '$var' ";
5439
    if (!empty($subvar)) {
5440
        $subvar = Database::escape_string($subvar);
5441
        $select .= " AND subkey = '$subvar'";
5442
    }
5443
    if (!empty($cat)) {
5444
        $cat = Database::escape_string($cat);
5445
        $select .= " AND category = '$cat'";
5446
    }
5447
    if ($access_url > 1) {
5448
        $select .= " AND access_url = $access_url";
5449
    } else {
5450
        $select .= " AND access_url = 1 ";
5451
    }
5452
5453
    $res = Database::query($select);
5454
    if (Database::num_rows($res) > 0) {
5455
        // Found item for this access_url.
5456
        $row = Database::fetch_array($res);
5457
        $sql = "UPDATE $t_settings SET selected_value = '$value'
5458
                WHERE id = ".$row['id'];
5459
        Database::query($sql);
5460
    } else {
5461
        // Item not found for this access_url, we have to check if it exist with access_url = 1
5462
        $select = "SELECT * FROM $t_settings
5463
                   WHERE variable = '$var' AND access_url = 1 ";
5464
        // Just in case
5465
        if ($access_url == 1) {
5466
            if (!empty($subvar)) {
5467
                $select .= " AND subkey = '$subvar'";
5468
            }
5469
            if (!empty($cat)) {
5470
                $select .= " AND category = '$cat'";
5471
            }
5472
            $res = Database::query($select);
5473
            if (Database::num_rows($res) > 0) {
5474
                // We have a setting for access_url 1, but none for the current one, so create one.
5475
                $row = Database::fetch_array($res);
5476
                $insert = "INSERT INTO $t_settings (variable, subkey, type,category, selected_value, title, comment, scope, subkeytext, access_url)
5477
                        VALUES
5478
                        ('".$row['variable']."',".(!empty($row['subkey']) ? "'".$row['subkey']."'" : "NULL").",".
5479
                    "'".$row['type']."','".$row['category']."',".
5480
                    "'$value','".$row['title']."',".
5481
                    "".(!empty($row['comment']) ? "'".$row['comment']."'" : "NULL").",".(!empty($row['scope']) ? "'".$row['scope']."'" : "NULL").",".
5482
                    "".(!empty($row['subkeytext']) ? "'".$row['subkeytext']."'" : "NULL").",$access_url)";
5483
                Database::query($insert);
5484
            } else {
0 ignored issues
show
Unused Code introduced by
This else statement is empty and can be removed.

This check looks for the else branches of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These else branches can be removed.

if (rand(1, 6) > 3) {
print "Check failed";
} else {
    //print "Check succeeded";
}

could be turned into

if (rand(1, 6) > 3) {
    print "Check failed";
}

This is much more concise to read.

Loading history...
5485
                // Such a setting does not exist.
5486
                //error_log(__FILE__.':'.__LINE__.': Attempting to update setting '.$var.' ('.$subvar.') which does not exist at all', 0);
5487
            }
5488
        } else {
5489
            // Other access url.
5490
            if (!empty($subvar)) {
5491
                $select .= " AND subkey = '$subvar'";
5492
            }
5493
            if (!empty($cat)) {
5494
                $select .= " AND category = '$cat'";
5495
            }
5496
            $res = Database::query($select);
5497
5498
            if (Database::num_rows($res) > 0) {
5499
                // We have a setting for access_url 1, but none for the current one, so create one.
5500
                $row = Database::fetch_array($res);
5501
                if ($row['access_url_changeable'] == 1) {
5502
                    $insert = "INSERT INTO $t_settings (variable,subkey, type,category, selected_value,title, comment,scope, subkeytext,access_url, access_url_changeable) VALUES
5503
                            ('".$row['variable']."',".
5504
                        (!empty($row['subkey']) ? "'".$row['subkey']."'" : "NULL").",".
5505
                        "'".$row['type']."','".$row['category']."',".
5506
                        "'$value','".$row['title']."',".
5507
                        "".(!empty($row['comment']) ? "'".$row['comment']."'" : "NULL").",".
5508
                        (!empty($row['scope']) ? "'".$row['scope']."'" : "NULL").",".
5509
                        "".(!empty($row['subkeytext']) ? "'".$row['subkeytext']."'" : "NULL").",$access_url,".$row['access_url_changeable'].")";
5510
                    Database::query($insert);
5511
                }
5512
            } else { // Such a setting does not exist.
0 ignored issues
show
Unused Code introduced by
This else statement is empty and can be removed.

This check looks for the else branches of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These else branches can be removed.

if (rand(1, 6) > 3) {
print "Check failed";
} else {
    //print "Check succeeded";
}

could be turned into

if (rand(1, 6) > 3) {
    print "Check failed";
}

This is much more concise to read.

Loading history...
5513
                //error_log(__FILE__.':'.__LINE__.': Attempting to update setting '.$var.' ('.$subvar.') which does not exist at all. The access_url is: '.$access_url.' ',0);
5514
            }
5515
        }
5516
    }
5517
}
5518
5519
/**
5520
 * Sets a whole category of settings to one specific value
5521
 * @param string    Category
5522
 * @param string    Value
5523
 * @param int       Access URL. Optional. Defaults to 1
5524
 * @param array     Optional array of filters on field type
5525
 * @param string $category
5526
 * @param string $value
5527
 * @return bool
5528
 */
5529
function api_set_settings_category($category, $value = null, $access_url = 1, $fieldtype = [])
5530
{
5531
    if (empty($category)) {
5532
        return false;
5533
    }
5534
    $category = Database::escape_string($category);
5535
    $t_s = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5536
    $access_url = (int) $access_url;
5537
    if (empty($access_url)) {
5538
        $access_url = 1;
5539
    }
5540
    if (isset($value)) {
5541
        $value = Database::escape_string($value);
5542
        $sql = "UPDATE $t_s SET selected_value = '$value'
5543
                WHERE category = '$category' AND access_url = $access_url";
5544
        if (is_array($fieldtype) && count($fieldtype) > 0) {
5545
            $sql .= " AND ( ";
5546
            $i = 0;
5547
            foreach ($fieldtype as $type) {
5548
                if ($i > 0) {
5549
                    $sql .= ' OR ';
5550
                }
5551
                $type = Database::escape_string($type);
5552
                $sql .= " type='".$type."' ";
5553
                $i++;
5554
            }
5555
            $sql .= ")";
5556
        }
5557
        $res = Database::query($sql);
5558
        return $res !== false;
5559
    } else {
5560
        $sql = "UPDATE $t_s SET selected_value = NULL
5561
                WHERE category = '$category' AND access_url = $access_url";
5562
        if (is_array($fieldtype) && count($fieldtype) > 0) {
5563
            $sql .= " AND ( ";
5564
            $i = 0;
5565
            foreach ($fieldtype as $type) {
5566
                if ($i > 0) {
5567
                    $sql .= ' OR ';
5568
                }
5569
                $type = Database::escape_string($type);
5570
                $sql .= " type='".$type."' ";
5571
                $i++;
5572
            }
5573
            $sql .= ")";
5574
        }
5575
        $res = Database::query($sql);
5576
        return $res !== false;
5577
    }
5578
}
5579
5580
/**
5581
 * Gets all available access urls in an array (as in the database)
5582
 * @return array    An array of database records
5583
 */
5584
function api_get_access_urls($from = 0, $to = 1000000, $order = 'url', $direction = 'ASC')
5585
{
5586
    $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5587
    $from = (int) $from;
5588
    $to = (int) $to;
5589
    $order = Database::escape_string($order, null, false);
5590
    $direction = Database::escape_string($direction, null, false);
5591
    $sql = "SELECT id, url, description, active, created_by, tms
5592
            FROM $table
5593
            ORDER BY $order $direction
5594
            LIMIT $to OFFSET $from";
5595
    $res = Database::query($sql);
5596
    return Database::store_result($res);
5597
}
5598
5599
/**
5600
 * Gets the access url info in an array
5601
 * @param int $id Id of the access url
5602
 * @param bool $returnDefault Set to false if you want the real URL if URL 1 is still 'http://localhost/'
5603
 * @return array All the info (url, description, active, created_by, tms)
5604
 * from the access_url table
5605
 * @author Julio Montoya
5606
 */
5607
function api_get_access_url($id, $returnDefault = true)
5608
{
5609
    static $staticResult;
5610
    $id = intval($id);
5611
5612
    if (isset($staticResult[$id])) {
5613
        $result = $staticResult[$id];
5614
    } else {
5615
        // Calling the Database:: library dont work this is handmade.
5616
        $table_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5617
        $sql = "SELECT url, description, active, created_by, tms
5618
                FROM $table_access_url WHERE id = '$id' ";
5619
        $res = Database::query($sql);
5620
        $result = @Database::fetch_array($res);
5621
        $staticResult[$id] = $result;
5622
    }
5623
5624
    // If the result url is 'http://localhost/' (the default) and the root_web
5625
    // (=current url) is different, and the $id is = 1 (which might mean
5626
    // api_get_current_access_url_id() returned 1 by default), then return the
5627
    // root_web setting instead of the current URL
5628
    // This is provided as an option to avoid breaking the storage of URL-specific
5629
    // homepages in home/localhost/
5630
    if ($id === 1 && $returnDefault === false) {
5631
        $currentUrl = api_get_current_access_url_id();
5632
        // only do this if we are on the main URL (=1), otherwise we could get
5633
        // information on another URL instead of the one asked as parameter
5634
        if ($currentUrl === 1) {
5635
            $rootWeb = api_get_path(WEB_PATH);
5636
            $default = 'http://localhost/';
5637
            if ($result['url'] === $default && $rootWeb != $default) {
5638
                $result['url'] = $rootWeb;
5639
            }
5640
        }
5641
    }
5642
5643
    return $result;
5644
}
5645
5646
/**
5647
 * Gets all the current settings for a specific access url
5648
 * @param string    The category, if any, that we want to get
5649
 * @param string    Whether we want a simple list (display a category) or
5650
 * a grouped list (group by variable as in settings.php default). Values: 'list' or 'group'
5651
 * @param int       Access URL's ID. Optional. Uses 1 by default, which is the unique URL
5652
 * @return array    Array of database results for the current settings of the current access URL
5653
 */
5654
function &api_get_settings($cat = null, $ordering = 'list', $access_url = 1, $url_changeable = 0)
5655
{
5656
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5657
    $access_url = (int) $access_url;
5658
    $where_condition = '';
5659
    if ($url_changeable == 1) {
5660
        $where_condition = " AND access_url_changeable= '1' ";
5661
    }
5662
    if (empty($access_url) || $access_url == -1) {
5663
        $access_url = 1;
5664
    }
5665
    $sql = "SELECT * FROM $table
5666
            WHERE access_url = $access_url  $where_condition ";
5667
5668
    if (!empty($cat)) {
5669
        $cat = Database::escape_string($cat);
5670
        $sql .= " AND category='$cat' ";
5671
    }
5672
    if ($ordering == 'group') {
5673
        $sql .= " ORDER BY id ASC";
5674
    } else {
5675
        $sql .= " ORDER BY 1,2 ASC";
5676
    }
5677
    $result = Database::query($sql);
5678
    if ($result === null) {
5679
        return [];
5680
    }
5681
    $result = Database::store_result($result, 'ASSOC');
5682
5683
    return $result;
5684
}
5685
5686
/**
5687
 * @param string $value The value we want to record
5688
 * @param string $variable The variable name we want to insert
5689
 * @param string $subKey The subkey for the variable we want to insert
5690
 * @param string $type The type for the variable we want to insert
5691
 * @param string $category The category for the variable we want to insert
5692
 * @param string $title The title
5693
 * @param string $comment The comment
5694
 * @param string $scope The scope
5695
 * @param string $subKeyText The subkey text
5696
 * @param int $accessUrlId The access_url for which this parameter is valid
5697
 * @param int $visibility The changeability of this setting for non-master urls
5698
 * @return int The setting ID
5699
 */
5700
function api_add_setting(
5701
    $value,
5702
    $variable,
5703
    $subKey = '',
5704
    $type = 'textfield',
5705
    $category = '',
5706
    $title = '',
5707
    $comment = '',
5708
    $scope = '',
5709
    $subKeyText = '',
5710
    $accessUrlId = 1,
5711
    $visibility = 0
5712
) {
5713
    $em = Database::getManager();
5714
    $settingRepo = $em->getRepository('ChamiloCoreBundle:SettingsCurrent');
5715
    $accessUrlId = (int) $accessUrlId ?: 1;
5716
5717
    if (is_array($value)) {
5718
        $value = serialize($value);
5719
    } else {
5720
        $value = trim($value);
5721
    }
5722
5723
    $criteria = ['variable' => $variable, 'accessUrl' => $accessUrlId];
5724
5725
    if (!empty($subKey)) {
5726
        $criteria['subkey'] = $subKey;
5727
    }
5728
5729
    // Check if this variable doesn't exist already
5730
    /** @var SettingsCurrent $setting */
5731
    $setting = $settingRepo->findOneBy($criteria);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $setting is correct as $settingRepo->findOneBy($criteria) targeting Doctrine\ORM\EntityRepository::findOneBy() seems to always return null.

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

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

}

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

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

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

Loading history...
5732
5733
    if ($setting) {
5734
        $setting->setSelectedValue($value);
5735
5736
        $em->persist($setting);
5737
        $em->flush();
5738
5739
        return $setting->getId();
5740
    }
5741
5742
    // Item not found for this access_url, we have to check if the whole thing is missing
5743
    // (in which case we ignore the insert) or if there *is* a record but just for access_url = 1
5744
    $setting = new SettingsCurrent();
5745
    $setting
5746
        ->setVariable($variable)
5747
        ->setSelectedValue($value)
5748
        ->setType($type)
5749
        ->setCategory($category)
5750
        ->setSubkey($subKey)
5751
        ->setTitle($title)
5752
        ->setComment($comment)
5753
        ->setScope($scope)
5754
        ->setSubkeytext($subKeyText)
5755
        ->setAccessUrl($accessUrlId)
5756
        ->setAccessUrlChangeable($visibility);
5757
5758
    $em->persist($setting);
5759
    $em->flush();
5760
5761
    return $setting->getId();
5762
}
5763
5764
/**
5765
 * Checks wether a user can or can't view the contents of a course.
5766
 * @deprecated use CourseManager::is_user_subscribed_in_course
5767
 * @param   int $userid     User id or NULL to get it from $_SESSION
5768
 * @param   int $cid        Course id to check whether the user is allowed.
5769
 * @return  bool
5770
 */
5771
function api_is_course_visible_for_user($userid = null, $cid = null)
5772
{
5773
    if ($userid === null) {
5774
        $userid = api_get_user_id();
5775
    }
5776
    if (empty($userid) || strval(intval($userid)) != $userid) {
5777
        if (api_is_anonymous()) {
5778
            $userid = api_get_anonymous_id();
5779
        } else {
5780
            return false;
5781
        }
5782
    }
5783
    $cid = Database::escape_string($cid);
5784
5785
    $courseInfo = api_get_course_info($cid);
5786
    $courseId = $courseInfo['real_id'];
5787
    $is_platformAdmin = api_is_platform_admin();
5788
5789
    $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
5790
    $course_cat_table = Database::get_main_table(TABLE_MAIN_CATEGORY);
5791
5792
    $sql = "SELECT
5793
                $course_table.category_code,
5794
                $course_table.visibility,
5795
                $course_table.code,
5796
                $course_cat_table.code
5797
            FROM $course_table
5798
            LEFT JOIN $course_cat_table
5799
                ON $course_table.category_code = $course_cat_table.code
5800
            WHERE
5801
                $course_table.code = '$cid'
5802
            LIMIT 1";
5803
5804
    $result = Database::query($sql);
5805
5806
    if (Database::num_rows($result) > 0) {
5807
        $visibility = Database::fetch_array($result);
5808
        $visibility = $visibility['visibility'];
5809
    } else {
5810
        $visibility = 0;
5811
    }
5812
    // Shortcut permissions in case the visibility is "open to the world".
5813
    if ($visibility === COURSE_VISIBILITY_OPEN_WORLD) {
5814
        return true;
5815
    }
5816
5817
    $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
5818
5819
    $sql = "SELECT
5820
                is_tutor, status
5821
            FROM $tbl_course_user
5822
            WHERE
5823
                user_id  = '$userid' AND
5824
                relation_type <> '".COURSE_RELATION_TYPE_RRHH."' AND
5825
                c_id = $courseId
5826
            LIMIT 1";
5827
5828
    $result = Database::query($sql);
5829
5830
    if (Database::num_rows($result) > 0) {
5831
        // This user has got a recorded state for this course.
5832
        $cuData = Database::fetch_array($result);
5833
        $is_courseMember = true;
5834
        $is_courseAdmin = ($cuData['status'] == 1);
5835
    }
5836
5837
    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...
5838
        // This user has no status related to this course.
5839
        // Is it the session coach or the session admin?
5840
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
5841
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
5842
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
5843
5844
        $sql = "SELECT
5845
                    session.id_coach, session_admin_id, session.id
5846
                FROM
5847
                    $tbl_session as session
5848
                INNER JOIN $tbl_session_course
5849
                    ON session_rel_course.session_id = session.id
5850
                    AND session_rel_course.c_id = '$courseId'
5851
                LIMIT 1";
5852
5853
        $result = Database::query($sql);
5854
        $row = Database::store_result($result);
5855
5856
        if ($row[0]['id_coach'] == $userid) {
5857
            $is_courseMember = true;
5858
            $is_courseAdmin = false;
5859
        } elseif ($row[0]['session_admin_id'] == $userid) {
5860
            $is_courseMember = false;
5861
            $is_courseAdmin = false;
5862
        } else {
5863
            // Check if the current user is the course coach.
5864
            $sql = "SELECT 1
5865
                    FROM $tbl_session_course
5866
                    WHERE session_rel_course.c_id = '$courseId'
5867
                    AND session_rel_course.id_coach = '$userid'
5868
                    LIMIT 1";
5869
5870
            $result = Database::query($sql);
5871
5872
            //if ($row = Database::fetch_array($result)) {
5873
            if (Database::num_rows($result) > 0) {
5874
                $is_courseMember = true;
5875
                $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
5876
5877
                $sql = "SELECT status FROM $tbl_user
5878
                        WHERE user_id = $userid
5879
                        LIMIT 1";
5880
5881
                $result = Database::query($sql);
5882
5883
                if (Database::result($result, 0, 0) == 1) {
5884
                    $is_courseAdmin = true;
5885
                } else {
5886
                    $is_courseAdmin = false;
5887
                }
5888
            } else {
5889
                // Check if the user is a student is this session.
5890
                $sql = "SELECT  id
5891
                        FROM $tbl_session_course_user
5892
                        WHERE
5893
                            user_id  = '$userid' AND
5894
                            c_id = '$courseId'
5895
                        LIMIT 1";
5896
5897
                if (Database::num_rows($result) > 0) {
5898
                    // This user haa got a recorded state for this course.
5899
                    while ($row = Database::fetch_array($result)) {
5900
                        $is_courseMember = true;
5901
                        $is_courseAdmin = false;
5902
                    }
5903
                }
5904
            }
5905
        }
5906
    }
5907
5908
    switch ($visibility) {
5909
        case COURSE_VISIBILITY_OPEN_WORLD:
5910
            return true;
5911
        case COURSE_VISIBILITY_OPEN_PLATFORM:
5912
            return isset($userid);
5913
        case COURSE_VISIBILITY_REGISTERED:
5914
        case COURSE_VISIBILITY_CLOSED:
5915
            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...
5916
        case COURSE_VISIBILITY_HIDDEN:
5917
            return $is_platformAdmin;
5918
    }
5919
5920
    return false;
5921
}
5922
5923
/**
5924
 * Returns whether an element (forum, message, survey ...) belongs to a session or not
5925
 * @param String the tool of the element
5926
 * @param int the element id in database
5927
 * @param int the session_id to compare with element session id
5928
 * @param string $tool
5929
 * @return boolean true if the element is in the session, false else
5930
 */
5931
function api_is_element_in_the_session($tool, $element_id, $session_id = null)
5932
{
5933
    if (is_null($session_id)) {
5934
        $session_id = api_get_session_id();
5935
    }
5936
5937
    // Get information to build query depending of the tool.
5938
    switch ($tool) {
5939
        case TOOL_SURVEY:
5940
            $table_tool = Database::get_course_table(TABLE_SURVEY);
5941
            $key_field = 'survey_id';
5942
            break;
5943
        case TOOL_ANNOUNCEMENT:
5944
            $table_tool = Database::get_course_table(TABLE_ANNOUNCEMENT);
5945
            $key_field = 'id';
5946
            break;
5947
        case TOOL_AGENDA:
5948
            $table_tool = Database::get_course_table(TABLE_AGENDA);
5949
            $key_field = 'id';
5950
            break;
5951
        case TOOL_GROUP:
5952
            $table_tool = Database::get_course_table(TABLE_GROUP);
5953
            $key_field = 'id';
5954
            break;
5955
        default:
5956
            return false;
5957
    }
5958
    $course_id = api_get_course_int_id();
5959
5960
    $sql = "SELECT session_id FROM $table_tool 
5961
            WHERE c_id = $course_id AND $key_field =  ".intval($element_id);
5962
    $rs = Database::query($sql);
5963
    if ($element_session_id = Database::result($rs, 0, 0)) {
5964
        if ($element_session_id == intval($session_id)) {
5965
            // The element belongs to the session.
5966
            return true;
5967
        }
5968
    }
5969
    return false;
5970
}
5971
5972
/**
5973
 * Replaces "forbidden" characters in a filename string.
5974
 *
5975
 * @param string $filename
5976
 * @param bool $treat_spaces_as_hyphens
5977
 *
5978
 * @return string
5979
 */
5980
function api_replace_dangerous_char($filename, $treat_spaces_as_hyphens = true)
5981
{
5982
    return URLify::filter(
5983
        $filename,
5984
        250,
5985
        '',
5986
        true,
5987
        true,
5988
        false,
5989
        false,
5990
        $treat_spaces_as_hyphens
5991
    );
5992
}
5993
5994
/**
5995
 * Fixes the $_SERVER['REQUEST_URI'] that is empty in IIS6.
5996
 * @author Ivan Tcholakov, 28-JUN-2006.
5997
 */
5998
function api_request_uri()
5999
{
6000
    if (!empty($_SERVER['REQUEST_URI'])) {
6001
        return $_SERVER['REQUEST_URI'];
6002
    }
6003
    $uri = $_SERVER['SCRIPT_NAME'];
6004
    if (!empty($_SERVER['QUERY_STRING'])) {
6005
        $uri .= '?'.$_SERVER['QUERY_STRING'];
6006
    }
6007
    $_SERVER['REQUEST_URI'] = $uri;
6008
    return $uri;
6009
}
6010
6011
6012
/** Gets the current access_url id of the Chamilo Platform
6013
 * @author Julio Montoya <[email protected]>
6014
 * @return int access_url_id of the current Chamilo Installation
6015
 */
6016
function api_get_current_access_url_id()
6017
{
6018
    $access_url_table = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
6019
    $path = Database::escape_string(api_get_path(WEB_PATH));
6020
    $sql = "SELECT id FROM $access_url_table WHERE url = '".$path."'";
6021
    $result = Database::query($sql);
6022
    if (Database::num_rows($result) > 0) {
6023
        $access_url_id = Database::result($result, 0, 0);
6024
        return $access_url_id;
6025
    }
6026
    //if the url in WEB_PATH was not found, it can only mean that there is
6027
    // either a configuration problem or the first URL has not been defined yet
6028
    // (by default it is http://localhost/). Thus the more sensible thing we can
6029
    // do is return 1 (the main URL) as the user cannot hack this value anyway
6030
    return 1;
6031
}
6032
6033
/**
6034
 * Gets the registered urls from a given user id
6035
 * @author Julio Montoya <[email protected]>
6036
 * @return int user id
6037
 */
6038
function api_get_access_url_from_user($user_id)
6039
{
6040
    $user_id = intval($user_id);
6041
    $table_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
6042
    $table_url          = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
6043
    $sql = "SELECT access_url_id
6044
            FROM $table_url_rel_user url_rel_user
6045
            INNER JOIN $table_url u
6046
            ON (url_rel_user.access_url_id = u.id)
6047
            WHERE user_id = ".intval($user_id);
6048
    $result = Database::query($sql);
6049
    $list = [];
6050
    while ($row = Database::fetch_array($result, 'ASSOC')) {
6051
        $list[] = $row['access_url_id'];
6052
    }
6053
    return $list;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $list returns the type array which is incompatible with the documented return type integer.
Loading history...
6054
}
6055
6056
/**
6057
 * Gets the status of a user in a course
6058
 * @param int       $user_id
6059
 * @param int    $courseId
6060
 * @return int      user status
6061
 */
6062
function api_get_status_of_user_in_course($user_id, $courseId)
6063
{
6064
    $tbl_rel_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
6065
    if (!empty($user_id) && !empty($courseId)) {
6066
        $user_id = intval($user_id);
6067
        $courseId = intval($courseId);
6068
        $sql = 'SELECT status
6069
                FROM '.$tbl_rel_course_user.'
6070
                WHERE user_id='.$user_id.' AND c_id = '.$courseId;
6071
        $result = Database::query($sql);
6072
        $row_status = Database::fetch_array($result, 'ASSOC');
6073
        return $row_status['status'];
6074
    } else {
6075
        return 0;
6076
    }
6077
}
6078
6079
/**
6080
 * Checks whether the curent user is in a group or not.
6081
 *
6082
 * @param string        The group id - optional (takes it from session if not given)
6083
 * @param string        The course code - optional (no additional check by course if course code is not given)
6084
 * @return boolean
6085
 * @author Ivan Tcholakov
6086
 */
6087
function api_is_in_group($groupIdParam = null, $courseCodeParam = null)
6088
{
6089
    if (!empty($courseCodeParam)) {
6090
        $courseCode = api_get_course_id();
6091
        if (!empty($courseCode)) {
6092
            if ($courseCodeParam != $courseCode) {
6093
                return false;
6094
            }
6095
        } else {
6096
            return false;
6097
        }
6098
    }
6099
6100
    $groupId = api_get_group_id();
6101
6102
    if (isset($groupId) && $groupId != '') {
6103
        if (!empty($groupIdParam)) {
6104
            return $groupIdParam == $groupId;
6105
        } else {
6106
            return true;
6107
        }
6108
    }
6109
6110
    return false;
6111
}
6112
6113
/**
6114
 * Checks whether a secret key is valid
6115
 * @param string $original_key_secret  - secret key from (webservice) client
6116
 * @param string $security_key - security key from Chamilo
6117
 * @return boolean - true if secret key is valid, false otherwise
6118
 */
6119
function api_is_valid_secret_key($original_key_secret, $security_key)
6120
{
6121
    return $original_key_secret == sha1($security_key);
6122
}
6123
6124
/**
6125
 * Checks whether a user is into course
6126
 * @param int $course_id - the course id
6127
 * @param int $user_id - the user id
6128
 * @return bool
6129
 */
6130
function api_is_user_of_course($course_id, $user_id)
6131
{
6132
    $tbl_course_rel_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
6133
    $sql = 'SELECT user_id FROM '.$tbl_course_rel_user.'
6134
            WHERE
6135
                c_id ="'.intval($course_id).'" AND
6136
                user_id = "'.intval($user_id).'" AND
6137
                relation_type <> '.COURSE_RELATION_TYPE_RRHH.' ';
6138
    $result = Database::query($sql);
6139
    return Database::num_rows($result) == 1;
6140
}
6141
6142
/**
6143
 * Checks whether the server's operating system is Windows (TM).
6144
 * @return boolean - true if the operating system is Windows, false otherwise
6145
 */
6146
function api_is_windows_os()
6147
{
6148
    if (function_exists('php_uname')) {
6149
        // php_uname() exists as of PHP 4.0.2, according to the documentation.
6150
        // We expect that this function will always work for Chamilo 1.8.x.
6151
        $os = php_uname();
6152
    }
6153
    // The following methods are not needed, but let them stay, just in case.
6154
    elseif (isset($_ENV['OS'])) {
6155
        // Sometimes $_ENV['OS'] may not be present (bugs?)
6156
        $os = $_ENV['OS'];
6157
    } elseif (defined('PHP_OS')) {
6158
        // PHP_OS means on which OS PHP was compiled, this is why
6159
        // using PHP_OS is the last choice for detection.
6160
        $os = PHP_OS;
6161
    } else {
6162
        return false;
6163
    }
6164
    return strtolower(substr((string) $os, 0, 3)) == 'win';
6165
}
6166
6167
/**
6168
 * This function informs whether the sent request is XMLHttpRequest
6169
 */
6170
function api_is_xml_http_request()
6171
{
6172
    return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest';
6173
}
6174
6175
/**
6176
 * This wrapper function has been implemented for avoiding some known problems about the function getimagesize().
6177
 * @link http://php.net/manual/en/function.getimagesize.php
6178
 * @link http://www.dokeos.com/forum/viewtopic.php?t=12345
6179
 * @link http://www.dokeos.com/forum/viewtopic.php?t=16355
6180
 * @return integer
6181
 */
6182
function api_getimagesize($path)
6183
{
6184
    $image = new Image($path);
6185
    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 which is incompatible with the documented return type integer.
Loading history...
6186
}
6187
6188
/**
6189
 * This function resizes an image, with preserving its proportions (or aspect ratio).
6190
 * @author Ivan Tcholakov, MAY-2009.
6191
 * @param int $image            System path or URL of the image
6192
 * @param int $target_width     Targeted width
6193
 * @param int $target_height    Targeted height
6194
 * @return array                Calculated new width and height
6195
 */
6196
function api_resize_image($image, $target_width, $target_height)
6197
{
6198
    $image_properties = api_getimagesize($image);
6199
6200
    return api_calculate_image_size(
6201
        $image_properties['width'],
6202
        $image_properties['height'],
6203
        $target_width,
6204
        $target_height
6205
    );
6206
}
6207
6208
/**
6209
 * This function calculates new image size, with preserving image's proportions (or aspect ratio).
6210
 * @author Ivan Tcholakov, MAY-2009.
6211
 * @author The initial idea has been taken from code by Patrick Cool, MAY-2004.
6212
 * @param int $image_width      Initial width
6213
 * @param int $image_height     Initial height
6214
 * @param int $target_width     Targeted width
6215
 * @param int $target_height    Targeted height
6216
 * @return array                Calculated new width and height
6217
 */
6218
function api_calculate_image_size(
6219
    $image_width,
6220
    $image_height,
6221
    $target_width,
6222
    $target_height
6223
) {
6224
    // Only maths is here.
6225
    $result = ['width' => $image_width, 'height' => $image_height];
6226
    if ($image_width <= 0 || $image_height <= 0) {
6227
        return $result;
6228
    }
6229
    $resize_factor_width = $target_width / $image_width;
6230
    $resize_factor_height = $target_height / $image_height;
6231
    $delta_width = $target_width - $image_width * $resize_factor_height;
6232
    $delta_height = $target_height - $image_height * $resize_factor_width;
6233
    if ($delta_width > $delta_height) {
6234
        $result['width'] = ceil($image_width * $resize_factor_height);
6235
        $result['height'] = ceil($image_height * $resize_factor_height);
6236
    } elseif ($delta_width < $delta_height) {
6237
        $result['width'] = ceil($image_width * $resize_factor_width);
6238
        $result['height'] = ceil($image_height * $resize_factor_width);
6239
    } else {
6240
        $result['width'] = ceil($target_width);
6241
        $result['height'] = ceil($target_height);
6242
    }
6243
    return $result;
6244
}
6245
6246
/**
6247
 * Returns a list of Chamilo's tools or
6248
 * checks whether a given identificator is a valid Chamilo's tool.
6249
 * @author Isaac flores paz
6250
 * @param string The tool name to filter
6251
 * @return mixed Filtered string or array
6252
 */
6253
function api_get_tools_lists($my_tool = null)
6254
{
6255
    $tools_list = [
6256
        TOOL_DOCUMENT,
6257
        TOOL_THUMBNAIL,
6258
        TOOL_HOTPOTATOES,
6259
        TOOL_CALENDAR_EVENT,
6260
        TOOL_LINK,
6261
        TOOL_COURSE_DESCRIPTION,
6262
        TOOL_SEARCH,
6263
        TOOL_LEARNPATH,
6264
        TOOL_ANNOUNCEMENT,
6265
        TOOL_FORUM,
6266
        TOOL_THREAD,
6267
        TOOL_POST,
6268
        TOOL_DROPBOX,
6269
        TOOL_QUIZ,
6270
        TOOL_USER,
6271
        TOOL_GROUP,
6272
        TOOL_BLOGS,
6273
        TOOL_CHAT,
6274
        TOOL_STUDENTPUBLICATION,
6275
        TOOL_TRACKING,
6276
        TOOL_HOMEPAGE_LINK,
6277
        TOOL_COURSE_SETTING,
6278
        TOOL_BACKUP,
6279
        TOOL_COPY_COURSE_CONTENT,
6280
        TOOL_RECYCLE_COURSE,
6281
        TOOL_COURSE_HOMEPAGE,
6282
        TOOL_COURSE_RIGHTS_OVERVIEW,
6283
        TOOL_UPLOAD,
6284
        TOOL_COURSE_MAINTENANCE,
6285
        TOOL_SURVEY,
6286
        TOOL_WIKI,
6287
        TOOL_GLOSSARY,
6288
        TOOL_GRADEBOOK,
6289
        TOOL_NOTEBOOK,
6290
        TOOL_ATTENDANCE,
6291
        TOOL_COURSE_PROGRESS,
6292
    ];
6293
    if (empty($my_tool)) {
6294
        return $tools_list;
6295
    }
6296
    return in_array($my_tool, $tools_list) ? $my_tool : '';
6297
}
6298
6299
/**
6300
 * Checks whether we already approved the last version term and condition
6301
 * @param int user id
6302
 * @return bool true if we pass false otherwise
6303
 */
6304
function api_check_term_condition($userId)
6305
{
6306
    if (api_get_setting('allow_terms_conditions') == 'true') {
6307
        // Check if exists terms and conditions
6308
        if (LegalManager::count() == 0) {
6309
            return true;
6310
        }
6311
6312
        $extraFieldValue = new ExtraFieldValue('user');
6313
        $data = $extraFieldValue->get_values_by_handler_and_field_variable(
6314
            $userId,
6315
            'legal_accept'
6316
        );
6317
6318
        if (!empty($data) && isset($data['value']) && !empty($data['value'])) {
6319
            $result = $data['value'];
6320
            $user_conditions = explode(':', $result);
6321
            $version = $user_conditions[0];
6322
            $lang_id = $user_conditions[1];
6323
            $real_version = LegalManager::get_last_version($lang_id);
6324
6325
            return $version >= $real_version;
6326
        }
6327
        return false;
6328
    }
6329
    return false;
6330
}
6331
6332
/**
6333
 * Gets all information of a tool into course
6334
 * @param int The tool id
6335
 * @return array
6336
 */
6337
function api_get_tool_information_by_name($name)
6338
{
6339
    $t_tool = Database::get_course_table(TABLE_TOOL_LIST);
6340
    $course_id = api_get_course_int_id();
6341
    $sql = "SELECT * FROM $t_tool
6342
            WHERE c_id = $course_id  AND name = '".Database::escape_string($name)."' ";
6343
    $rs  = Database::query($sql);
6344
    return Database::fetch_array($rs, 'ASSOC');
6345
}
6346
6347
/**
6348
 * Function used to protect a "global" admin script.
6349
 * The function blocks access when the user has no global platform admin rights.
6350
 * Global admins are the admins that are registered in the main.admin table
6351
 * AND the users who have access to the "principal" portal.
6352
 * That means that there is a record in the main.access_url_rel_user table
6353
 * with his user id and the access_url_id=1
6354
 *
6355
 * @author Julio Montoya
6356
 * @param integer $user_id
6357
 * @return bool
6358
 */
6359
function api_is_global_platform_admin($user_id = null)
6360
{
6361
    $user_id = intval($user_id);
6362
    if (empty($user_id)) {
6363
        $user_id = api_get_user_id();
6364
    }
6365
    if (api_is_platform_admin_by_id($user_id)) {
6366
        $urlList = api_get_access_url_from_user($user_id);
6367
        // The admin is registered in the first "main" site with access_url_id = 1
6368
        if (in_array(1, $urlList)) {
6369
            return true;
6370
        } else {
6371
            return false;
6372
        }
6373
    }
6374
    return false;
6375
}
6376
6377
/**
6378
 * @param int $admin_id_to_check
6379
 * @param int  $my_user_id
6380
 * @param bool $allow_session_admin
6381
 * @return bool
6382
 */
6383
function api_global_admin_can_edit_admin(
6384
    $admin_id_to_check,
6385
    $my_user_id = null,
6386
    $allow_session_admin = false
6387
) {
6388
    if (empty($my_user_id)) {
6389
        $my_user_id = api_get_user_id();
6390
    }
6391
6392
    $iam_a_global_admin = api_is_global_platform_admin($my_user_id);
6393
    $user_is_global_admin = api_is_global_platform_admin($admin_id_to_check);
6394
6395
    if ($iam_a_global_admin) {
6396
        // Global admin can edit everything
6397
        return true;
6398
    } else {
6399
        // If i'm a simple admin
6400
        $is_platform_admin = api_is_platform_admin_by_id($my_user_id);
6401
6402
        if ($allow_session_admin) {
6403
            $is_platform_admin = api_is_platform_admin_by_id($my_user_id) || (api_get_user_status($my_user_id) == SESSIONADMIN);
6404
        }
6405
6406
        if ($is_platform_admin) {
6407
            if ($user_is_global_admin) {
6408
                return false;
6409
            } else {
6410
                return true;
6411
            }
6412
        } else {
6413
            return false;
6414
        }
6415
    }
6416
}
6417
6418
/**
6419
 * @param int $admin_id_to_check
6420
 * @param int  $my_user_id
6421
 * @param bool $allow_session_admin
6422
 * @return boolean|null
6423
 */
6424
function api_protect_super_admin($admin_id_to_check, $my_user_id = null, $allow_session_admin = false)
6425
{
6426
    if (api_global_admin_can_edit_admin($admin_id_to_check, $my_user_id, $allow_session_admin)) {
6427
        return true;
6428
    } else {
6429
        api_not_allowed();
6430
    }
6431
}
6432
6433
/**
6434
 * Function used to protect a global admin script.
6435
 * The function blocks access when the user has no global platform admin rights.
6436
 * See also the api_is_global_platform_admin() function wich defines who's a "global" admin
6437
 *
6438
 * @author Julio Montoya
6439
 */
6440
function api_protect_global_admin_script()
6441
{
6442
    if (!api_is_global_platform_admin()) {
6443
        api_not_allowed();
6444
        return false;
6445
    }
6446
    return true;
6447
}
6448
6449
/**
6450
 * Get active template
6451
 * @param string    theme type (optional: default)
6452
 * @param string    path absolute(abs) or relative(rel) (optional:rel)
6453
 * @return string   actived template path
6454
 */
6455
function api_get_template($path_type = 'rel')
6456
{
6457
    $path_types = ['rel', 'abs'];
6458
    $template_path = '';
6459
    if (in_array($path_type, $path_types)) {
6460
        if ($path_type == 'rel') {
6461
            $template_path = api_get_path(SYS_TEMPLATE_PATH);
6462
        } else {
6463
            $template_path = api_get_path(WEB_TEMPLATE_PATH);
6464
        }
6465
    }
6466
    $actived_theme = 'default';
6467
    if (api_get_setting('active_template')) {
6468
        $actived_theme = api_get_setting('active_template');
6469
    }
6470
    $actived_theme_path = $template_path.$actived_theme.DIRECTORY_SEPARATOR;
6471
    return $actived_theme_path;
6472
}
6473
6474
/**
6475
 * Check browser support for specific file types or features
6476
 * This function checks if the user's browser supports a file format or given
6477
 * feature, or returns the current browser and major version when
6478
 * $format=check_browser. Only a limited number of formats and features are
6479
 * checked by this method. Make sure you check its definition first.
6480
 * @param string $format Can be a file format (extension like svg, webm, ...) or a feature (like autocapitalize, ...)
6481
 *
6482
 * @return bool or return text array if $format=check_browser
6483
 * @author Juan Carlos Raña Trabado
6484
 */
6485
function api_browser_support($format = '')
6486
{
6487
    $browser = new Browser();
6488
    $current_browser = $browser->getBrowser();
6489
    $a_versiontemp = explode('.', $browser->getVersion());
6490
    $current_majorver = $a_versiontemp[0];
6491
6492
    static $result;
6493
6494
    if (isset($result[$format])) {
6495
        return $result[$format];
6496
    }
6497
6498
    // Native svg support
6499
    if ($format == 'svg') {
6500
        if (($current_browser == 'Internet Explorer' && $current_majorver >= 9) ||
6501
            ($current_browser == 'Firefox' && $current_majorver > 1) ||
6502
            ($current_browser == 'Safari' && $current_majorver >= 4) ||
6503
            ($current_browser == 'Chrome' && $current_majorver >= 1) ||
6504
            ($current_browser == 'Opera' && $current_majorver >= 9)
6505
        ) {
6506
            $result[$format] = true;
6507
            return true;
6508
        } else {
6509
            $result[$format] = false;
6510
            return false;
6511
        }
6512
    } elseif ($format == 'pdf') {
6513
        //native pdf support
6514
        if ($current_browser == 'Chrome' && $current_majorver >= 6) {
6515
            $result[$format] = true;
6516
            return true;
6517
        } else {
6518
            $result[$format] = false;
6519
            return false;
6520
        }
6521
    } elseif ($format == 'tif' || $format == 'tiff') {
6522
        //native tif support
6523
        if ($current_browser == 'Safari' && $current_majorver >= 5) {
6524
            $result[$format] = true;
6525
            return true;
6526
        } else {
6527
            $result[$format] = false;
6528
            return false;
6529
        }
6530
    } elseif ($format == 'ogg' || $format == 'ogx' || $format == 'ogv' || $format == 'oga') {
6531
        //native ogg, ogv,oga support
6532
        if (($current_browser == 'Firefox' && $current_majorver >= 3) ||
6533
            ($current_browser == 'Chrome' && $current_majorver >= 3) ||
6534
            ($current_browser == 'Opera' && $current_majorver >= 9)) {
6535
            $result[$format] = true;
6536
            return true;
6537
        } else {
6538
            $result[$format] = false;
6539
            return false;
6540
        }
6541
    } elseif ($format == 'mpg' || $format == 'mpeg') {
6542
        //native mpg support
6543
        if (($current_browser == 'Safari' && $current_majorver >= 5)) {
6544
            $result[$format] = true;
6545
            return true;
6546
        } else {
6547
            $result[$format] = false;
6548
            return false;
6549
        }
6550
    } elseif ($format == 'mp4') {
6551
        //native mp4 support (TODO: Android, iPhone)
6552
        if ($current_browser == 'Android' || $current_browser == 'iPhone') {
6553
            $result[$format] = true;
6554
            return true;
6555
        } else {
6556
            $result[$format] = false;
6557
            return false;
6558
        }
6559
    } elseif ($format == 'mov') {
6560
        //native mov support( TODO:check iPhone)
6561
        if ($current_browser == 'Safari' && $current_majorver >= 5 || $current_browser == 'iPhone') {
6562
            $result[$format] = true;
6563
            return true;
6564
        } else {
6565
            $result[$format] = false;
6566
            return false;
6567
        }
6568
    } elseif ($format == 'avi') {
6569
        //native avi support
6570
        if ($current_browser == 'Safari' && $current_majorver >= 5) {
6571
            $result[$format] = true;
6572
            return true;
6573
        } else {
6574
            $result[$format] = false;
6575
            return false;
6576
        }
6577
    } elseif ($format == 'wmv') {
6578
        //native wmv support
6579
        if ($current_browser == 'Firefox' && $current_majorver >= 4) {
6580
            $result[$format] = true;
6581
            return true;
6582
        } else {
6583
            $result[$format] = false;
6584
            return false;
6585
        }
6586
    } elseif ($format == 'webm') {
6587
        //native webm support (TODO:check IE9, Chrome9, Android)
6588
        if (($current_browser == 'Firefox' && $current_majorver >= 4) ||
6589
            ($current_browser == 'Opera' && $current_majorver >= 9) ||
6590
            ($current_browser == 'Internet Explorer' && $current_majorver >= 9) ||
6591
            ($current_browser == 'Chrome' && $current_majorver >= 9) ||
6592
            $current_browser == 'Android'
6593
        ) {
6594
            $result[$format] = true;
6595
            return true;
6596
        } else {
6597
            $result[$format] = false;
6598
            return false;
6599
        }
6600
    } elseif ($format == 'wav') {
6601
        //native wav support (only some codecs !)
6602
        if (($current_browser == 'Firefox' && $current_majorver >= 4) ||
6603
            ($current_browser == 'Safari' && $current_majorver >= 5) ||
6604
            ($current_browser == 'Opera' && $current_majorver >= 9) ||
6605
            ($current_browser == 'Internet Explorer' && $current_majorver >= 9) ||
6606
            ($current_browser == 'Chrome' && $current_majorver > 9) ||
6607
            $current_browser == 'Android' ||
6608
            $current_browser == 'iPhone'
6609
        ) {
6610
            $result[$format] = true;
6611
            return true;
6612
        } else {
6613
            $result[$format] = false;
6614
            return false;
6615
        }
6616
    } elseif ($format == 'mid' || $format == 'kar') {
6617
        //native midi support (TODO:check Android)
6618
        if ($current_browser == 'Opera' && $current_majorver >= 9 || $current_browser == 'Android') {
6619
            $result[$format] = true;
6620
            return true;
6621
        } else {
6622
            $result[$format] = false;
6623
            return false;
6624
        }
6625
    } elseif ($format == 'wma') {
6626
        //native wma support
6627
        if ($current_browser == 'Firefox' && $current_majorver >= 4) {
6628
            $result[$format] = true;
6629
            return true;
6630
        } else {
6631
            $result[$format] = false;
6632
            return false;
6633
        }
6634
    } elseif ($format == 'au') {
6635
        //native au support
6636
        if ($current_browser == 'Safari' && $current_majorver >= 5) {
6637
            $result[$format] = true;
6638
            return true;
6639
        } else {
6640
            $result[$format] = false;
6641
            return false;
6642
        }
6643
    } elseif ($format == 'mp3') {
6644
        //native mp3 support (TODO:check Android, iPhone)
6645
        if (($current_browser == 'Safari' && $current_majorver >= 5) ||
6646
            ($current_browser == 'Chrome' && $current_majorver >= 6) ||
6647
            ($current_browser == 'Internet Explorer' && $current_majorver >= 9) ||
6648
            $current_browser == 'Android' ||
6649
            $current_browser == 'iPhone' ||
6650
            $current_browser == 'Firefox'
6651
        ) {
6652
            $result[$format] = true;
6653
            return true;
6654
        } else {
6655
            $result[$format] = false;
6656
            return false;
6657
        }
6658
    } elseif ($format == 'autocapitalize') {
6659
        // Help avoiding showing the autocapitalize option if the browser doesn't
6660
        // support it: this attribute is against the HTML5 standard
6661
        if ($current_browser == 'Safari' || $current_browser == 'iPhone') {
6662
            return true;
6663
        } else {
6664
            return false;
6665
        }
6666
    } elseif ($format == "check_browser") {
6667
        $array_check_browser = [$current_browser, $current_majorver];
6668
        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...
6669
    } else {
6670
        $result[$format] = false;
6671
        return false;
6672
    }
6673
}
6674
6675
/**
6676
 * This function checks if exist path and file browscap.ini
6677
 * In order for this to work, your browscap configuration setting in php.ini
6678
 * must point to the correct location of the browscap.ini file on your system
6679
 * http://php.net/manual/en/function.get-browser.php
6680
 *
6681
 * @return bool
6682
 *
6683
 * @author Juan Carlos Raña Trabado
6684
 */
6685
function api_check_browscap()
6686
{
6687
    $setting = ini_get('browscap');
6688
    if ($setting) {
6689
        $browser = get_browser($_SERVER['HTTP_USER_AGENT'], true);
6690
        if (strpos($setting, 'browscap.ini') && !empty($browser)) {
6691
            return true;
6692
        }
6693
    }
6694
    return false;
6695
}
6696
6697
/**
6698
 * Returns the <script> HTML tag
6699
 */
6700
function api_get_js($file)
6701
{
6702
    return '<script type="text/javascript" src="'.api_get_path(WEB_LIBRARY_PATH).'javascript/'.$file.'"></script>'."\n";
6703
}
6704
6705
/**
6706
 * Returns the <script> HTML tag
6707
 * @return string
6708
 */
6709
function api_get_asset($file)
6710
{
6711
    return '<script type="text/javascript" src="'.api_get_path(WEB_PUBLIC_PATH).'assets/'.$file.'"></script>'."\n";
6712
}
6713
6714
/**
6715
 * Returns the <script> HTML tag
6716
 * @return string
6717
 */
6718
function api_get_css_asset($file, $media = 'screen')
6719
{
6720
    return '<link href="'.api_get_path(WEB_PUBLIC_PATH).'assets/'.$file.'" rel="stylesheet" media="'.$media.'" type="text/css" />'."\n";
6721
}
6722
6723
/**
6724
 * Returns the <link> HTML tag
6725
 * @param string $file
6726
 */
6727
function api_get_css($file, $media = 'screen')
6728
{
6729
    return '<link href="'.$file.'" rel="stylesheet" media="'.$media.'" type="text/css" />'."\n";
6730
}
6731
6732
/**
6733
 * Returns the js header to include the jquery library
6734
 */
6735
function api_get_jquery_js()
6736
{
6737
    return api_get_asset('jquery/dist/jquery.min.js');
6738
}
6739
6740
/**
6741
 * Returns the jquery path
6742
 * @return string
6743
 */
6744
function api_get_jquery_web_path()
6745
{
6746
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery/dist/jquery.min.js';
6747
}
6748
6749
/**
6750
 * @return string
6751
 */
6752
function api_get_jquery_ui_js_web_path()
6753
{
6754
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery-ui/jquery-ui.min.js';
6755
}
6756
6757
/**
6758
 * @return string
6759
 */
6760
function api_get_jquery_ui_css_web_path()
6761
{
6762
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery-ui/themes/smoothness/jquery-ui.min.css';
6763
}
6764
6765
/**
6766
 * Returns the jquery-ui library js headers
6767
 * @param   bool    add the jqgrid library
6768
 * @return  string  html tags
6769
 *
6770
 */
6771
function api_get_jquery_ui_js($include_jqgrid = false)
6772
{
6773
    $libraries = [];
6774
    if ($include_jqgrid) {
6775
        $libraries[] = 'jqgrid';
6776
    }
6777
    return api_get_jquery_libraries_js($libraries);
6778
}
6779
6780
function api_get_jqgrid_js()
6781
{
6782
    return api_get_jquery_libraries_js(['jqgrid']);
6783
}
6784
6785
/**
6786
 * Returns the jquery library js and css headers
6787
 *
6788
 * @param   array   list of jquery libraries supported jquery-ui, jqgrid
6789
 * @param   bool    add the jquery library
6790
 * @return  string  html tags
6791
 *
6792
 */
6793
function api_get_jquery_libraries_js($libraries)
6794
{
6795
    $js = '';
6796
    $js_path = api_get_path(WEB_LIBRARY_PATH).'javascript/';
6797
6798
    //jqgrid js and css
6799
    if (in_array('jqgrid', $libraries)) {
6800
        $languaje = 'en';
6801
        $platform_isocode = strtolower(api_get_language_isocode());
6802
6803
        //languages supported by jqgrid see files in main/inc/lib/javascript/jqgrid/js/i18n
6804
        $jqgrid_langs = [
6805
            'bg', 'bg1251', 'cat', 'cn', 'cs', 'da', 'de', 'el', 'en', 'es', 'fa', 'fi', 'fr', 'gl', 'he', 'hu', 'is', 'it', 'ja', 'nl', 'no', 'pl', 'pt-br', 'pt', 'ro', 'ru', 'sk', 'sr', 'sv', 'tr', 'ua'
6806
        ];
6807
6808
        if (in_array($platform_isocode, $jqgrid_langs)) {
6809
            $languaje = $platform_isocode;
6810
        }
6811
        //$js .= '<link rel="stylesheet" href="'.$js_path.'jqgrid/css/ui.jqgrid.css" type="text/css">';
6812
        $js .= api_get_css($js_path.'jqgrid/css/ui.jqgrid.css');
6813
        $js .= api_get_js('jqgrid/js/i18n/grid.locale-'.$languaje.'.js');
6814
        $js .= api_get_js('jqgrid/js/jquery.jqGrid.min.js');
6815
    }
6816
6817
    //Document multiple upload funcionality
6818
    if (in_array('jquery-uploadzs', $libraries)) {
6819
        $js .= api_get_asset('blueimp-load-image/js/load-image.all.min.js');
6820
        $js .= api_get_asset('blueimp-canvas-to-blob/js/canvas-to-blob.min.js');
6821
        $js .= api_get_asset('jquery-file-upload/js/jquery.iframe-transport.js');
6822
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload.js');
6823
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-process.js');
6824
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-image.js');
6825
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-audio.js');
6826
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-video.js');
6827
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-validate.js');
6828
6829
        $js .= api_get_css(api_get_path(WEB_PUBLIC_PATH).'assets/jquery-file-upload/css/jquery.fileupload.css');
6830
        $js .= api_get_css(api_get_path(WEB_PUBLIC_PATH).'assets/jquery-file-upload/css/jquery.fileupload-ui.css');
6831
    }
6832
6833
    // jquery datepicker
6834
    if (in_array('datepicker', $libraries)) {
6835
        $languaje = 'en-GB';
6836
        $platform_isocode = strtolower(api_get_language_isocode());
6837
6838
        // languages supported by jqgrid see files in main/inc/lib/javascript/jqgrid/js/i18n
6839
        $datapicker_langs = [
6840
            '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'
6841
        ];
6842
        if (in_array($platform_isocode, $datapicker_langs)) {
6843
            $languaje = $platform_isocode;
6844
        }
6845
6846
        $js .= api_get_js('jquery-ui/jquery-ui-i18n.min.js');
6847
        $script = '<script>
6848
        $(function(){
6849
            $.datepicker.setDefaults($.datepicker.regional["'.$languaje.'"]);
6850
            $.datepicker.regional["local"] = $.datepicker.regional["'.$languaje.'"];
6851
        });
6852
        </script>
6853
        ';
6854
        $js .= $script;
6855
    }
6856
    return $js;
6857
}
6858
6859
/**
6860
 * Returns the course's URL
6861
 *
6862
 * This function relies on api_get_course_info()
6863
 * @param   string  The course code - optional (takes it from session if not given)
6864
 * @param   int     The session id  - optional (takes it from session if not given)
6865
 * @param integer $session_id
6866
 * @return  string|null   The URL of the course or null if something does not work
6867
 * @author  Julio Montoya <[email protected]>
6868
 */
6869
function api_get_course_url($course_code = null, $session_id = null)
6870
{
6871
    if (empty($course_code)) {
6872
        $course_info = api_get_course_info();
6873
    } else {
6874
        $course_info = api_get_course_info($course_code);
6875
    }
6876
    if (empty($session_id)) {
6877
        $session_url = '?id_session='.api_get_session_id();
6878
    } else {
6879
        $session_url = '?id_session='.intval($session_id);
6880
    }
6881
    /*
6882
    if (empty($group_id)) {
6883
        $group_url = '&gidReq='.api_get_group_id();
6884
    } else {
6885
        $group_url = '&gidReq='.intval($group_id);
6886
    }*/
6887
    if (!empty($course_info['path'])) {
6888
        return api_get_path(WEB_COURSE_PATH).$course_info['path'].'/index.php'.$session_url;
6889
    }
6890
    return null;
6891
}
6892
6893
/**
6894
 *
6895
 * Check if the current portal has the $_configuration['multiple_access_urls'] parameter on
6896
 * @return bool true if multi site is enabled
6897
 *
6898
 **/
6899
function api_get_multiple_access_url()
6900
{
6901
    global $_configuration;
6902
    if (isset($_configuration['multiple_access_urls']) && $_configuration['multiple_access_urls']) {
6903
        return true;
6904
    }
6905
    return false;
6906
}
6907
6908
/**
6909
 * @return bool
6910
 */
6911
function api_is_multiple_url_enabled()
6912
{
6913
    return api_get_multiple_access_url();
6914
}
6915
6916
/**
6917
 * Returns a md5 unique id
6918
 * @todo add more parameters
6919
 */
6920
function api_get_unique_id()
6921
{
6922
    $id = md5(time().uniqid().api_get_user_id().api_get_course_id().api_get_session_id());
6923
    return $id;
6924
}
6925
6926
/**
6927
 * Get home path
6928
 * @return string
6929
 */
6930
function api_get_home_path()
6931
{
6932
    // FIX : Start the routing determination from central path definition
6933
    $home = api_get_path(SYS_HOME_PATH);
6934
    if (api_get_multiple_access_url()) {
6935
        $access_url_id = api_get_current_access_url_id();
6936
        $url_info = api_get_access_url($access_url_id);
6937
        $url = api_remove_trailing_slash(preg_replace('/https?:\/\//i', '', $url_info['url']));
6938
        $clean_url = api_replace_dangerous_char($url);
6939
        $clean_url = str_replace('/', '-', $clean_url);
6940
        $clean_url .= '/';
6941
        if ($clean_url != 'localhost/') {
6942
            // means that the multiple URL was not well configured we don't rename the $home variable
6943
            return "{$home}{$clean_url}";
6944
        }
6945
    }
6946
6947
    return $home;
6948
}
6949
6950
/**
6951
 *
6952
 * @param int Course id
6953
 * @param int tool id: TOOL_QUIZ, TOOL_FORUM, TOOL_STUDENTPUBLICATION, TOOL_LEARNPATH
6954
 * @param int the item id (tool id, exercise id, lp id)
6955
 * @return bool
6956
 */
6957
function api_resource_is_locked_by_gradebook($item_id, $link_type, $course_code = null)
6958
{
6959
    if (api_is_platform_admin()) {
6960
        return false;
6961
    }
6962
    if (api_get_setting('gradebook_locking_enabled') == 'true') {
6963
        if (empty($course_code)) {
6964
            $course_code = api_get_course_id();
6965
        }
6966
        $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_LINK);
6967
        $item_id = intval($item_id);
6968
        $link_type = intval($link_type);
6969
        $course_code = Database::escape_string($course_code);
6970
        $sql = "SELECT locked FROM $table
6971
                WHERE locked = 1 AND ref_id = $item_id AND type = $link_type AND course_code = '$course_code' ";
6972
        $result = Database::query($sql);
6973
        if (Database::num_rows($result)) {
6974
            return true;
6975
        }
6976
    }
6977
    return false;
6978
}
6979
6980
/**
6981
 * Blocks a page if the item was added in a gradebook
6982
 *
6983
 * @param int       exercise id, work id, thread id,
6984
 * @param int       LINK_EXERCISE, LINK_STUDENTPUBLICATION, LINK_LEARNPATH LINK_FORUM_THREAD, LINK_ATTENDANCE
6985
 * see gradebook/lib/be/linkfactory
6986
 * @param string    course code
6987
 * @return false|null
6988
 */
6989
function api_block_course_item_locked_by_gradebook($item_id, $link_type, $course_code = null)
6990
{
6991
    if (api_is_platform_admin()) {
6992
        return false;
6993
    }
6994
6995
    if (api_resource_is_locked_by_gradebook($item_id, $link_type, $course_code)) {
6996
        $message = Display::return_message(get_lang('ResourceLockedByGradebook'), 'warning');
6997
        api_not_allowed(true, $message);
6998
    }
6999
}
7000
7001
/**
7002
 * Checks the PHP version installed is enough to run Chamilo
7003
 * @param string Include path (used to load the error page)
7004
 * @return void
7005
 */
7006
function api_check_php_version($my_inc_path = null)
7007
{
7008
    if (!function_exists('version_compare') || version_compare(phpversion(), REQUIRED_PHP_VERSION, '<')) {
7009
        $global_error_code = 1;
7010
        // Incorrect PHP version
7011
        $global_page = $my_inc_path.'global_error_message.inc.php';
7012
        if (file_exists($global_page)) {
7013
            require $global_page;
7014
        }
7015
        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...
7016
    }
7017
}
7018
7019
/**
7020
 * Checks whether the Archive directory is present and writeable. If not,
7021
 * prints a warning message.
7022
 */
7023
function api_check_archive_dir()
7024
{
7025
    if (is_dir(api_get_path(SYS_ARCHIVE_PATH)) && !is_writable(api_get_path(SYS_ARCHIVE_PATH))) {
7026
        $message = Display::return_message(get_lang('ArchivesDirectoryNotWriteableContactAdmin'), 'warning');
7027
        api_not_allowed(true, $message);
7028
    }
7029
}
7030
7031
/**
7032
 * Returns an array of global configuration settings which should be ignored
7033
 * when printing the configuration settings screens
7034
 * @return array Array of strings, each identifying one of the excluded settings
7035
 */
7036
function api_get_locked_settings()
7037
{
7038
    return [
7039
        'server_type',
7040
        'permanently_remove_deleted_files',
7041
        'account_valid_duration',
7042
        'service_ppt2lp',
7043
        'wcag_anysurfer_public_pages',
7044
        'upload_extensions_list_type',
7045
        'upload_extensions_blacklist',
7046
        'upload_extensions_whitelist',
7047
        'upload_extensions_skip',
7048
        'upload_extensions_replace_by',
7049
        'hide_dltt_markup',
7050
        'split_users_upload_directory',
7051
        'permissions_for_new_directories',
7052
        'permissions_for_new_files',
7053
        'platform_charset',
7054
        'ldap_description',
7055
        'cas_activate',
7056
        'cas_server',
7057
        'cas_server_uri',
7058
        'cas_port',
7059
        'cas_protocol',
7060
        'cas_add_user_activate',
7061
        'update_user_info_cas_with_ldap',
7062
        'languagePriority1',
7063
        'languagePriority2',
7064
        'languagePriority3',
7065
        'languagePriority4',
7066
        'login_is_email',
7067
        'chamilo_database_version'
7068
    ];
7069
}
7070
7071
/**
7072
 * Checks if the user is corrently logged in. Returns the user ID if he is, or
7073
 * false if he isn't. If the user ID is given and is an integer, then the same
7074
 * ID is simply returned
7075
 * @param  integer User ID
7076
 * @return boolean Integer User ID is logged in, or false otherwise
7077
 */
7078
function api_user_is_login($user_id = null)
7079
{
7080
    $user_id = empty($user_id) ? api_get_user_id() : intval($user_id);
7081
    return $user_id && !api_is_anonymous();
7082
}
7083
7084
/**
7085
 * Guess the real ip for register in the database, even in reverse proxy cases.
7086
 * To be recognized, the IP has to be found in either $_SERVER['REMOTE_ADDR'] or
7087
 * in $_SERVER['HTTP_X_FORWARDED_FOR'], which is in common use with rproxies.
7088
 * @return string the user's real ip (unsafe - escape it before inserting to db)
7089
 * @author Jorge Frisancho Jibaja <[email protected]>, USIL - Some changes to allow the use of real IP using reverse proxy
7090
 * @version CEV CHANGE 24APR2012
7091
 */
7092
function api_get_real_ip()
7093
{
7094
    // Guess the IP if behind a reverse proxy
7095
    global $debug;
7096
    $ip = trim($_SERVER['REMOTE_ADDR']);
7097
    if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
7098
        if (preg_match('/,/', $_SERVER['HTTP_X_FORWARDED_FOR'])) {
7099
            @list($ip1, $ip2) = @explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
7100
        } else {
7101
            $ip1 = $_SERVER['HTTP_X_FORWARDED_FOR'];
7102
        }
7103
        $ip = trim($ip1);
7104
    }
7105
    if (!empty($debug)) {
7106
        error_log('Real IP: '.$ip);
7107
    }
7108
    return $ip;
7109
}
7110
7111
/**
7112
 * Checks whether an IP is included inside an IP range
7113
 * @param string IP address
7114
 * @param string IP range
7115
 * @param string $ip
7116
 * @return bool True if IP is in the range, false otherwise
7117
 * @author claudiu at cnixs dot com  on http://www.php.net/manual/fr/ref.network.php#55230
7118
 * @author Yannick Warnier for improvements and managment of multiple ranges
7119
 * @todo check for IPv6 support
7120
 */
7121
function api_check_ip_in_range($ip, $range)
7122
{
7123
    if (empty($ip) or empty($range)) {
7124
        return false;
7125
    }
7126
    $ip_ip = ip2long($ip);
7127
    // divide range param into array of elements
7128
    if (strpos($range, ',') !== false) {
7129
        $ranges = explode(',', $range);
7130
    } else {
7131
        $ranges = [$range];
7132
    }
7133
    foreach ($ranges as $range) {
7134
        $range = trim($range);
7135
        if (empty($range)) {
7136
            continue;
7137
        }
7138
        if (strpos($range, '/') === false) {
7139
            if (strcmp($ip, $range) === 0) {
7140
                return true; // there is a direct IP match, return OK
7141
            }
7142
            continue; //otherwise, get to the next range
7143
        }
7144
        // the range contains a "/", so analyse completely
7145
        list($net, $mask) = explode("/", $range);
7146
7147
        $ip_net = ip2long($net);
7148
        // mask binary magic
7149
        $ip_mask = ~((1 << (32 - $mask)) - 1);
7150
7151
        $ip_ip_net = $ip_ip & $ip_mask;
7152
        if ($ip_ip_net == $ip_net) {
7153
            return true;
7154
        }
7155
    }
7156
7157
    return false;
7158
}
7159
7160
function api_check_user_access_to_legal($course_visibility)
7161
{
7162
    $course_visibility_list = [COURSE_VISIBILITY_OPEN_WORLD, COURSE_VISIBILITY_OPEN_PLATFORM];
7163
    return in_array($course_visibility, $course_visibility_list) || api_is_drh();
7164
}
7165
7166
/**
7167
 * Checks if the global chat is enabled or not
7168
 *
7169
 * @return bool
7170
 */
7171
function api_is_global_chat_enabled()
7172
{
7173
    return
7174
        !api_is_anonymous() &&
7175
        api_get_setting('allow_global_chat') == 'true' &&
7176
        api_get_setting('allow_social_tool') == 'true';
7177
}
7178
7179
/**
7180
 * @todo Fix tool_visible_by_default_at_creation labels
7181
 * @todo Add sessionId parameter to avoid using context
7182
 *
7183
 * @param int $item_id
7184
 * @param int $tool_id
7185
 * @param int $group_id id
7186
 * @param array $courseInfo
7187
 * @param int $sessionId
7188
 * @param int $userId
7189
 */
7190
function api_set_default_visibility(
7191
    $item_id,
7192
    $tool_id,
7193
    $group_id = 0,
7194
    $courseInfo = [],
7195
    $sessionId = 0,
7196
    $userId = 0
7197
) {
7198
    $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
7199
    $courseId = $courseInfo['real_id'];
7200
    $courseCode = $courseInfo['code'];
7201
    $sessionId = empty($sessionId) ? api_get_session_id() : $sessionId;
7202
    $userId = empty($userId) ? api_get_user_id() : $userId;
7203
7204
    if (empty($group_id)) {
7205
        $group_id = api_get_group_id();
7206
    }
7207
7208
    $groupInfo = GroupManager::get_group_properties($group_id);
7209
    $original_tool_id = $tool_id;
7210
7211
    switch ($tool_id) {
7212
        case TOOL_LINK:
7213
        case TOOL_LINK_CATEGORY:
7214
            $tool_id = 'links';
7215
            break;
7216
        case TOOL_DOCUMENT:
7217
            $tool_id = 'documents';
7218
            break;
7219
        case TOOL_LEARNPATH:
7220
            $tool_id = 'learning';
7221
            break;
7222
        case TOOL_ANNOUNCEMENT:
7223
            $tool_id = 'announcements';
7224
            break;
7225
        case TOOL_FORUM:
7226
        case TOOL_FORUM_CATEGORY:
7227
        case TOOL_FORUM_THREAD:
7228
            $tool_id = 'forums';
7229
            break;
7230
        case TOOL_QUIZ:
7231
            $tool_id = 'quiz';
7232
            break;
7233
    }
7234
    $setting = api_get_setting('tool_visible_by_default_at_creation');
7235
7236
    if (isset($setting[$tool_id])) {
7237
        $visibility = 'invisible';
7238
        if ($setting[$tool_id] == 'true') {
7239
            $visibility = 'visible';
7240
        }
7241
7242
        // Read the portal and course default visibility
7243
        if ($tool_id == 'documents') {
7244
            $visibility = DocumentManager::getDocumentDefaultVisibility($courseCode);
7245
        }
7246
7247
        api_item_property_update(
7248
            $courseInfo,
7249
            $original_tool_id,
7250
            $item_id,
7251
            $visibility,
7252
            $userId,
7253
            $groupInfo,
7254
            null,
7255
            null,
7256
            null,
7257
            $sessionId
7258
        );
7259
7260
        // Fixes default visibility for tests
7261
        switch ($original_tool_id) {
7262
            case TOOL_QUIZ:
7263
                if (empty($sessionId)) {
7264
                    $objExerciseTmp = new Exercise($courseId);
7265
                    $objExerciseTmp->read($item_id);
7266
                    if ($visibility == 'visible') {
7267
                        $objExerciseTmp->enable();
7268
                        $objExerciseTmp->save();
7269
                    } else {
7270
                        $objExerciseTmp->disable();
7271
                        $objExerciseTmp->save();
7272
                    }
7273
                }
7274
                break;
7275
        }
7276
    }
7277
}
7278
7279
/**
7280
 * @return string
7281
 */
7282
function api_get_security_key()
7283
{
7284
    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') could also return false which is incompatible with the documented return type string. 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...
7285
}
7286
7287
/**
7288
 * @param int $user_id
7289
 * @param int $courseId
7290
 * @param int $session_id
7291
 * @return array
7292
 */
7293
function api_detect_user_roles($user_id, $courseId, $session_id = 0)
7294
{
7295
    $user_roles = [];
7296
    $courseInfo = api_get_course_info_by_id($courseId);
7297
    $course_code = $courseInfo['code'];
7298
7299
    $url_id = api_get_current_access_url_id();
7300
    if (api_is_platform_admin_by_id($user_id, $url_id)) {
7301
        $user_roles[] = PLATFORM_ADMIN;
7302
    }
7303
7304
    /*if (api_is_drh()) {
7305
        $user_roles[] = DRH;
7306
    }*/
7307
7308
    if (!empty($session_id)) {
7309
        if (SessionManager::user_is_general_coach($user_id, $session_id)) {
7310
            $user_roles[] = SESSION_GENERAL_COACH;
7311
        }
7312
    }
7313
7314
    if (!empty($course_code)) {
7315
        if (empty($session_id)) {
7316
            if (CourseManager::is_course_teacher($user_id, $course_code)) {
7317
                $user_roles[] = COURSEMANAGER;
7318
            }
7319
            if (CourseManager::get_tutor_in_course_status($user_id, $courseInfo['real_id'])) {
7320
                $user_roles[] = COURSE_TUTOR;
7321
            }
7322
7323
            if (CourseManager::is_user_subscribed_in_course($user_id, $course_code)) {
7324
                $user_roles[] = COURSE_STUDENT;
7325
            }
7326
        } else {
7327
            $user_status_in_session = SessionManager::get_user_status_in_course_session(
7328
                $user_id,
7329
                $courseId,
7330
                $session_id
7331
            );
7332
7333
            if (!empty($user_status_in_session)) {
7334
                if ($user_status_in_session == 0) {
7335
                    $user_roles[] = SESSION_STUDENT;
7336
                }
7337
                if ($user_status_in_session == 2) {
7338
                    $user_roles[] = SESSION_COURSE_COACH;
7339
                }
7340
            }
7341
7342
            /*if (api_is_course_session_coach($user_id, $course_code, $session_id)) {
7343
               $user_roles[] = SESSION_COURSE_COACH;
7344
            }*/
7345
        }
7346
    }
7347
    return $user_roles;
7348
}
7349
7350
/**
7351
 * @param int $courseId
7352
 * @param int $session_id
7353
 * @return bool
7354
 */
7355
function api_coach_can_edit_view_results($courseId = null, $session_id = null)
7356
{
7357
    if (api_is_platform_admin()) {
7358
        return true;
7359
    }
7360
7361
    $user_id = api_get_user_id();
7362
7363
    if (empty($courseId)) {
7364
        $courseId = api_get_course_int_id();
7365
    }
7366
7367
    if (empty($session_id)) {
7368
        $session_id = api_get_session_id();
7369
    }
7370
7371
    $roles = api_detect_user_roles($user_id, $courseId, $session_id);
7372
7373
    if (in_array(SESSION_COURSE_COACH, $roles)) {
7374
        //return api_get_setting('session_tutor_reports_visibility') == 'true';
7375
        return true;
7376
    } else {
7377
        if (in_array(COURSEMANAGER, $roles)) {
7378
            return true;
7379
        }
7380
        return false;
7381
    }
7382
}
7383
7384
/**
7385
 * @param string $file
7386
 * @return string
7387
 */
7388
function api_get_js_simple($file)
7389
{
7390
    return '<script type="text/javascript" src="'.$file.'"></script>'."\n";
7391
}
7392
7393
function api_set_settings_and_plugins()
7394
{
7395
    global $_configuration;
7396
    $_setting = [];
7397
    $_plugins = [];
7398
7399
    // access_url == 1 is the default chamilo location
7400
    $settings_by_access_list = [];
7401
    $access_url_id = api_get_current_access_url_id();
7402
    if ($access_url_id != 1) {
7403
        $url_info = api_get_access_url($_configuration['access_url']);
7404
        if ($url_info['active'] == 1) {
7405
            $settings_by_access = & api_get_settings(null, 'list', $_configuration['access_url'], 1);
7406
            foreach ($settings_by_access as & $row) {
7407
                if (empty($row['variable'])) {
7408
                    $row['variable'] = 0;
7409
                }
7410
                if (empty($row['subkey'])) {
7411
                    $row['subkey'] = 0;
7412
                }
7413
                if (empty($row['category'])) {
7414
                    $row['category'] = 0;
7415
                }
7416
                $settings_by_access_list[$row['variable']][$row['subkey']][$row['category']] = $row;
7417
            }
7418
        }
7419
    }
7420
7421
    $result = api_get_settings(null, 'list', 1);
7422
7423
    foreach ($result as & $row) {
7424
        if ($access_url_id != 1) {
7425
            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...
7426
                $var = empty($row['variable']) ? 0 : $row['variable'];
7427
                $subkey = empty($row['subkey']) ? 0 : $row['subkey'];
7428
                $category = empty($row['category']) ? 0 : $row['category'];
7429
            }
7430
7431
            if ($row['access_url_changeable'] == 1 && $url_info['active'] == 1) {
7432
                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...
7433
                    $settings_by_access_list[$var][$subkey][$category]['selected_value'] != '') {
0 ignored issues
show
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...
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...
7434
                    if ($row['subkey'] == null) {
7435
                        $_setting[$row['variable']] = $settings_by_access_list[$var][$subkey][$category]['selected_value'];
7436
                    } else {
7437
                        $_setting[$row['variable']][$row['subkey']] = $settings_by_access_list[$var][$subkey][$category]['selected_value'];
7438
                    }
7439
                } else {
7440
                    if ($row['subkey'] == null) {
7441
                        $_setting[$row['variable']] = $row['selected_value'];
7442
                    } else {
7443
                        $_setting[$row['variable']][$row['subkey']] = $row['selected_value'];
7444
                    }
7445
                }
7446
            } else {
7447
                if ($row['subkey'] == null) {
7448
                    $_setting[$row['variable']] = $row['selected_value'];
7449
                } else {
7450
                    $_setting[$row['variable']][$row['subkey']] = $row['selected_value'];
7451
                }
7452
            }
7453
        } else {
7454
            if ($row['subkey'] == null) {
7455
                $_setting[$row['variable']] = $row['selected_value'];
7456
            } else {
7457
                $_setting[$row['variable']][$row['subkey']] = $row['selected_value'];
7458
            }
7459
        }
7460
    }
7461
7462
    $result = api_get_settings('Plugins', 'list', $access_url_id);
7463
    $_plugins = [];
7464
    foreach ($result as & $row) {
7465
        $key = & $row['variable'];
7466
        if (is_string($_setting[$key])) {
7467
            $_setting[$key] = [];
7468
        }
7469
        $_setting[$key][] = $row['selected_value'];
7470
        $_plugins[$key][] = $row['selected_value'];
7471
    }
7472
7473
    $_SESSION['_setting'] = $_setting;
7474
    $_SESSION['_plugins'] = $_plugins;
7475
}
7476
7477
/**
7478
 * Tries to set memory limit, if authorized and new limit is higher than current
7479
 * @param string $mem New memory limit
7480
 * @return bool True on success, false on failure or current is higher than suggested
7481
 * @assert (null) === false
7482
 * @assert (-1) === false
7483
 * @assert (0) === true
7484
 * @assert ('1G') === true
7485
 */
7486
function api_set_memory_limit($mem)
7487
{
7488
    //if ini_set() not available, this function is useless
7489
    if (!function_exists('ini_set') || is_null($mem) || $mem == -1) {
7490
        return false;
7491
    }
7492
7493
    $memory_limit = ini_get('memory_limit');
7494
    if (api_get_bytes_memory_limit($mem) > api_get_bytes_memory_limit($memory_limit)) {
7495
        ini_set('memory_limit', $mem);
7496
        return true;
7497
    }
7498
    return false;
7499
}
7500
7501
/**
7502
 * Gets memory limit in bytes
7503
 * @param string The memory size (128M, 1G, 1000K, etc)
7504
 * @return int
7505
 * @assert (null) === false
7506
 * @assert ('1t')  === 1099511627776
7507
 * @assert ('1g')  === 1073741824
7508
 * @assert ('1m')  === 1048576
7509
 * @assert ('100k') === 102400
7510
 */
7511
function api_get_bytes_memory_limit($mem)
7512
{
7513
    $size = strtolower(substr($mem, -1));
7514
7515
    switch ($size) {
7516
        case 't':
7517
            $mem = intval(substr($mem, -1)) * 1024 * 1024 * 1024 * 1024;
7518
            break;
7519
        case 'g':
7520
            $mem = intval(substr($mem, 0, -1)) * 1024 * 1024 * 1024;
7521
            break;
7522
        case 'm':
7523
            $mem = intval(substr($mem, 0, -1)) * 1024 * 1024;
7524
            break;
7525
        case 'k':
7526
            $mem = intval(substr($mem, 0, -1)) * 1024;
7527
            break;
7528
        default:
7529
            // we assume it's integer only
7530
            $mem = intval($mem);
7531
            break;
7532
    }
7533
    return $mem;
7534
}
7535
7536
/**
7537
 * Finds all the information about a user from username instead of user id
7538
 *
7539
 * @param string $officialCode
7540
 * @return array $user_info user_id, lastname, firstname, username, email, ...
7541
 * @author Yannick Warnier <[email protected]>
7542
 */
7543
function api_get_user_info_from_official_code($officialCode)
7544
{
7545
    if (empty($officialCode)) {
7546
        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...
7547
    }
7548
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
7549
            WHERE official_code ='".Database::escape_string($officialCode)."'";
7550
    $result = Database::query($sql);
7551
    if (Database::num_rows($result) > 0) {
7552
        $result_array = Database::fetch_array($result);
7553
        return _api_format_user($result_array);
7554
    }
7555
    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...
7556
}
7557
7558
/**
7559
 * @param string $usernameInputId
7560
 * @param string $passwordInputId
7561
 * @return null|string
7562
 */
7563
function api_get_password_checker_js($usernameInputId, $passwordInputId)
7564
{
7565
    $checkPass = api_get_setting('allow_strength_pass_checker');
7566
    $useStrengthPassChecker = $checkPass === 'true';
7567
7568
    if ($useStrengthPassChecker === false) {
7569
        return null;
7570
    }
7571
7572
    $translations = [
7573
        'wordLength' => get_lang('PasswordIsTooShort'),
7574
        'wordNotEmail' => get_lang('YourPasswordCannotBeTheSameAsYourEmail'),
7575
        'wordSimilarToUsername' => get_lang('YourPasswordCannotContainYourUsername'),
7576
        'wordTwoCharacterClasses' => get_lang('WordTwoCharacterClasses'),
7577
        'wordRepetitions' => get_lang('TooManyRepetitions'),
7578
        'wordSequences' => get_lang('YourPasswordContainsSequences'),
7579
        'errorList' => get_lang('ErrorsFound'),
7580
        'veryWeak' => get_lang('PasswordVeryWeak'),
7581
        'weak' => get_lang('PasswordWeak'),
7582
        'normal' => get_lang('PasswordNormal'),
7583
        'medium' => get_lang('PasswordMedium'),
7584
        'strong' => get_lang('PasswordStrong'),
7585
        'veryStrong' => get_lang('PasswordVeryStrong')
7586
    ];
7587
7588
    $js = api_get_asset('pwstrength-bootstrap/dist/pwstrength-bootstrap.min.js');
7589
    $js .= "<script>    
7590
    var errorMessages = {
7591
        password_to_short : \"" . get_lang('PasswordIsTooShort')."\",
7592
        same_as_username : \"".get_lang('YourPasswordCannotBeTheSameAsYourUsername')."\"
7593
    };
7594
7595
    $(document).ready(function() {
7596
        var lang = ".json_encode($translations).";     
7597
        var options = {        
7598
            onLoad : function () {
7599
                //$('#messages').text('Start typing password');
7600
            },
7601
            onKeyUp: function (evt) {
7602
                $(evt.target).pwstrength('outputErrorList');
7603
            },
7604
            errorMessages : errorMessages,
7605
            viewports: {
7606
                progress: '#password_progress',
7607
                verdict: '#password-verdict',
7608
                errors: '#password-errors'
7609
            },
7610
            usernameField: '$usernameInputId'
7611
        };
7612
        options.i18n = {
7613
            t: function (key) {
7614
                var result = lang[key];
7615
                return result === key ? '' : result; // This assumes you return the                
7616
            }
7617
        };
7618
        $('".$passwordInputId."').pwstrength(options);
7619
    });
7620
    </script>";
7621
7622
    return $js;
7623
}
7624
7625
/**
7626
 * create an user extra field called 'captcha_blocked_until_date'
7627
 * @param string $username
7628
 * @return bool
7629
 */
7630
function api_block_account_captcha($username)
7631
{
7632
    $userInfo = api_get_user_info_from_username($username);
7633
    if (empty($userInfo)) {
7634
        return false;
7635
    }
7636
    $minutesToBlock = api_get_setting('captcha_time_to_block');
7637
    $time = time() + $minutesToBlock * 60;
7638
    UserManager::update_extra_field_value(
7639
        $userInfo['user_id'],
7640
        'captcha_blocked_until_date',
7641
        api_get_utc_datetime($time)
7642
    );
7643
    return true;
7644
}
7645
7646
/**
7647
 * @param string $username
7648
 * @return bool
7649
 */
7650
function api_clean_account_captcha($username)
7651
{
7652
    $userInfo = api_get_user_info_from_username($username);
7653
    if (empty($userInfo)) {
7654
        return false;
7655
    }
7656
    Session::erase('loginFailedCount');
7657
    UserManager::update_extra_field_value(
7658
        $userInfo['user_id'],
7659
        'captcha_blocked_until_date',
7660
        null
7661
    );
7662
    return true;
7663
}
7664
7665
/**
7666
 * @param string $username
7667
 * @return bool
7668
 */
7669
function api_get_user_blocked_by_captcha($username)
7670
{
7671
    $userInfo = api_get_user_info_from_username($username);
7672
    if (empty($userInfo)) {
7673
        return false;
7674
    }
7675
    $data = UserManager::get_extra_user_data_by_field(
7676
        $userInfo['user_id'],
7677
        'captcha_blocked_until_date'
7678
    );
7679
    if (isset($data) && isset($data['captcha_blocked_until_date'])) {
7680
        return $data['captcha_blocked_until_date'];
7681
    }
7682
    return false;
7683
}
7684
7685
/**
7686
 * Remove tags from HTML anf return the $in_number_char first non-HTML char
7687
 * Postfix the text with "..." if it has been truncated.
7688
 * @param string $text
7689
 * @param integer $number
7690
 *
7691
 * @return string
7692
 * @author hubert borderiou
7693
 */
7694
function api_get_short_text_from_html($text, $number)
7695
{
7696
    // Delete script and style tags
7697
    $text =  preg_replace('/(<(script|style)\b[^>]*>).*?(<\/\2>)/is', "$1$3", $text);
7698
    $text = api_html_entity_decode($text);
7699
    $out_res = api_remove_tags_with_space($text, false);
7700
    $postfix = "...";
7701
    if (strlen($out_res) > $number) {
7702
        $out_res = substr($out_res, 0, $number).$postfix;
7703
    }
7704
    return $out_res;
7705
}
7706
7707
/**
7708
 * Replace tags with a space in a text.
7709
 * If $in_double_quote_replace, replace " with '' (for HTML attribute purpose, for exemple)
7710
 * @return string
7711
 * @author hubert borderiou
7712
 */
7713
function api_remove_tags_with_space($in_html, $in_double_quote_replace = true)
7714
{
7715
    $out_res = $in_html;
7716
    if ($in_double_quote_replace) {
7717
        $out_res = str_replace('"', "''", $out_res);
7718
    }
7719
    // avoid text stuck together when tags are removed, adding a space after >
7720
    $out_res = str_replace(">", "> ", $out_res);
7721
    $out_res = strip_tags($out_res);
7722
7723
    return $out_res;
7724
}
7725
7726
/**
7727
 * If true, the drh can access all content (courses, users) inside a session
7728
 * @return bool
7729
 */
7730
function api_drh_can_access_all_session_content()
7731
{
7732
    $value = api_get_setting('drh_can_access_all_session_content');
7733
7734
    return $value === 'true';
7735
}
7736
7737
/**
7738
 * @param string $tool
7739
 * @param string $setting
7740
 * @param integer $defaultValue
7741
 * @return string
7742
 */
7743
function api_get_default_tool_setting($tool, $setting, $defaultValue)
7744
{
7745
    global $_configuration;
7746
    if (isset($_configuration[$tool]) &&
7747
        isset($_configuration[$tool]['default_settings']) &&
7748
        isset($_configuration[$tool]['default_settings'][$setting])
7749
    ) {
7750
        return $_configuration[$tool]['default_settings'][$setting];
7751
    }
7752
7753
    return $defaultValue;
7754
}
7755
7756
/**
7757
 * Checks if user can login as another user
7758
 *
7759
 * @param int $loginAsUserId the user id to log in
7760
 * @param int $userId my user id
7761
 * @return bool
7762
 */
7763
function api_can_login_as($loginAsUserId, $userId = null)
7764
{
7765
    if (empty($userId)) {
7766
        $userId = api_get_user_id();
7767
    }
7768
    if ($loginAsUserId == $userId) {
7769
        return false;
7770
    }
7771
7772
    if (empty($loginAsUserId)) {
7773
        return false;
7774
    }
7775
7776
    if ($loginAsUserId != strval(intval($loginAsUserId))) {
7777
        return false;
7778
    }
7779
7780
    // Check if the user to login is an admin
7781
    if (api_is_platform_admin_by_id($loginAsUserId)) {
7782
        // Only super admins can login to admin accounts
7783
        if (!api_global_admin_can_edit_admin($loginAsUserId)) {
7784
            return false;
7785
        }
7786
    }
7787
7788
    $userInfo = api_get_user_info($userId);
7789
    $isDrh = function () use ($loginAsUserId) {
7790
        if (api_is_drh()) {
7791
            if (api_drh_can_access_all_session_content()) {
7792
                $users = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus(
7793
                    'drh_all',
7794
                    api_get_user_id()
7795
                );
7796
                $userList = [];
7797
                if (is_array($users)) {
7798
                    foreach ($users as $user) {
7799
                        $userList[] = $user['user_id'];
7800
                    }
7801
                }
7802
                if (in_array($loginAsUserId, $userList)) {
7803
                    return true;
7804
                }
7805
            } else {
7806
                if (api_is_drh() &&
7807
                    UserManager::is_user_followed_by_drh($loginAsUserId, api_get_user_id())
7808
                ) {
7809
                    return true;
7810
                }
7811
            }
7812
        }
7813
        return false;
7814
    };
7815
7816
    return api_is_platform_admin() || (api_is_session_admin() && $userInfo['status'] == 5) || $isDrh();
7817
}
7818
7819
/**
7820
 * @return bool
7821
 */
7822
function api_is_allowed_in_course()
7823
{
7824
    if (api_is_platform_admin()) {
7825
        return true;
7826
    }
7827
7828
    return Session::read('is_allowed_in_course');
7829
}
7830
7831
/**
7832
 * Set the cookie to go directly to the course code $in_firstpage
7833
 * after login
7834
 * @param string $in_firstpage is the course code of the course to go
7835
 */
7836
function api_set_firstpage_parameter($in_firstpage)
7837
{
7838
    setcookie('GotoCourse', $in_firstpage);
7839
}
7840
7841
/**
7842
 * Delete the cookie to go directly to the course code $in_firstpage
7843
 * after login
7844
 */
7845
function api_delete_firstpage_parameter()
7846
{
7847
    setcookie('GotoCourse', '', time() - 3600);
7848
}
7849
7850
/**
7851
 * @return boolean if course_code for direct course access after login is set
7852
 */
7853
function exist_firstpage_parameter()
7854
{
7855
    return isset($_COOKIE['GotoCourse']) && $_COOKIE['GotoCourse'] != '';
7856
}
7857
7858
/**
7859
 * @return return the course_code of the course where user login
7860
 */
7861
function api_get_firstpage_parameter()
7862
{
7863
    return $_COOKIE['GotoCourse'];
7864
}
7865
7866
/**
7867
 * Return true on https install
7868
 * @return boolean
7869
 */
7870
function api_is_https()
7871
{
7872
    if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) &&
7873
        $_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...
7874
    ) {
7875
        $isSecured = true;
7876
    } else {
7877
        if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') {
7878
            $isSecured = true;
7879
        } else {
7880
            $isSecured = false;
7881
            // last chance
7882
            if (!empty($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443) {
7883
                $isSecured = true;
7884
            }
7885
        }
7886
    }
7887
7888
    return $isSecured;
7889
}
7890
7891
/**
7892
 * Return protocol (http or https)
7893
 * @return string
7894
 */
7895
function api_get_protocol()
7896
{
7897
    return api_is_https() ? 'https' : 'http';
7898
}
7899
7900
/**
7901
 * Return a string where " are replaced with 2 '
7902
 * It is useful when you pass a PHP variable in a Javascript browser dialog
7903
 * e.g. : alert("<?php get_lang('Message') ?>");
7904
 * and message contains character "
7905
 *
7906
 * @param string $in_text
7907
 * @return string
7908
 */
7909
function convert_double_quote_to_single($in_text)
7910
{
7911
    return api_preg_replace('/"/', "''", $in_text);
7912
}
7913
7914
/**
7915
 * Get origin
7916
 *
7917
 * @param string
7918
 * @return string
7919
 **/
7920
function api_get_origin()
7921
{
7922
    $origin = isset($_REQUEST['origin']) ? Security::remove_XSS($_REQUEST['origin']) : '';
7923
7924
    return $origin;
7925
}
7926
7927
/**
7928
 * Warns an user that the portal reach certain limit.
7929
 * @param string $limitName
7930
 */
7931
function api_warn_hosting_contact($limitName)
7932
{
7933
    $hostingParams = api_get_configuration_value(1);
7934
    $email = null;
7935
7936
    if (!empty($hostingParams)) {
7937
        if (isset($hostingParams['hosting_contact_mail'])) {
7938
            $email = $hostingParams['hosting_contact_mail'];
7939
        }
7940
    }
7941
7942
    if (!empty($email)) {
7943
        $subject = get_lang('HostingWarningReached');
7944
        $body = get_lang('PortalName').': '.api_get_path(WEB_PATH)." \n ";
7945
        $body .= get_lang('PortalLimitType').': '.$limitName." \n ";
7946
        if (isset($hostingParams[$limitName])) {
7947
            $body .= get_lang('Value').': '.$hostingParams[$limitName];
7948
        }
7949
        api_mail_html(null, $email, $subject, $body);
7950
    }
7951
}
7952
7953
/**
7954
 * Gets value of a variable from app/config/configuration.php
7955
 * Variables that are not set in the configuration.php file but set elsewhere:
7956
 * - virtual_css_theme_folder (vchamilo plugin)
7957
 * - access_url (global.inc.php)
7958
 * - apc/apc_prefix (global.inc.php)
7959
 *
7960
 * @param string $variable
7961
 *
7962
 * @return bool|mixed
7963
 */
7964
function api_get_configuration_value($variable)
7965
{
7966
    global $_configuration;
7967
    // Check the current url id, id = 1 by default
7968
    $urlId = isset($_configuration['access_url']) ? (int) $_configuration['access_url'] : 1;
7969
7970
    $variable = trim($variable);
7971
7972
    // Check if variable exists
7973
    if (isset($_configuration[$variable])) {
7974
        if (is_array($_configuration[$variable])) {
7975
            // Check if it exists for the sub portal
7976
            if (array_key_exists($urlId, $_configuration[$variable])) {
7977
                return $_configuration[$variable][$urlId];
7978
            } else {
7979
                // Try to found element with id = 1 (master portal)
7980
                if (array_key_exists(1, $_configuration[$variable])) {
7981
                    return $_configuration[$variable][1];
7982
                }
7983
            }
7984
        }
7985
7986
        return $_configuration[$variable];
7987
    }
7988
7989
    return false;
7990
}
7991
7992
/**
7993
 * Returns supported image extensions in the portal
7994
 * @param   bool    $supportVectors Whether vector images should also be accepted or not
7995
 * @return  array   Supported image extensions in the portal
7996
 */
7997
function api_get_supported_image_extensions($supportVectors = true)
7998
{
7999
    // jpg can also be called jpeg, jpe, jfif and jif. See https://en.wikipedia.org/wiki/JPEG#JPEG_filename_extensions
8000
    $supportedImageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'jpe', 'jfif', 'jif'];
8001
    if ($supportVectors) {
8002
        array_push($supportedImageExtensions, 'svg');
8003
    }
8004
    if (version_compare(PHP_VERSION, '5.5.0', '>=')) {
8005
        array_push($supportedImageExtensions, 'webp');
8006
    }
8007
    return $supportedImageExtensions;
8008
}
8009
8010
/**
8011
 * This setting changes the registration status for the campus
8012
 *
8013
 * @author Patrick Cool <[email protected]>, Ghent University
8014
 * @version August 2006
8015
 * @param   bool    $listCampus Whether we authorize
8016
 * @todo the $_settings should be reloaded here. => write api function for this and use this in global.inc.php also.
8017
 */
8018
function api_register_campus($listCampus = true)
8019
{
8020
    $tbl_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
8021
8022
    $sql = "UPDATE $tbl_settings SET selected_value='true' WHERE variable='registered'";
8023
    Database::query($sql);
8024
8025
    if (!$listCampus) {
8026
        $sql = "UPDATE $tbl_settings SET selected_value='true' WHERE variable='donotlistcampus'";
8027
        Database::query($sql);
8028
    }
8029
}
8030
8031
/**
8032
 * Checks whether current user is a student boss
8033
 * @global array $_user
8034
 * @return boolean
8035
 */
8036
function api_is_student_boss()
8037
{
8038
    $_user = api_get_user_info();
8039
8040
    return isset($_user['status']) && $_user['status'] == STUDENT_BOSS;
8041
}
8042
8043
/**
8044
 * Check whether the user type should be exclude.
8045
 * Such as invited or anonymous users
8046
 * @param boolean $checkDB Optional. Whether check the user status
8047
 * @param int $userId Options. The user id
8048
 *
8049
 * @return boolean
8050
 */
8051
function api_is_excluded_user_type($checkDB = false, $userId = 0)
8052
{
8053
    if ($checkDB) {
8054
        $userId = empty($userId) ? api_get_user_id() : intval($userId);
8055
8056
        if ($userId == 0) {
8057
            return true;
8058
        }
8059
8060
        $userInfo = api_get_user_info($userId);
8061
8062
        switch ($userInfo['status']) {
8063
            case INVITEE:
8064
            case ANONYMOUS:
8065
                return true;
8066
            default:
8067
                return false;
8068
        }
8069
    }
8070
8071
    $isInvited = api_is_invitee();
8072
    $isAnonymous = api_is_anonymous();
8073
8074
    if ($isInvited || $isAnonymous) {
8075
        return true;
8076
    }
8077
8078
    return false;
8079
}
8080
8081
/**
8082
 * Get the user status to ignore in reports
8083
 * @param string $format Optional. The result type (array or string)
8084
 * @return array|string
8085
 */
8086
function api_get_users_status_ignored_in_reports($format = 'array')
8087
{
8088
    $excludedTypes = [
8089
        INVITEE,
8090
        ANONYMOUS
8091
    ];
8092
8093
    if ($format == 'string') {
8094
        return implode(', ', $excludedTypes);
8095
    }
8096
8097
    return $excludedTypes;
8098
}
8099
8100
/**
8101
 * Set the Site Use Cookie Warning for 1 year
8102
 */
8103
function api_set_site_use_cookie_warning_cookie()
8104
{
8105
    setcookie('ChamiloUsesCookies', 'ok', time() + 31556926);
8106
}
8107
8108
/**
8109
 * Return true if the Site Use Cookie Warning Cookie warning exists
8110
 * @return bool
8111
 */
8112
function api_site_use_cookie_warning_cookie_exist()
8113
{
8114
    return isset($_COOKIE['ChamiloUsesCookies']);
8115
}
8116
8117
/**
8118
 * Given a number of seconds, format the time to show hours, minutes and seconds
8119
 * @param int $time The time in seconds
8120
 * @param string $originFormat Optional. PHP o JS
8121
 * @return string (00h00'00")
8122
 */
8123
function api_format_time($time, $originFormat = 'php')
8124
{
8125
    $h = get_lang('h');
8126
    $hours = $time / 3600;
8127
    $mins = ($time % 3600) / 60;
8128
    $secs = ($time % 60);
8129
8130
    if ($time < 0) {
8131
        $hours = 0;
8132
        $mins = 0;
8133
        $secs = 0;
8134
    }
8135
8136
    if ($originFormat == 'js') {
8137
        $formattedTime = trim(sprintf("%02d : %02d : %02d", $hours, $mins, $secs));
8138
    } else {
8139
        $formattedTime = trim(sprintf("%02d$h%02d'%02d\"", $hours, $mins, $secs));
8140
    }
8141
8142
    return $formattedTime;
8143
}
8144
8145
/**
8146
 * Create a new empty directory with index.html file
8147
 * @param string $name The new directory name
8148
 * @param string $parentDirectory Directory parent directory name
8149
 * @return boolean Return true if the directory was create. Otherwise return false
8150
 */
8151
function api_create_protected_dir($name, $parentDirectory)
8152
{
8153
    $isCreated = false;
8154
8155
    if (!is_writable($parentDirectory)) {
8156
        return false;
8157
    }
8158
8159
    $fullPath = $parentDirectory.api_replace_dangerous_char($name);
8160
8161
    if (mkdir($fullPath, api_get_permissions_for_new_directories(), true)) {
8162
        $fp = fopen($fullPath.'/index.html', 'w');
8163
8164
        if ($fp) {
8165
            if (fwrite($fp, '<html><head></head><body></body></html>')) {
8166
                $isCreated = true;
8167
            }
8168
        }
8169
8170
        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

8170
        fclose(/** @scrutinizer ignore-type */ $fp);
Loading history...
8171
    }
8172
8173
    return $isCreated;
8174
}
8175
8176
/**
8177
 * Sends an HTML email using the phpmailer class (and multipart/alternative to downgrade gracefully)
8178
 * Sender name and email can be specified, if not specified
8179
 * name and email of the platform admin are used
8180
 *
8181
 * @author Bert Vanderkimpen ICT&O UGent
8182
 * @author Yannick Warnier <[email protected]>
8183
 *
8184
 * @param string    name of recipient
8185
 * @param string    email of recipient
8186
 * @param string    email subject
8187
 * @param string    email body
8188
 * @param string    sender name
8189
 * @param string    sender e-mail
8190
 * @param array     extra headers in form $headers = array($name => $value) to allow parsing
8191
 * @param array     data file (path and filename)
8192
 * @param bool      True for attaching a embedded file inside content html (optional)
8193
 * @param array     Additional parameters
8194
 * @return          integer true if mail was sent
8195
 * @see             class.phpmailer.php
8196
 */
8197
function api_mail_html(
8198
    $recipient_name,
0 ignored issues
show
Unused Code introduced by
The parameter $recipient_name 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

8198
    /** @scrutinizer ignore-unused */ $recipient_name,

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...
8199
    $recipient_email,
0 ignored issues
show
Unused Code introduced by
The parameter $recipient_email 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

8199
    /** @scrutinizer ignore-unused */ $recipient_email,

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...
8200
    $subject,
0 ignored issues
show
Unused Code introduced by
The parameter $subject 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

8200
    /** @scrutinizer ignore-unused */ $subject,

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...
8201
    $message,
0 ignored issues
show
Unused Code introduced by
The parameter $message is not used and could be removed. ( Ignorable by Annotation )

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

8201
    /** @scrutinizer ignore-unused */ $message,

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...
8202
    $senderName = '',
0 ignored issues
show
Unused Code introduced by
The parameter $senderName 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

8202
    /** @scrutinizer ignore-unused */ $senderName = '',

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...
8203
    $senderEmail = '',
0 ignored issues
show
Unused Code introduced by
The parameter $senderEmail 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

8203
    /** @scrutinizer ignore-unused */ $senderEmail = '',

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...
8204
    $extra_headers = [],
0 ignored issues
show
Unused Code introduced by
The parameter $extra_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

8204
    /** @scrutinizer ignore-unused */ $extra_headers = [],

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...
8205
    $data_file = [],
0 ignored issues
show
Unused Code introduced by
The parameter $data_file 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

8205
    /** @scrutinizer ignore-unused */ $data_file = [],

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...
8206
    $embedded_image = false,
0 ignored issues
show
Unused Code introduced by
The parameter $embedded_image 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

8206
    /** @scrutinizer ignore-unused */ $embedded_image = 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...
8207
    $additionalParameters = []
0 ignored issues
show
Unused Code introduced by
The parameter $additionalParameters 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

8207
    /** @scrutinizer ignore-unused */ $additionalParameters = []

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...
8208
) {
8209
    global $platform_email;
8210
    return;
8211
8212
    $mail = new PHPMailer();
0 ignored issues
show
Unused Code introduced by
$mail = new PHPMailer() 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...
8213
    $mail->Mailer = $platform_email['SMTP_MAILER'];
8214
    $mail->Host = $platform_email['SMTP_HOST'];
8215
    $mail->Port = $platform_email['SMTP_PORT'];
8216
    $mail->CharSet = $platform_email['SMTP_CHARSET'];
8217
    // Stay far below SMTP protocol 980 chars limit.
8218
    $mail->WordWrap = 200;
8219
8220
    if ($platform_email['SMTP_AUTH']) {
8221
        $mail->SMTPAuth = 1;
8222
        $mail->Username = $platform_email['SMTP_USER'];
8223
        $mail->Password = $platform_email['SMTP_PASS'];
8224
        if (isset($platform_email['SMTP_SECURE'])) {
8225
            $mail->SMTPSecure = $platform_email['SMTP_SECURE'];
8226
        }
8227
    }
8228
    $mail->SMTPDebug = isset($platform_email['SMTP_DEBUG']) ? $platform_email['SMTP_DEBUG'] : 0;
8229
8230
    // 5 = low, 1 = high
8231
    $mail->Priority = 3;
8232
    $mail->SMTPKeepAlive = true;
8233
8234
    // Default values
8235
    $notification = new Notification();
8236
    $defaultEmail = $notification->getDefaultPlatformSenderEmail();
8237
    $defaultName = $notification->getDefaultPlatformSenderName();
8238
8239
    // If the parameter is set don't use the admin.
8240
    $senderName = !empty($senderName) ? $senderName : $defaultName;
8241
    $senderEmail = !empty($senderEmail) ? $senderEmail : $defaultEmail;
8242
8243
    // Reply to first
8244
    if (isset($extra_headers['reply_to']) && empty($platform_email['SMTP_UNIQUE_REPLY_TO'])) {
8245
        $mail->AddReplyTo(
8246
            $extra_headers['reply_to']['mail'],
8247
            $extra_headers['reply_to']['name']
8248
        );
8249
        // Errors to sender
8250
        $mail->AddCustomHeader('Errors-To: '.$extra_headers['reply_to']['mail']);
8251
        $mail->Sender = $extra_headers['reply_to']['mail'];
8252
        unset($extra_headers['reply_to']);
8253
    } else {
8254
        $mail->AddCustomHeader('Errors-To: '.$defaultEmail);
8255
    }
8256
8257
    //If the SMTP configuration only accept one sender
8258
    if (isset($platform_email['SMTP_UNIQUE_SENDER']) && $platform_email['SMTP_UNIQUE_SENDER']) {
8259
        $senderName = $platform_email['SMTP_FROM_NAME'];
8260
        $senderEmail = $platform_email['SMTP_FROM_EMAIL'];
8261
        $valid = PHPMailer::validateAddress($senderEmail);
8262
        if ($valid) {
8263
            //force-set Sender to $senderEmail, otherwise SetFrom only does it if it is currently empty
8264
            $mail->Sender = $senderEmail;
8265
        }
8266
    }
8267
8268
    $mail->SetFrom($senderEmail, $senderName);
8269
    $mail->Subject = $subject;
8270
    $mail->AltBody = strip_tags(
8271
        str_replace('<br />', "\n", api_html_entity_decode($message))
8272
    );
8273
8274
    $list = api_get_configuration_value('send_all_emails_to');
8275
    if (!empty($list) && isset($list['emails'])) {
8276
        foreach ($list['emails'] as $email) {
8277
            //$mail->AddBCC($email);
8278
            $mail->AddAddress($email);
8279
        }
8280
    }
8281
8282
    // Send embedded image.
8283
    if ($embedded_image) {
8284
        // Get all images html inside content.
8285
        preg_match_all("/<img\s+.*?src=[\"\']?([^\"\' >]*)[\"\']?[^>]*>/i", $message, $m);
8286
        // Prepare new tag images.
8287
        $new_images_html = [];
8288
        $i = 1;
8289
        if (!empty($m[1])) {
8290
            foreach ($m[1] as $image_path) {
8291
                $real_path = realpath($image_path);
8292
                $filename  = basename($image_path);
8293
                $image_cid = $filename.'_'.$i;
8294
                $encoding = 'base64';
8295
                $image_type = mime_content_type($real_path);
8296
                $mail->AddEmbeddedImage(
8297
                    $real_path,
8298
                    $image_cid,
8299
                    $filename,
8300
                    $encoding,
8301
                    $image_type
8302
                );
8303
                $new_images_html[] = '<img src="cid:'.$image_cid.'" />';
8304
                $i++;
8305
            }
8306
        }
8307
8308
        // Replace origin image for new embedded image html.
8309
        $x = 0;
8310
        if (!empty($m[0])) {
8311
            foreach ($m[0] as $orig_img) {
8312
                $message = str_replace($orig_img, $new_images_html[$x], $message);
8313
                $x++;
8314
            }
8315
        }
8316
    }
8317
8318
    $mailView = new Template(null, false, false, false, false, false, false);
8319
8320
    $noReply = api_get_setting('noreply_email_address');
8321
    if (!empty($noReply)) {
8322
        $message .= "<br />".get_lang('ThisIsAutomaticEmailNoReply');
8323
    }
8324
    $mailView->assign('content', $message);
8325
8326
    if (isset($additionalParameters['link'])) {
8327
        $mailView->assign('link', $additionalParameters['link']);
8328
    }
8329
    $mailView->assign('mail_header_style', api_get_configuration_value('mail_header_style'));
8330
    $mailView->assign('mail_content_style', api_get_configuration_value('mail_content_style'));
8331
    $layout = $mailView->get_template('mail/mail.tpl');
8332
    $mail->Body = $mailView->fetch($layout);
8333
8334
    // Attachment ...
8335
    if (!empty($data_file)) {
8336
        $o = 0;
8337
        foreach ($data_file as $file_attach) {
8338
            if (!empty($file_attach['path']) && !empty($file_attach['filename'])) {
8339
                $mail->AddAttachment($file_attach['path'], $file_attach['filename']);
8340
            }
8341
            $o++;
8342
        }
8343
    }
8344
8345
    // Only valid addresses are accepted.
8346
    if (is_array($recipient_email)) {
8347
        foreach ($recipient_email as $dest) {
8348
            if (api_valid_email($dest)) {
8349
                $mail->AddAddress($dest, $recipient_name);
8350
            }
8351
        }
8352
    } else {
8353
        if (api_valid_email($recipient_email)) {
8354
            $mail->AddAddress($recipient_email, $recipient_name);
8355
        } else {
8356
            return 0;
8357
        }
8358
    }
8359
8360
    if (is_array($extra_headers) && count($extra_headers) > 0) {
8361
        foreach ($extra_headers as $key => $value) {
8362
            switch (strtolower($key)) {
8363
                case 'encoding':
8364
                case 'content-transfer-encoding':
8365
                    $mail->Encoding = $value;
8366
                    break;
8367
                case 'charset':
8368
                    $mail->Charset = $value;
8369
                    break;
8370
                case 'contenttype':
8371
                case 'content-type':
8372
                    $mail->ContentType = $value;
8373
                    break;
8374
                default:
8375
                    $mail->AddCustomHeader($key.':'.$value);
8376
                    break;
8377
            }
8378
        }
8379
    } else {
8380
        if (!empty($extra_headers)) {
8381
            $mail->AddCustomHeader($extra_headers);
8382
        }
8383
    }
8384
8385
    // WordWrap the html body (phpMailer only fixes AltBody) FS#2988
8386
    $mail->Body = $mail->WrapText($mail->Body, $mail->WordWrap);
8387
8388
    // Send the mail message.
8389
    if (!$mail->Send()) {
8390
        error_log('ERROR: mail not sent to '.$recipient_name.' ('.$recipient_email.') because of '.$mail->ErrorInfo.'<br />');
8391
        if ($mail->SMTPDebug) {
8392
            error_log(
8393
                "Connection details :: ".
8394
                "Protocol: ".$mail->Mailer.' :: '.
8395
                "Host/Port: ".$mail->Host.':'.$mail->Port.' :: '.
8396
                "Authent/Open: ".($mail->SMTPAuth ? 'Authent' : 'Open').' :: '.
8397
                ($mail->SMTPAuth ? "  User/Pass: ".$mail->Username.':'.$mail->Password : '').' :: '.
8398
                "Sender: ".$mail->Sender
8399
            );
8400
        }
8401
        return 0;
8402
    }
8403
8404
    if (!empty($additionalParameters)) {
8405
        $plugin = new AppPlugin();
8406
        $smsPlugin = $plugin->getSMSPluginLibrary();
8407
        if ($smsPlugin) {
8408
            $smsPlugin->send($additionalParameters);
8409
        }
8410
    }
8411
8412
    // Clear all the addresses.
8413
    $mail->ClearAddresses();
8414
8415
    // Clear all attachments
8416
    $mail->ClearAttachments();
8417
8418
    return 1;
8419
}
8420
8421
/**
8422
 * @param string $tool Possible values: GroupManager::GROUP_TOOL_*
8423
 * @param bool $showHeader
8424
 */
8425
function api_protect_course_group($tool, $showHeader = true)
8426
{
8427
    $userId = api_get_user_id();
8428
    $groupId = api_get_group_id();
8429
    $groupInfo = GroupManager::get_group_properties($groupId);
8430
8431
    if (!empty($groupInfo)) {
8432
        $allow = GroupManager::user_has_access(
8433
            $userId,
8434
            $groupInfo['iid'],
8435
            $tool
8436
        );
8437
8438
        if (!$allow) {
8439
            api_not_allowed($showHeader);
8440
        }
8441
    }
8442
}
8443
8444
/**
8445
 * Check if a date is in a date range
8446
 *
8447
 * @param datetime $startDate
8448
 * @param datetime $endDate
8449
 * @param datetime $currentDate
8450
 * @return bool true if date is in rage, false otherwise
8451
 */
8452
function api_is_date_in_date_range($startDate, $endDate, $currentDate = null)
8453
{
8454
    $startDate = strtotime(api_get_local_time($startDate));
8455
    $endDate = strtotime(api_get_local_time($endDate));
8456
    $currentDate = strtotime(api_get_local_time($currentDate));
8457
8458
    if ($currentDate >= $startDate && $currentDate <= $endDate) {
8459
        return true;
8460
    }
8461
8462
    return false;
8463
}
8464
8465
/**
8466
 * Eliminate the duplicates of a multidimensional array by sending the key
8467
 *
8468
 * @param array $array multidimensional array
8469
 * @param int $key key to find to compare
8470
 * @return array
8471
 *
8472
 */
8473
function api_unique_multidim_array($array, $key)
8474
{
8475
    $temp_array = [];
8476
    $i = 0;
8477
    $key_array = [];
8478
8479
    foreach ($array as $val) {
8480
        if (!in_array($val[$key], $key_array)) {
8481
            $key_array[$i] = $val[$key];
8482
            $temp_array[$i] = $val;
8483
        }
8484
        $i++;
8485
    }
8486
    return $temp_array;
8487
}
8488
8489
/**
8490
 * Limit the access to Session Admins wheen the limit_session_admin_role
8491
 * configuration variable is set to true
8492
 */
8493
function api_protect_limit_for_session_admin()
8494
{
8495
    $limitAdmin = api_get_setting('limit_session_admin_role');
8496
    if (api_is_session_admin() && $limitAdmin === 'true') {
8497
        api_not_allowed(true);
8498
    }
8499
}
8500
8501
/**
8502
 * @return bool
8503
 */
8504
function api_is_student_view_active()
8505
{
8506
    $studentView = Session::read('studentview');
8507
    return $studentView == 'studentview';
8508
}
8509
8510
/**
8511
 * Adds a file inside the upload/$type/id
8512
 *
8513
 * @param string $type
8514
 * @param array $file
8515
 * @param int $itemId
8516
 * @param string $cropParameters
8517
 * @return array|bool
8518
 */
8519
function api_upload_file($type, $file, $itemId, $cropParameters = '')
8520
{
8521
    $upload = process_uploaded_file($file);
8522
    if ($upload) {
8523
        $name = api_replace_dangerous_char($file['name']);
8524
8525
        // No "dangerous" files
8526
        $name = disable_dangerous_file($name);
8527
8528
        $pathId = '/'.substr((string) $itemId, 0, 1).'/'.$itemId.'/';
8529
        $path = api_get_path(SYS_UPLOAD_PATH).$type.$pathId;
8530
8531
        if (!is_dir($path)) {
8532
            mkdir($path, api_get_permissions_for_new_directories(), true);
8533
        }
8534
8535
        $pathToSave = $path.$name;
8536
8537
        $result = move_uploaded_file($file['tmp_name'], $pathToSave);
8538
        if ($result) {
8539
            if (!empty($cropParameters)) {
8540
                $image = new Image($pathToSave);
8541
                $image->crop($cropParameters);
8542
            }
8543
8544
            return ['path_to_save' => $pathId.$name];
8545
        }
8546
        return false;
8547
    }
8548
}
8549
8550
/**
8551
 * @param string $type
8552
 * @param int $itemId
8553
 * @param string $file
8554
 *
8555
 * @return bool
8556
 */
8557
function api_get_uploaded_file($type, $itemId, $file)
8558
{
8559
    $itemId = (int) $itemId;
8560
    $pathId = '/'.substr((string) $itemId, 0, 1).'/'.$itemId.'/';
8561
    $path = api_get_path(SYS_UPLOAD_PATH).$type.$pathId;
8562
8563
    $file = basename($file);
8564
8565
    $file = $path.'/'.$file;
8566
    if (file_exists($file)) {
8567
        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...
8568
    }
8569
    return false;
8570
}
8571
8572
/**
8573
 * @param string $type
8574
 * @param int $itemId
8575
 * @param string $file
8576
 * @param string $title
8577
 */
8578
function api_download_uploaded_file($type, $itemId, $file, $title = '')
8579
{
8580
    $file = api_get_uploaded_file($type, $itemId, $file);
8581
    if ($file) {
8582
        if (Security::check_abs_path($file, api_get_path(SYS_UPLOAD_PATH).$type)) {
8583
            DocumentManager::file_send_for_download($file, true, $title);
8584
            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...
8585
        }
8586
    }
8587
    api_not_allowed(true);
8588
}
8589
8590
/**
8591
 * @param string $type
8592
 * @param string $file
8593
 */
8594
function api_remove_uploaded_file($type, $file)
8595
{
8596
    $path = api_get_path(SYS_UPLOAD_PATH).$type.'/'.$file;
8597
    if (file_exists($path)) {
8598
        unlink($path);
8599
    }
8600
}
8601
8602
/**
8603
 * Converts string value to float value
8604
 *
8605
 * 3.141516 => 3.141516
8606
 * 3,141516 => 3.141516
8607
 * @todo WIP
8608
 *
8609
 * @param string $number
8610
 * @return float
8611
 */
8612
function api_float_val($number)
8613
{
8614
    $number = (float) str_replace(',', '.', trim($number));
8615
    return $number;
8616
}
8617
8618
/**
8619
 * Converts float values
8620
 * Example if $decimals = 2
8621
 *
8622
 * 3.141516 => 3.14
8623
 * 3,141516 => 3,14
8624
 *
8625
 * @todo WIP
8626
 *
8627
 * @param string $number number in iso code
8628
 * @param int $decimals
8629
 * @return bool|string
8630
 */
8631
function api_number_format($number, $decimals = 0)
8632
{
8633
    $number = api_float_val($number);
8634
8635
    return number_format($number, $decimals);
8636
}
8637
8638
/**
8639
 * Set location url with a exit break by default
8640
 *
8641
 * @param $url
8642
 * @param bool $exit
8643
 * @return void
8644
 */
8645
function location($url, $exit = true)
8646
{
8647
    header('Location: '.$url);
8648
8649
    if ($exit) {
8650
        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...
8651
    }
8652
}
8653
8654
/**
8655
 * @return string
8656
 */
8657
function api_get_web_url()
8658
{
8659
    if (api_get_setting('server_type') == 'test') {
8660
        return api_get_path(WEB_PATH).'web/app_dev.php/';
8661
    } else {
8662
        return api_get_path(WEB_PATH).'web/';
8663
    }
8664
}
8665