Completed
Push — master ( 76a038...0c6f8d )
by Julito
10:18
created

api_item_property_update()   F

Complexity

Conditions 36
Paths > 20000

Size

Total Lines 297
Code Lines 203

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 36
eloc 203
c 1
b 0
f 0
nc 419330
nop 10
dl 0
loc 297
rs 0

5 Methods

Rating   Name   Duplication   Size   Complexity  
A api_get_item_property_info() 0 40 5
A api_get_track_item_property_history() 0 17 3
A api_get_languages_combo() 0 31 5
A api_track_item_property_update() 0 23 2
B api_display_language_form() 0 50 8

How to fix   Long Method    Complexity    Many Parameters   

Long Method

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

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

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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

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

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

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

// Bar.php
namespace OtherDir;

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

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

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

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

// Bar.php
namespace OtherDir;

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

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

Loading history...
1059
            isset($course_info['registration_code']) &&
1060
            !empty($course_info['registration_code'])
1061
        ) {
1062
            $is_visible = false;
1063
        }
1064
    }
1065
1066
    if (!empty($checkTool)) {
1067
        if (!api_is_allowed_to_edit(true, true, true)) {
1068
            $toolInfo = api_get_tool_information_by_name($checkTool);
1069
            if (!empty($toolInfo) && isset($toolInfo['visibility']) && 0 == $toolInfo['visibility']) {
1070
                api_not_allowed(true);
1071
1072
                return false;
1073
            }
1074
        }
1075
    }
1076
1077
    // Check session visibility
1078
    $session_id = api_get_session_id();
1079
1080
    if (!empty($session_id)) {
1081
        // $isAllowedInCourse was set in local.inc.php
1082
        if (!$isAllowedInCourse) {
1083
            $is_visible = false;
1084
        }
1085
    }
1086
1087
    if (!$is_visible) {
1088
        api_not_allowed($print_headers);
1089
1090
        return false;
1091
    }
1092
1093
    return true;
1094
}
1095
1096
/**
1097
 * Function used to protect an admin script.
1098
 *
1099
 * The function blocks access when the user has no platform admin rights
1100
 * with an error message printed on default output
1101
 *
1102
 * @param bool Whether to allow session admins as well
1103
 * @param bool Whether to allow HR directors as well
1104
 * @param string An optional message (already passed through get_lang)
1105
 *
1106
 * @return bool True if user is allowed, false otherwise.
1107
 *              The function also outputs an error message in case not allowed
1108
 *
1109
 * @author Roan Embrechts (original author)
1110
 */
1111
function api_protect_admin_script($allow_sessions_admins = false, $allow_drh = false, $message = null)
1112
{
1113
    if (!api_is_platform_admin($allow_sessions_admins, $allow_drh)) {
1114
        api_not_allowed(true, $message);
1115
1116
        return false;
1117
    }
1118
1119
    return true;
1120
}
1121
1122
/**
1123
 * Function used to protect a teacher script.
1124
 * The function blocks access when the user has no teacher rights.
1125
 *
1126
 * @return bool True if the current user can access the script, false otherwise
1127
 *
1128
 * @author Yoselyn Castillo
1129
 */
1130
function api_protect_teacher_script()
1131
{
1132
    if (!api_is_allowed_to_edit()) {
1133
        api_not_allowed(true);
1134
1135
        return false;
1136
    }
1137
1138
    return true;
1139
}
1140
1141
/**
1142
 * Function used to prevent anonymous users from accessing a script.
1143
 *
1144
 * @param bool|true $printHeaders
1145
 *
1146
 * @author Roan Embrechts
1147
 *
1148
 * @return bool
1149
 */
1150
function api_block_anonymous_users($printHeaders = true)
1151
{
1152
    $user = api_get_user_info();
1153
    if (!(isset($user['user_id']) && $user['user_id']) || api_is_anonymous($user['user_id'], true)) {
1154
        api_not_allowed($printHeaders);
1155
1156
        return false;
1157
    }
1158
1159
    return true;
1160
}
1161
1162
/**
1163
 * Returns a rough evaluation of the browser's name and version based on very
1164
 * simple regexp.
1165
 *
1166
 * @return array with the navigator name and version ['name' => '...', 'version' => '...']
1167
 */
1168
function api_get_navigator()
1169
{
1170
    $navigator = 'Unknown';
1171
    $version = 0;
1172
1173
    if (!isset($_SERVER['HTTP_USER_AGENT'])) {
1174
        return ['name' => 'Unknown', 'version' => '0.0.0'];
1175
    }
1176
1177
    if (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Opera')) {
1178
        $navigator = 'Opera';
1179
        list(, $version) = explode('Opera', $_SERVER['HTTP_USER_AGENT']);
1180
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Edge')) {
1181
        $navigator = 'Edge';
1182
        list(, $version) = explode('Edge', $_SERVER['HTTP_USER_AGENT']);
1183
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE')) {
1184
        $navigator = 'Internet Explorer';
1185
        list(, $version) = explode('MSIE ', $_SERVER['HTTP_USER_AGENT']);
1186
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Chrome')) {
1187
        $navigator = 'Chrome';
1188
        list(, $version) = explode('Chrome', $_SERVER['HTTP_USER_AGENT']);
1189
    } elseif (false !== stripos($_SERVER['HTTP_USER_AGENT'], 'Safari')) {
1190
        $navigator = 'Safari';
1191
        if (false !== stripos($_SERVER['HTTP_USER_AGENT'], 'Version/')) {
1192
            // If this Safari does have the "Version/" string in its user agent
1193
            // then use that as a version indicator rather than what's after
1194
            // "Safari/" which is rather a "build number" or something
1195
            list(, $version) = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1196
        } else {
1197
            list(, $version) = explode('Safari/', $_SERVER['HTTP_USER_AGENT']);
1198
        }
1199
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Firefox')) {
1200
        $navigator = 'Firefox';
1201
        list(, $version) = explode('Firefox', $_SERVER['HTTP_USER_AGENT']);
1202
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Netscape')) {
1203
        $navigator = 'Netscape';
1204
        if (false !== stripos($_SERVER['HTTP_USER_AGENT'], 'Netscape/')) {
1205
            list(, $version) = explode('Netscape', $_SERVER['HTTP_USER_AGENT']);
1206
        } else {
1207
            list(, $version) = explode('Navigator', $_SERVER['HTTP_USER_AGENT']);
1208
        }
1209
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Konqueror')) {
1210
        $navigator = 'Konqueror';
1211
        list(, $version) = explode('Konqueror', $_SERVER['HTTP_USER_AGENT']);
1212
    } elseif (false !== stripos($_SERVER['HTTP_USER_AGENT'], 'applewebkit')) {
1213
        $navigator = 'AppleWebKit';
1214
        list(, $version) = explode('Version/', $_SERVER['HTTP_USER_AGENT']);
1215
    } elseif (false !== strpos($_SERVER['HTTP_USER_AGENT'], 'Gecko')) {
1216
        $navigator = 'Mozilla';
1217
        list(, $version) = explode('; rv:', $_SERVER['HTTP_USER_AGENT']);
1218
    }
1219
1220
    // Now cut extra stuff around (mostly *after*) the version number
1221
    $version = preg_replace('/^([\/\s])?([\d\.]+)?.*/', '\2', $version);
1222
1223
    if (false === strpos($version, '.')) {
1224
        $version = number_format(doubleval($version), 1);
1225
    }
1226
1227
    return ['name' => $navigator, 'version' => $version];
1228
}
1229
1230
/**
1231
 * @return true if user self registration is allowed, false otherwise
1232
 */
1233
function api_is_self_registration_allowed()
1234
{
1235
    return isset($GLOBALS['allowSelfReg']) ? $GLOBALS['allowSelfReg'] : false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return IssetNode ? $GLOB...'allowSelfReg'] : false could also return false which is incompatible with the documented return type true. Did you maybe forget to handle an error condition?

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

Loading history...
1236
}
1237
1238
/**
1239
 * This function returns the id of the user which is stored in the $_user array.
1240
 *
1241
 * example: The function can be used to check if a user is logged in
1242
 *          if (api_get_user_id())
1243
 *
1244
 * @return int the id of the current user, 0 if is empty
1245
 */
1246
function api_get_user_id()
1247
{
1248
    $userInfo = Session::read('_user');
1249
    if ($userInfo && isset($userInfo['user_id'])) {
1250
        return (int) $userInfo['user_id'];
1251
    }
1252
1253
    return 0;
1254
}
1255
1256
/**
1257
 * Gets the list of courses a specific user is subscribed to.
1258
 *
1259
 * @param int       User ID
1260
 * @param bool $fetch_session Whether to get session courses or not - NOT YET IMPLEMENTED
1261
 *
1262
 * @return array Array of courses in the form [0]=>('code'=>xxx,'db'=>xxx,'dir'=>xxx,'status'=>d)
1263
 *
1264
 * @deprecated use CourseManager::get_courses_list_by_user_id()
1265
 */
1266
function api_get_user_courses($userId, $fetch_session = true)
1267
{
1268
    // Get out if not integer
1269
    if ($userId != strval(intval($userId))) {
1270
        return [];
1271
    }
1272
1273
    $t_course = Database::get_main_table(TABLE_MAIN_COURSE);
1274
    $t_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
1275
1276
    $sql = "SELECT cc.id as real_id, cc.code code, cc.directory dir, cu.status status
1277
            FROM $t_course cc, $t_course_user cu
1278
            WHERE
1279
                cc.id = cu.c_id AND
1280
                cu.user_id = $userId AND
1281
                cu.relation_type <> ".COURSE_RELATION_TYPE_RRHH;
1282
    $result = Database::query($sql);
1283
    if (false === $result) {
1284
        return [];
1285
    }
1286
1287
    $courses = [];
1288
    while ($row = Database::fetch_array($result)) {
1289
        // we only need the database name of the course
1290
        $courses[] = $row;
1291
    }
1292
1293
    return $courses;
1294
}
1295
1296
/**
1297
 * Formats user information into a standard array
1298
 * This function should be only used inside api_get_user_info().
1299
 *
1300
 * @param array Non-standard user array
0 ignored issues
show
Documentation Bug introduced by
The doc comment Non-standard at position 0 could not be parsed: Unknown type name 'Non-standard' at position 0 in Non-standard.
Loading history...
1301
 * @param bool $add_password
1302
 * @param bool $loadAvatars  turn off to improve performance
1303
 *
1304
 * @return array Standard user array
1305
 */
1306
function _api_format_user($user, $add_password = false, $loadAvatars = true)
1307
{
1308
    $result = [];
1309
1310
    if (!isset($user['id'])) {
1311
        return [];
1312
    }
1313
1314
    $result['firstname'] = null;
1315
    $result['lastname'] = null;
1316
1317
    if (isset($user['firstname']) && isset($user['lastname'])) {
1318
        // with only lowercase
1319
        $result['firstname'] = $user['firstname'];
1320
        $result['lastname'] = $user['lastname'];
1321
    } elseif (isset($user['firstName']) && isset($user['lastName'])) {
1322
        // with uppercase letters
1323
        $result['firstname'] = isset($user['firstName']) ? $user['firstName'] : null;
1324
        $result['lastname'] = isset($user['lastName']) ? $user['lastName'] : null;
1325
    }
1326
1327
    if (isset($user['email'])) {
1328
        $result['mail'] = isset($user['email']) ? $user['email'] : null;
1329
        $result['email'] = isset($user['email']) ? $user['email'] : null;
1330
    } else {
1331
        $result['mail'] = isset($user['mail']) ? $user['mail'] : null;
1332
        $result['email'] = isset($user['mail']) ? $user['mail'] : null;
1333
    }
1334
1335
    $result['complete_name'] = api_get_person_name($result['firstname'], $result['lastname']);
1336
    $result['complete_name_with_username'] = $result['complete_name'];
1337
1338
    if (!empty($user['username']) && 'false' === api_get_setting('profile.hide_username_with_complete_name')) {
1339
        $result['complete_name_with_username'] = $result['complete_name'].' ('.$user['username'].')';
1340
    }
1341
1342
    $showEmail = 'true' === api_get_setting('show_email_addresses');
1343
    if (!empty($user['email'])) {
1344
        $result['complete_name_with_email_forced'] = $result['complete_name'].' ('.$user['email'].')';
1345
        if ($showEmail) {
1346
            $result['complete_name_with_email'] = $result['complete_name'].' ('.$user['email'].')';
1347
        }
1348
    } else {
1349
        $result['complete_name_with_email'] = $result['complete_name'];
1350
        $result['complete_name_with_email_forced'] = $result['complete_name'];
1351
    }
1352
1353
    // Kept for historical reasons
1354
    $result['firstName'] = $result['firstname'];
1355
    $result['lastName'] = $result['lastname'];
1356
1357
    $attributes = [
1358
        'phone',
1359
        'address',
1360
        'picture_uri',
1361
        'official_code',
1362
        'status',
1363
        'active',
1364
        'auth_source',
1365
        'username',
1366
        'theme',
1367
        'language',
1368
        'creator_id',
1369
        'registration_date',
1370
        'hr_dept_id',
1371
        'expiration_date',
1372
        'last_login',
1373
        'user_is_online',
1374
    ];
1375
1376
    if ('true' === api_get_setting('extended_profile')) {
1377
        $attributes[] = 'competences';
1378
        $attributes[] = 'diplomas';
1379
        $attributes[] = 'teach';
1380
        $attributes[] = 'openarea';
1381
    }
1382
1383
    foreach ($attributes as $attribute) {
1384
        $result[$attribute] = isset($user[$attribute]) ? $user[$attribute] : null;
1385
    }
1386
1387
    $user_id = (int) $user['id'];
1388
    // Maintain the user_id index for backwards compatibility
1389
    $result['user_id'] = $result['id'] = $user_id;
1390
1391
    $hasCertificates = Certificate::getCertificateByUser($user_id);
1392
    $result['has_certificates'] = 0;
1393
    if (!empty($hasCertificates)) {
1394
        $result['has_certificates'] = 1;
1395
    }
1396
1397
    $result['icon_status'] = '';
1398
    $result['icon_status_medium'] = '';
1399
    $result['is_admin'] = UserManager::is_admin($user_id);
1400
1401
    // Getting user avatar.
1402
    if ($loadAvatars) {
1403
        $result['avatar'] = '';
1404
        $result['avatar_no_query'] = '';
1405
        $result['avatar_small'] = '';
1406
        $result['avatar_medium'] = '';
1407
1408
        /*if (!isset($user['avatar'])) {
1409
            $originalFile = UserManager::getUserPicture(
1410
                $user_id,
1411
                USER_IMAGE_SIZE_ORIGINAL,
1412
                null,
1413
                $result
1414
            );
1415
            $result['avatar'] = $originalFile;
1416
            $avatarString = explode('?', $result['avatar']);
1417
            $result['avatar_no_query'] = reset($avatarString);
1418
        } else {
1419
            $result['avatar'] = $user['avatar'];
1420
            $avatarString = explode('?', $user['avatar']);
1421
            $result['avatar_no_query'] = reset($avatarString);
1422
        }
1423
1424
        if (!isset($user['avatar_small'])) {
1425
            $smallFile = UserManager::getUserPicture(
1426
                $user_id,
1427
                USER_IMAGE_SIZE_SMALL,
1428
                null,
1429
                $result
1430
            );
1431
            $result['avatar_small'] = $smallFile;
1432
        } else {
1433
            $result['avatar_small'] = $user['avatar_small'];
1434
        }
1435
1436
        if (!isset($user['avatar_medium'])) {
1437
            $mediumFile = UserManager::getUserPicture(
1438
                $user_id,
1439
                USER_IMAGE_SIZE_MEDIUM,
1440
                null,
1441
                $result
1442
            );
1443
            $result['avatar_medium'] = $mediumFile;
1444
        } else {
1445
            $result['avatar_medium'] = $user['avatar_medium'];
1446
        }*/
1447
1448
        $urlImg = api_get_path(WEB_IMG_PATH);
1449
        $iconStatus = '';
1450
        $iconStatusMedium = '';
1451
        $label = '';
1452
        switch ($result['status']) {
1453
            case STUDENT:
1454
                if ($result['has_certificates']) {
1455
                    $iconStatus = $urlImg.'icons/svg/identifier_graduated.svg';
1456
                    $label = get_lang('Graduated');
1457
                } else {
1458
                    $iconStatus = $urlImg.'icons/svg/identifier_student.svg';
1459
                    $label = get_lang('Student');
1460
                }
1461
                break;
1462
            case COURSEMANAGER:
1463
                if ($result['is_admin']) {
1464
                    $iconStatus = $urlImg.'icons/svg/identifier_admin.svg';
1465
                    $label = get_lang('Admin');
1466
                } else {
1467
                    $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1468
                    $label = get_lang('Teacher');
1469
                }
1470
                break;
1471
            case STUDENT_BOSS:
1472
                $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1473
                $label = get_lang('StudentBoss');
1474
                break;
1475
        }
1476
1477
        if (!empty($iconStatus)) {
1478
            $iconStatusMedium = '<img src="'.$iconStatus.'" width="32px" height="32px">';
1479
            $iconStatus = '<img src="'.$iconStatus.'" width="22px" height="22px">';
1480
        }
1481
1482
        $result['icon_status'] = $iconStatus;
1483
        $result['icon_status_label'] = $label;
1484
        $result['icon_status_medium'] = $iconStatusMedium;
1485
    }
1486
1487
    if (isset($user['user_is_online'])) {
1488
        $result['user_is_online'] = true == $user['user_is_online'] ? 1 : 0;
1489
    }
1490
    if (isset($user['user_is_online_in_chat'])) {
1491
        $result['user_is_online_in_chat'] = (int) $user['user_is_online_in_chat'];
1492
    }
1493
1494
    if ($add_password) {
1495
        $result['password'] = $user['password'];
1496
    }
1497
1498
    if (isset($result['profile_completed'])) {
1499
        $result['profile_completed'] = $user['profile_completed'];
1500
    }
1501
1502
    $result['profile_url'] = api_get_path(WEB_CODE_PATH).'social/profile.php?u='.$user_id;
1503
1504
    // Send message link
1505
    $sendMessage = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&user_id='.$user_id;
1506
    $result['complete_name_with_message_link'] = Display::url(
1507
        $result['complete_name_with_username'],
1508
        $sendMessage,
1509
        ['class' => 'ajax']
1510
    );
1511
1512
    if (isset($user['extra'])) {
1513
        $result['extra'] = $user['extra'];
1514
    }
1515
1516
    return $result;
1517
}
1518
1519
/**
1520
 * Finds all the information about a user.
1521
 * If no parameter is passed you find all the information about the current user.
1522
 *
1523
 * @param int  $user_id
1524
 * @param bool $checkIfUserOnline
1525
 * @param bool $showPassword
1526
 * @param bool $loadExtraData
1527
 * @param bool $loadOnlyVisibleExtraData Get the user extra fields that are visible
1528
 * @param bool $loadAvatars              turn off to improve performance and if avatars are not needed
1529
 * @param bool $updateCache              update apc cache if exists
1530
 *
1531
 * @return mixed $user_info user_id, lastname, firstname, username, email, etc or false on error
1532
 *
1533
 * @author Patrick Cool <[email protected]>
1534
 * @author Julio Montoya
1535
 *
1536
 * @version 21 September 2004
1537
 */
1538
function api_get_user_info(
1539
    $user_id = 0,
1540
    $checkIfUserOnline = false,
1541
    $showPassword = false,
1542
    $loadExtraData = false,
1543
    $loadOnlyVisibleExtraData = false,
1544
    $loadAvatars = true,
1545
    $updateCache = false
1546
) {
1547
    // Make sure user_id is safe
1548
    $user_id = (int) $user_id;
1549
    $user = false;
1550
    if (empty($user_id)) {
1551
        $userFromSession = Session::read('_user');
1552
        if (isset($userFromSession) && !empty($userFromSession)) {
1553
            return $userFromSession;
1554
            /*
1555
            return _api_format_user(
1556
                $userFromSession,
1557
                $showPassword,
1558
                $loadAvatars
1559
            );*/
1560
        }
1561
1562
        return false;
1563
    }
1564
1565
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1566
            WHERE id = $user_id";
1567
    $result = Database::query($sql);
1568
    if (Database::num_rows($result) > 0) {
1569
        $result_array = Database::fetch_array($result);
1570
        $result_array['user_is_online_in_chat'] = 0;
1571
        if ($checkIfUserOnline) {
1572
            $use_status_in_platform = user_is_online($user_id);
1573
            $result_array['user_is_online'] = $use_status_in_platform;
1574
            $user_online_in_chat = 0;
1575
            if ($use_status_in_platform) {
1576
                $user_status = UserManager::get_extra_user_data_by_field(
1577
                    $user_id,
1578
                    'user_chat_status',
1579
                    false,
1580
                    true
1581
                );
1582
                if (1 == (int) $user_status['user_chat_status']) {
1583
                    $user_online_in_chat = 1;
1584
                }
1585
            }
1586
            $result_array['user_is_online_in_chat'] = $user_online_in_chat;
1587
        }
1588
1589
        if ($loadExtraData) {
1590
            $fieldValue = new ExtraFieldValue('user');
1591
            $result_array['extra'] = $fieldValue->getAllValuesForAnItem(
1592
                $user_id,
1593
                $loadOnlyVisibleExtraData
1594
            );
1595
        }
1596
        $user = _api_format_user($result_array, $showPassword, $loadAvatars);
1597
    }
1598
1599
    return $user;
1600
}
1601
1602
function api_get_user_info_from_entity(
1603
    User $user,
1604
    $checkIfUserOnline = false,
1605
    $showPassword = false,
1606
    $loadExtraData = false,
1607
    $loadOnlyVisibleExtraData = false,
1608
    $loadAvatars = true,
1609
    $loadCertificate = false
1610
) {
1611
    if (!$user instanceof UserInterface) {
1612
        return false;
1613
    }
1614
1615
    // Make sure user_id is safe
1616
    $user_id = (int) $user->getId();
1617
1618
    if (empty($user_id)) {
1619
        $userFromSession = Session::read('_user');
1620
1621
        if (isset($userFromSession) && !empty($userFromSession)) {
1622
            return $userFromSession;
1623
        }
1624
1625
        return false;
1626
    }
1627
1628
    $result = [];
1629
    $result['user_is_online_in_chat'] = 0;
1630
    if ($checkIfUserOnline) {
1631
        $use_status_in_platform = user_is_online($user_id);
1632
        $result['user_is_online'] = $use_status_in_platform;
1633
        $user_online_in_chat = 0;
1634
        if ($use_status_in_platform) {
1635
            $user_status = UserManager::get_extra_user_data_by_field(
1636
                $user_id,
1637
                'user_chat_status',
1638
                false,
1639
                true
1640
            );
1641
            if (1 == (int) $user_status['user_chat_status']) {
1642
                $user_online_in_chat = 1;
1643
            }
1644
        }
1645
        $result['user_is_online_in_chat'] = $user_online_in_chat;
1646
    }
1647
1648
    if ($loadExtraData) {
1649
        $fieldValue = new ExtraFieldValue('user');
1650
        $result['extra'] = $fieldValue->getAllValuesForAnItem(
1651
            $user_id,
1652
            $loadOnlyVisibleExtraData
1653
        );
1654
    }
1655
1656
    $result['username'] = $user->getUsername();
1657
    $result['status'] = $user->getStatus();
1658
    $result['firstname'] = $user->getFirstname();
1659
    $result['lastname'] = $user->getLastname();
1660
    $result['email'] = $result['mail'] = $user->getEmail();
1661
    $result['complete_name'] = api_get_person_name($result['firstname'], $result['lastname']);
1662
    $result['complete_name_with_username'] = $result['complete_name'];
1663
1664
    if (!empty($result['username']) && 'false' === api_get_setting('profile.hide_username_with_complete_name')) {
1665
        $result['complete_name_with_username'] = $result['complete_name'].' ('.$result['username'].')';
1666
    }
1667
1668
    $showEmail = 'true' === api_get_setting('show_email_addresses');
1669
    if (!empty($result['email'])) {
1670
        $result['complete_name_with_email_forced'] = $result['complete_name'].' ('.$result['email'].')';
1671
        if ($showEmail) {
1672
            $result['complete_name_with_email'] = $result['complete_name'].' ('.$result['email'].')';
1673
        }
1674
    } else {
1675
        $result['complete_name_with_email'] = $result['complete_name'];
1676
        $result['complete_name_with_email_forced'] = $result['complete_name'];
1677
    }
1678
1679
    // Kept for historical reasons
1680
    $result['firstName'] = $result['firstname'];
1681
    $result['lastName'] = $result['lastname'];
1682
1683
    $attributes = [
1684
        'picture_uri',
1685
        'last_login',
1686
        'user_is_online',
1687
    ];
1688
1689
    $result['phone'] = $user->getPhone();
1690
    $result['address'] = $user->getAddress();
1691
    $result['official_code'] = $user->getOfficialCode();
1692
    $result['active'] = $user->getActive();
1693
    $result['auth_source'] = $user->getAuthSource();
1694
    $result['language'] = $user->getLanguage();
1695
    $result['creator_id'] = $user->getCreatorId();
1696
    $result['registration_date'] = $user->getRegistrationDate()->format('Y-m-d H:i:s');
1697
    $result['hr_dept_id'] = $user->getHrDeptId();
1698
    $result['expiration_date'] = '';
1699
    if ($user->getExpirationDate()) {
1700
        $result['expiration_date'] = $user->getExpirationDate()->format('Y-m-d H:i:s');
1701
    }
1702
1703
    $result['last_login'] = null;
1704
    if ($user->getLastLogin()) {
1705
        $result['last_login'] = $user->getLastLogin()->format('Y-m-d H:i:s');
1706
    }
1707
1708
    $result['competences'] = $user->getCompetences();
1709
    $result['diplomas'] = $user->getDiplomas();
1710
    $result['teach'] = $user->getTeach();
1711
    $result['openarea'] = $user->getOpenarea();
1712
    $user_id = (int) $user->getId();
1713
1714
    // Maintain the user_id index for backwards compatibility
1715
    $result['user_id'] = $result['id'] = $user_id;
1716
1717
    if ($loadCertificate) {
1718
        $hasCertificates = Certificate::getCertificateByUser($user_id);
1719
        $result['has_certificates'] = 0;
1720
        if (!empty($hasCertificates)) {
1721
            $result['has_certificates'] = 1;
1722
        }
1723
    }
1724
1725
    $result['icon_status'] = '';
1726
    $result['icon_status_medium'] = '';
1727
    $result['is_admin'] = UserManager::is_admin($user_id);
1728
1729
    // Getting user avatar.
1730
    if ($loadAvatars) {
1731
        $result['avatar'] = '';
1732
        $result['avatar_no_query'] = '';
1733
        $result['avatar_small'] = '';
1734
        $result['avatar_medium'] = '';
1735
1736
        /*if (!isset($user['avatar'])) {
1737
            $originalFile = UserManager::getUserPicture(
1738
                $user_id,
1739
                USER_IMAGE_SIZE_ORIGINAL,
1740
                null,
1741
                $result
1742
            );
1743
            $result['avatar'] = $originalFile;
1744
            $avatarString = explode('?', $result['avatar']);
1745
            $result['avatar_no_query'] = reset($avatarString);
1746
        } else {
1747
            $result['avatar'] = $user['avatar'];
1748
            $avatarString = explode('?', $user['avatar']);
1749
            $result['avatar_no_query'] = reset($avatarString);
1750
        }
1751
1752
        if (!isset($user['avatar_small'])) {
1753
            $smallFile = UserManager::getUserPicture(
1754
                $user_id,
1755
                USER_IMAGE_SIZE_SMALL,
1756
                null,
1757
                $result
1758
            );
1759
            $result['avatar_small'] = $smallFile;
1760
        } else {
1761
            $result['avatar_small'] = $user['avatar_small'];
1762
        }
1763
1764
        if (!isset($user['avatar_medium'])) {
1765
            $mediumFile = UserManager::getUserPicture(
1766
                $user_id,
1767
                USER_IMAGE_SIZE_MEDIUM,
1768
                null,
1769
                $result
1770
            );
1771
            $result['avatar_medium'] = $mediumFile;
1772
        } else {
1773
            $result['avatar_medium'] = $user['avatar_medium'];
1774
        }*/
1775
1776
        //$urlImg = api_get_path(WEB_IMG_PATH);
1777
        $urlImg = '/';
1778
        $iconStatus = '';
1779
        $iconStatusMedium = '';
1780
1781
        switch ($user->getStatus()) {
1782
            case STUDENT:
1783
                if (isset($result['has_certificates']) && $result['has_certificates']) {
1784
                    $iconStatus = $urlImg.'icons/svg/identifier_graduated.svg';
1785
                } else {
1786
                    $iconStatus = $urlImg.'icons/svg/identifier_student.svg';
1787
                }
1788
                break;
1789
            case COURSEMANAGER:
1790
                if ($result['is_admin']) {
1791
                    $iconStatus = $urlImg.'icons/svg/identifier_admin.svg';
1792
                } else {
1793
                    $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1794
                }
1795
                break;
1796
            case STUDENT_BOSS:
1797
                $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1798
                break;
1799
        }
1800
1801
        if (!empty($iconStatus)) {
1802
            $iconStatusMedium = '<img src="'.$iconStatus.'" width="32px" height="32px">';
1803
            $iconStatus = '<img src="'.$iconStatus.'" width="22px" height="22px">';
1804
        }
1805
1806
        $result['icon_status'] = $iconStatus;
1807
        $result['icon_status_medium'] = $iconStatusMedium;
1808
    }
1809
1810
    if (isset($result['user_is_online'])) {
1811
        $result['user_is_online'] = true == $result['user_is_online'] ? 1 : 0;
1812
    }
1813
    if (isset($result['user_is_online_in_chat'])) {
1814
        $result['user_is_online_in_chat'] = (int) $result['user_is_online_in_chat'];
1815
    }
1816
1817
    $result['password'] = '';
1818
    if ($showPassword) {
1819
        $result['password'] = $user->getPassword();
1820
    }
1821
1822
    if (isset($result['profile_completed'])) {
1823
        $result['profile_completed'] = $result['profile_completed'];
1824
    }
1825
1826
    $result['profile_url'] = api_get_path(WEB_CODE_PATH).'social/profile.php?u='.$user_id;
1827
1828
    // Send message link
1829
    $sendMessage = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&user_id='.$user_id;
1830
    $result['complete_name_with_message_link'] = Display::url(
1831
        $result['complete_name_with_username'],
1832
        $sendMessage,
1833
        ['class' => 'ajax']
1834
    );
1835
1836
    if (isset($result['extra'])) {
1837
        $result['extra'] = $result['extra'];
1838
    }
1839
1840
    return $result;
1841
}
1842
1843
/**
1844
 * @param int $userId
1845
 *
1846
 * @return User
1847
 */
1848
function api_get_user_entity($userId)
1849
{
1850
    $userId = (int) $userId;
1851
    $repo = UserManager::getRepository();
1852
1853
    /** @var User $user */
1854
    $user = $repo->find($userId);
1855
1856
    return $user;
1857
}
1858
1859
/**
1860
 * @return User|null
1861
 */
1862
function api_get_current_user()
1863
{
1864
    $isLoggedIn = Container::$container->get('security.authorization_checker')->isGranted('IS_AUTHENTICATED_REMEMBERED');
1865
    if (false === $isLoggedIn) {
1866
        return null;
1867
    }
1868
1869
    $token = Container::$container->get('security.token_storage')->getToken();
1870
1871
    if (null !== $token) {
1872
        return $token->getUser();
1873
    }
1874
1875
    return null;
1876
}
1877
1878
/**
1879
 * Finds all the information about a user from username instead of user id.
1880
 *
1881
 * @param string $username
1882
 *
1883
 * @return mixed $user_info array user_id, lastname, firstname, username, email or false on error
1884
 *
1885
 * @author Yannick Warnier <[email protected]>
1886
 */
1887
function api_get_user_info_from_username($username)
1888
{
1889
    if (empty($username)) {
1890
        return false;
1891
    }
1892
    $username = trim($username);
1893
1894
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1895
            WHERE username='".Database::escape_string($username)."'";
1896
    $result = Database::query($sql);
1897
    if (Database::num_rows($result) > 0) {
1898
        $resultArray = Database::fetch_array($result);
1899
1900
        return _api_format_user($resultArray);
1901
    }
1902
1903
    return false;
1904
}
1905
1906
/**
1907
 * Get first user with an email.
1908
 *
1909
 * @param string $email
1910
 *
1911
 * @return array|bool
1912
 */
1913
function api_get_user_info_from_email($email = '')
1914
{
1915
    if (empty($email)) {
1916
        return false;
1917
    }
1918
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
1919
            WHERE email ='".Database::escape_string($email)."' LIMIT 1";
1920
    $result = Database::query($sql);
1921
    if (Database::num_rows($result) > 0) {
1922
        $resultArray = Database::fetch_array($result);
1923
1924
        return _api_format_user($resultArray);
1925
    }
1926
1927
    return false;
1928
}
1929
1930
/**
1931
 * @return string
1932
 */
1933
function api_get_course_id()
1934
{
1935
    return Session::read('_cid', null);
1936
}
1937
1938
/**
1939
 * Returns the current course id (integer).
1940
 *
1941
 * @param string $code Optional course code
1942
 *
1943
 * @return int
1944
 */
1945
function api_get_course_int_id($code = null)
1946
{
1947
    if (!empty($code)) {
1948
        $code = Database::escape_string($code);
1949
        $row = Database::select(
1950
            'id',
1951
            Database::get_main_table(TABLE_MAIN_COURSE),
1952
            ['where' => ['code = ?' => [$code]]],
1953
            'first'
1954
        );
1955
1956
        if (is_array($row) && isset($row['id'])) {
1957
            return $row['id'];
1958
        } else {
1959
            return false;
1960
        }
1961
    }
1962
1963
    return Session::read('_real_cid', 0);
1964
}
1965
1966
/**
1967
 * Returns the current course directory.
1968
 *
1969
 * This function relies on api_get_course_info()
1970
 *
1971
 * @param string    The course code - optional (takes it from session if not given)
1972
 *
1973
 * @return string The directory where the course is located inside the Chamilo "courses" directory
1974
 *
1975
 * @author Yannick Warnier <[email protected]>
1976
 */
1977
function api_get_course_path($course_code = null)
1978
{
1979
    $info = !empty($course_code) ? api_get_course_info($course_code) : api_get_course_info();
1980
1981
    return $info['path'];
1982
}
1983
1984
/**
1985
 * Gets a course setting from the current course_setting table. Try always using integer values.
1986
 *
1987
 * @param string $settingName The name of the setting we want from the table
1988
 * @param array  $courseInfo
1989
 * @param bool   $force       force checking the value in the database
1990
 *
1991
 * @return mixed The value of that setting in that table. Return -1 if not found.
1992
 */
1993
function api_get_course_setting($settingName, $courseInfo = [], $force = false)
1994
{
1995
    if (empty($courseInfo)) {
1996
        $courseInfo = api_get_course_info();
1997
    }
1998
1999
    if (empty($courseInfo) || empty($settingName)) {
2000
        return -1;
2001
    }
2002
2003
    $courseId = isset($courseInfo['real_id']) && !empty($courseInfo['real_id']) ? $courseInfo['real_id'] : 0;
2004
2005
    if (empty($courseId)) {
2006
        return -1;
2007
    }
2008
2009
    static $courseSettingInfo = [];
2010
2011
    if ($force) {
2012
        $courseSettingInfo = [];
2013
    }
2014
2015
    if (!isset($courseSettingInfo[$courseId])) {
2016
        $table = Database::get_course_table(TABLE_COURSE_SETTING);
2017
        $settingName = Database::escape_string($settingName);
2018
2019
        $sql = "SELECT variable, value FROM $table
2020
                WHERE c_id = $courseId ";
2021
        $res = Database::query($sql);
2022
        if (Database::num_rows($res) > 0) {
2023
            $result = Database::store_result($res, 'ASSOC');
2024
            $courseSettingInfo[$courseId] = array_column($result, 'value', 'variable');
2025
2026
            if (isset($courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'])) {
2027
                $value = $courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'];
2028
                if (!is_null($value)) {
2029
                    $result = explode(',', $value);
2030
                    $courseSettingInfo[$courseId]['email_alert_manager_on_new_quiz'] = $result;
2031
                }
2032
            }
2033
        }
2034
    }
2035
2036
    if (isset($courseSettingInfo[$courseId]) && isset($courseSettingInfo[$courseId][$settingName])) {
2037
        return $courseSettingInfo[$courseId][$settingName];
2038
    }
2039
2040
    return -1;
2041
}
2042
2043
function api_get_course_plugin_setting($plugin, $settingName, $courseInfo = [])
2044
{
2045
    $value = api_get_course_setting($settingName, $courseInfo, true);
2046
2047
    if (-1 === $value) {
2048
        // Check global settings
2049
        $value = api_get_plugin_setting($plugin, $settingName);
2050
        if ($value === 'true') {
2051
            return 1;
2052
        }
2053
        if ($value === 'false') {
2054
            return 0;
2055
        }
2056
        if (null === $value) {
2057
            return -1;
2058
        }
2059
    }
2060
2061
    return $value;
2062
}
2063
2064
/**
2065
 * Gets an anonymous user ID.
2066
 *
2067
 * For some tools that need tracking, like the learnpath tool, it is necessary
2068
 * to have a usable user-id to enable some kind of tracking, even if not
2069
 * perfect. An anonymous ID is taken from the users table by looking for a
2070
 * status of "6" (anonymous).
2071
 *
2072
 * @return int User ID of the anonymous user, or O if no anonymous user found
2073
 */
2074
function api_get_anonymous_id()
2075
{
2076
    // Find if another anon is connected now
2077
    $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
2078
    $tableU = Database::get_main_table(TABLE_MAIN_USER);
2079
    $ip = Database::escape_string(api_get_real_ip());
2080
    $max = (int) api_get_configuration_value('max_anonymous_users');
2081
    if ($max >= 2) {
2082
        $sql = "SELECT * FROM $table as TEL
2083
                JOIN $tableU as U
2084
                ON U.user_id = TEL.login_user_id
2085
                WHERE TEL.user_ip = '$ip'
2086
                    AND U.status = ".ANONYMOUS."
2087
                    AND U.user_id != 2 ";
2088
2089
        $result = Database::query($sql);
2090
        if (empty(Database::num_rows($result))) {
2091
            $login = uniqid('anon_');
2092
            $anonList = UserManager::get_user_list(['status' => ANONYMOUS], ['registration_date ASC']);
2093
            if (count($anonList) >= $max) {
2094
                foreach ($anonList as $userToDelete) {
2095
                    UserManager::delete_user($userToDelete['user_id']);
2096
                    break;
2097
                }
2098
            }
2099
2100
            return UserManager::create_user(
0 ignored issues
show
Bug Best Practice introduced by
The expression return UserManager::crea...lhost', $login, $login) could also return false which is incompatible with the documented return type integer. Did you maybe forget to handle an error condition?

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

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

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

2277
    return /** @scrutinizer ignore-deprecated */ CourseManager::getManager()->find($courseId);
Loading history...
2278
}
2279
2280
/**
2281
 * @param int $id
2282
 *
2283
 * @return SessionEntity|null
2284
 */
2285
function api_get_session_entity($id = 0)
2286
{
2287
    if (empty($id)) {
2288
        $id = api_get_session_id();
2289
    }
2290
2291
    if (empty($id)) {
2292
        return null;
2293
    }
2294
2295
    return Database::getManager()->getRepository('ChamiloCoreBundle:Session')->find($id);
2296
}
2297
2298
/**
2299
 * @param int $id
2300
 *
2301
 * @return CGroup
2302
 */
2303
function api_get_group_entity($id = 0)
2304
{
2305
    if (empty($id)) {
2306
        $id = api_get_group_id();
2307
    }
2308
2309
    return Database::getManager()->getRepository('ChamiloCourseBundle:CGroup')->find($id);
2310
}
2311
2312
/**
2313
 * @param int $id
2314
 *
2315
 * @return AccessUrl
2316
 */
2317
function api_get_url_entity($id = 0)
2318
{
2319
    if (empty($id)) {
2320
        $id = api_get_current_access_url_id();
2321
    }
2322
2323
    return Container::getAccessUrlRepository()->find($id);
2324
}
2325
2326
/**
2327
 * Returns the current course info array.
2328
2329
 * Now if the course_code is given, the returned array gives info about that
2330
 * particular course, not specially the current one.
2331
 *
2332
 * @param int $id Numeric ID of the course
2333
 *
2334
 * @return array The course info as an array formatted by api_format_course_array, including category.name
2335
 */
2336
function api_get_course_info_by_id($id = 0)
2337
{
2338
    $id = (int) $id;
2339
    if (empty($id)) {
2340
        $course = Session::read('_course', []);
2341
2342
        return $course;
2343
    }
2344
2345
    $course = Container::getCourseRepository()->find($id);
2346
    if (empty($course)) {
2347
        return [];
2348
    }
2349
2350
    return api_format_course_array($course);
2351
}
2352
2353
/**
2354
 * Reformat the course array (output by api_get_course_info()) in order, mostly,
2355
 * to switch from 'code' to 'id' in the array.
2356
 *
2357
 * @return array
2358
 *
2359
 * @todo eradicate the false "id"=code field of the $_course array and use the int id
2360
 */
2361
function api_format_course_array(Course $course)
2362
{
2363
    if (empty($course)) {
2364
        return [];
2365
    }
2366
2367
    $category = $course->getCategory();
2368
2369
    $courseData = [];
2370
    $courseData['categoryCode'] = '';
2371
    $courseData['categoryName'] = '';
2372
    $courseData['category_id'] = 0;
2373
    if ($category) {
0 ignored issues
show
introduced by
$category is of type Chamilo\CoreBundle\Entity\CourseCategory, thus it always evaluated to true.
Loading history...
2374
        $courseData['categoryCode'] = $category->getCode();
2375
        $courseData['categoryName'] = $category->getName();
2376
        $courseData['category_id'] = $category->getId();
2377
    }
2378
2379
    $courseData['id'] = $courseData['real_id'] = $course->getId();
2380
2381
    // Added
2382
    $courseData['code'] = $courseData['sysCode'] = $course->getCode();
2383
    $courseData['name'] = $courseData['title'] = $course->getTitle();
2384
    $courseData['official_code'] = $courseData['visual_code'] = $course->getVisualCode();
2385
    $courseData['path'] = $courseData['directory'] = $course->getDirectory(); // Use as key in path.
2386
    $courseData['creation_date'] = $course->getCreationDate()->format('Y-m-d H:i:s');
2387
    $courseData['titular'] = $course->getTutorName();
2388
    $courseData['language'] = $courseData['course_language'] = $course->getCourseLanguage();
2389
    $courseData['extLink']['url'] = $courseData['department_url'] = $course->getDepartmentUrl();
2390
    $courseData['extLink']['name'] = $courseData['department_name'] = $course->getDepartmentName();
2391
2392
    $courseData['visibility'] = $course->getVisibility();
2393
    $courseData['subscribe_allowed'] = $courseData['subscribe'] = $course->getSubscribe();
2394
    $courseData['unsubscribe'] = $course->getUnsubscribe();
2395
    $courseData['activate_legal'] = $course->getActivateLegal();
2396
    $courseData['legal'] = $course->getLegal();
2397
    $courseData['show_score'] = $course->getShowScore(); //used in the work tool
2398
2399
    $coursePath = api_get_path(WEB_COURSE_PATH);
2400
    $webCourseHome = $coursePath.$courseData['real_id'].'/home';
2401
2402
    // Course password
2403
    $courseData['registration_code'] = $course->getRegistrationCode();
2404
    $courseData['disk_quota'] = $course->getDiskQuota();
2405
    $courseData['course_public_url'] = $webCourseHome;
2406
    $courseData['about_url'] = $coursePath.$courseData['real_id'].'/about';
2407
    $courseData['add_teachers_to_sessions_courses'] = $course->isAddTeachersToSessionsCourses();
2408
    $courseData['entity'] = $course;
2409
2410
    $image = Display::return_icon(
2411
        'course.png',
2412
        null,
2413
        null,
2414
        ICON_SIZE_BIG,
2415
        null,
2416
        true,
2417
        false
2418
    );
2419
2420
    $illustration = Container::getIllustrationRepository()->getIllustrationUrl($course);
2421
    if (!empty($illustration)) {
2422
        $image = $illustration;
2423
    }
2424
2425
    $courseData['course_image'] = $image.'?filter=course_picture_small';
2426
2427
    // Course large image
2428
    /*$courseData['course_image_large_source'] = '';
2429
    if (file_exists($courseSys.'/course-pic.png')) {
2430
        $url_image = $webCourseHome.'/course-pic.png';
2431
        $courseData['course_image_large_source'] = $courseSys.'/course-pic.png';
2432
    } else {
2433
        $url_image = Display::return_icon(
2434
            'session_default.png',
2435
            null,
2436
            null,
2437
            null,
2438
            null,
2439
            true,
2440
            true
2441
        );
2442
    }*/
2443
2444
    $courseData['course_image_large'] = $image.'?filter=course_picture_medium';
2445
2446
    return $courseData;
2447
}
2448
2449
/**
2450
 * Returns a difficult to guess password.
2451
 *
2452
 * @param int $length the length of the password
2453
 *
2454
 * @return string the generated password
2455
 */
2456
function api_generate_password($length = 8)
2457
{
2458
    if ($length < 2) {
2459
        $length = 2;
2460
    }
2461
2462
    $charactersLowerCase = 'abcdefghijkmnopqrstuvwxyz';
2463
    $charactersUpperCase = 'ABCDEFGHJKLMNPQRSTUVWXYZ';
2464
    $minNumbers = 2;
2465
    $length = $length - $minNumbers;
2466
    $minLowerCase = round($length / 2);
2467
    $minUpperCase = $length - $minLowerCase;
2468
2469
    $password = '';
2470
    $passwordRequirements = api_get_configuration_value('password_requirements');
2471
2472
    $factory = new RandomLib\Factory();
2473
    $generator = $factory->getGenerator(new SecurityLib\Strength(SecurityLib\Strength::MEDIUM));
2474
2475
    if (!empty($passwordRequirements)) {
2476
        $length = $passwordRequirements['min']['length'];
2477
        $minNumbers = $passwordRequirements['min']['numeric'];
2478
        $minLowerCase = $passwordRequirements['min']['lowercase'];
2479
        $minUpperCase = $passwordRequirements['min']['uppercase'];
2480
2481
        $rest = $length - $minNumbers - $minLowerCase - $minUpperCase;
2482
        // Add the rest to fill the length requirement
2483
        if ($rest > 0) {
2484
            $password .= $generator->generateString($rest, $charactersLowerCase.$charactersUpperCase);
2485
        }
2486
    }
2487
2488
    // Min digits default 2
2489
    for ($i = 0; $i < $minNumbers; $i++) {
2490
        $password .= $generator->generateInt(2, 9);
2491
    }
2492
2493
    // Min lowercase
2494
    $password .= $generator->generateString($minLowerCase, $charactersLowerCase);
2495
2496
    // Min uppercase
2497
    $password .= $generator->generateString($minUpperCase, $charactersUpperCase);
2498
    $password = str_shuffle($password);
2499
2500
    return $password;
2501
}
2502
2503
/**
2504
 * Checks a password to see wether it is OK to use.
2505
 *
2506
 * @param string $password
2507
 *
2508
 * @return bool if the password is acceptable, false otherwise
2509
 *              Notes about what a password "OK to use" is:
2510
 *              1. The password should be at least 5 characters long.
2511
 *              2. Only English letters (uppercase or lowercase, it doesn't matter) and digits are allowed.
2512
 *              3. The password should contain at least 3 letters.
2513
 *              4. It should contain at least 2 digits.
2514
 *              Settings will change if the configuration value is set: password_requirements
2515
 */
2516
function api_check_password($password)
2517
{
2518
    $passwordRequirements = Security::getPasswordRequirements();
2519
2520
    $minLength = $passwordRequirements['min']['length'];
2521
    $minNumbers = $passwordRequirements['min']['numeric'];
2522
    // Optional
2523
    $minLowerCase = $passwordRequirements['min']['lowercase'];
2524
    $minUpperCase = $passwordRequirements['min']['uppercase'];
2525
2526
    $minLetters = $minLowerCase + $minUpperCase;
2527
    $passwordLength = api_strlen($password);
2528
2529
    $conditions = [
2530
        'min_length' => $passwordLength >= $minLength,
2531
    ];
2532
2533
    $digits = 0;
2534
    $lowerCase = 0;
2535
    $upperCase = 0;
2536
2537
    for ($i = 0; $i < $passwordLength; $i++) {
2538
        $currentCharacterCode = api_ord(api_substr($password, $i, 1));
2539
        if ($currentCharacterCode >= 65 && $currentCharacterCode <= 90) {
2540
            $upperCase++;
2541
        }
2542
2543
        if ($currentCharacterCode >= 97 && $currentCharacterCode <= 122) {
2544
            $lowerCase++;
2545
        }
2546
        if ($currentCharacterCode >= 48 && $currentCharacterCode <= 57) {
2547
            $digits++;
2548
        }
2549
    }
2550
2551
    // Min number of digits
2552
    $conditions['min_numeric'] = $digits >= $minNumbers;
2553
2554
    if (!empty($minUpperCase)) {
2555
        // Uppercase
2556
        $conditions['min_uppercase'] = $upperCase >= $minUpperCase;
2557
    }
2558
2559
    if (!empty($minLowerCase)) {
2560
        // Lowercase
2561
        $conditions['min_lowercase'] = $upperCase >= $minLowerCase;
2562
    }
2563
2564
    // Min letters
2565
    $letters = $upperCase + $lowerCase;
2566
    $conditions['min_letters'] = $letters >= $minLetters;
2567
2568
    $isPasswordOk = true;
2569
    foreach ($conditions as $condition) {
2570
        if (false === $condition) {
2571
            $isPasswordOk = false;
2572
            break;
2573
        }
2574
    }
2575
2576
    if (false === $isPasswordOk) {
2577
        $output = get_lang('The new password does not match the minimum security requirements').'<br />';
2578
        $output .= Security::getPasswordRequirementsToString($conditions);
2579
2580
        Display::addFlash(Display::return_message($output, 'warning', false));
2581
    }
2582
2583
    return $isPasswordOk;
2584
}
2585
2586
/**
2587
 * Returns the status string corresponding to the status code.
2588
 *
2589
 * @author Noel Dieschburg
2590
 *
2591
 * @param the int status code
2592
 *
2593
 * @return string
2594
 */
2595
function get_status_from_code($status_code)
2596
{
2597
    switch ($status_code) {
2598
        case STUDENT:
2599
            return get_lang('Student', '');
2600
        case COURSEMANAGER:
2601
            return get_lang('Teacher', '');
2602
        case SESSIONADMIN:
2603
            return get_lang('SessionsAdmin', '');
2604
        case DRH:
2605
            return get_lang('Drh', '');
2606
    }
2607
}
2608
2609
/**
2610
 * Gets the current Chamilo (not PHP/cookie) session ID.
2611
 *
2612
 * @return int O if no active session, the session ID otherwise
2613
 */
2614
function api_get_session_id()
2615
{
2616
    return (int) Session::read('sid', 0);
2617
}
2618
2619
/**
2620
 * Gets the current Chamilo (not social network) group ID.
2621
 *
2622
 * @return int O if no active session, the session ID otherwise
2623
 */
2624
function api_get_group_id()
2625
{
2626
    return Session::read('gid', 0);
2627
}
2628
2629
/**
2630
 * Gets the current or given session name.
2631
 *
2632
 * @param   int     Session ID (optional)
2633
 *
2634
 * @return string The session name, or null if not found
2635
 */
2636
function api_get_session_name($session_id = 0)
2637
{
2638
    if (empty($session_id)) {
2639
        $session_id = api_get_session_id();
2640
        if (empty($session_id)) {
2641
            return null;
2642
        }
2643
    }
2644
    $t = Database::get_main_table(TABLE_MAIN_SESSION);
2645
    $s = "SELECT name FROM $t WHERE id = ".(int) $session_id;
2646
    $r = Database::query($s);
2647
    $c = Database::num_rows($r);
2648
    if ($c > 0) {
2649
        //technically, there can be only one, but anyway we take the first
2650
        $rec = Database::fetch_array($r);
2651
2652
        return $rec['name'];
2653
    }
2654
2655
    return null;
2656
}
2657
2658
/**
2659
 * Gets the session info by id.
2660
 *
2661
 * @param int $id Session ID
2662
 *
2663
 * @return array information of the session
2664
 */
2665
function api_get_session_info($id)
2666
{
2667
    return SessionManager::fetch($id);
2668
}
2669
2670
/**
2671
 * Gets the session visibility by session id.
2672
 *
2673
 * @param int  $session_id
2674
 * @param int  $courseId
2675
 * @param bool $ignore_visibility_for_admins
2676
 *
2677
 * @return int
2678
 *             0 = session still available,
2679
 *             SESSION_VISIBLE_READ_ONLY = 1,
2680
 *             SESSION_VISIBLE = 2,
2681
 *             SESSION_INVISIBLE = 3
2682
 */
2683
function api_get_session_visibility(
2684
    $session_id,
2685
    $courseId = null,
2686
    $ignore_visibility_for_admins = true
2687
) {
2688
    if (api_is_platform_admin()) {
2689
        if ($ignore_visibility_for_admins) {
2690
            return SESSION_AVAILABLE;
2691
        }
2692
    }
2693
2694
    $now = time();
2695
    if (empty($session_id)) {
2696
        return 0; // Means that the session is still available.
2697
    }
2698
2699
    $session_id = (int) $session_id;
2700
    $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
2701
2702
    $result = Database::query("SELECT * FROM $tbl_session WHERE id = $session_id");
2703
2704
    if (Database::num_rows($result) <= 0) {
2705
        return SESSION_INVISIBLE;
2706
    }
2707
2708
    $row = Database::fetch_array($result, 'ASSOC');
2709
    $visibility = $row['visibility'];
2710
2711
    // I don't care the session visibility.
2712
    if (empty($row['access_start_date']) && empty($row['access_end_date'])) {
2713
        // Session duration per student.
2714
        if (isset($row['duration']) && !empty($row['duration'])) {
2715
            $duration = $row['duration'] * 24 * 60 * 60;
2716
            $courseAccess = CourseManager::getFirstCourseAccessPerSessionAndUser($session_id, api_get_user_id());
2717
2718
            // If there is a session duration but there is no previous
2719
            // access by the user, then the session is still available
2720
            if (0 == count($courseAccess)) {
2721
                return SESSION_AVAILABLE;
2722
            }
2723
2724
            $currentTime = time();
2725
            $firstAccess = isset($courseAccess['login_course_date'])
2726
                ? api_strtotime($courseAccess['login_course_date'], 'UTC')
2727
                : 0;
2728
            $userDurationData = SessionManager::getUserSession(
2729
                api_get_user_id(),
2730
                $session_id
2731
            );
2732
            $userDuration = isset($userDurationData['duration'])
2733
                ? (intval($userDurationData['duration']) * 24 * 60 * 60)
2734
                : 0;
2735
2736
            $totalDuration = $firstAccess + $duration + $userDuration;
2737
2738
            return $totalDuration > $currentTime ? SESSION_AVAILABLE : SESSION_VISIBLE_READ_ONLY;
2739
        }
2740
2741
        return SESSION_AVAILABLE;
2742
    }
2743
2744
    // If start date was set.
2745
    if (!empty($row['access_start_date'])) {
2746
        $visibility = $now > api_strtotime($row['access_start_date'], 'UTC') ? SESSION_AVAILABLE : SESSION_INVISIBLE;
2747
    }
2748
2749
    // If the end date was set.
2750
    if (!empty($row['access_end_date'])) {
2751
        // Only if date_start said that it was ok
2752
        if (SESSION_AVAILABLE === $visibility) {
2753
            $visibility = $now < api_strtotime($row['access_end_date'], 'UTC')
2754
                ? SESSION_AVAILABLE // Date still available
2755
                : $row['visibility']; // Session ends
2756
        }
2757
    }
2758
2759
    // If I'm a coach the visibility can change in my favor depending in the coach dates.
2760
    $isCoach = api_is_coach($session_id, $courseId);
2761
2762
    if ($isCoach) {
2763
        // Test start date.
2764
        if (!empty($row['coach_access_start_date'])) {
2765
            $start = api_strtotime($row['coach_access_start_date'], 'UTC');
2766
            $visibility = $start < $now ? SESSION_AVAILABLE : SESSION_INVISIBLE;
2767
        }
2768
2769
        // Test end date.
2770
        if (!empty($row['coach_access_end_date'])) {
2771
            if (SESSION_AVAILABLE === $visibility) {
2772
                $endDateCoach = api_strtotime($row['coach_access_end_date'], 'UTC');
2773
                $visibility = $endDateCoach >= $now ? SESSION_AVAILABLE : $row['visibility'];
2774
            }
2775
        }
2776
    }
2777
2778
    return $visibility;
2779
}
2780
2781
/**
2782
 * This function returns a (star) session icon if the session is not null and
2783
 * the user is not a student.
2784
 *
2785
 * @param int $sessionId
2786
 * @param int $statusId  User status id - if 5 (student), will return empty
2787
 *
2788
 * @return string Session icon
2789
 */
2790
function api_get_session_image($sessionId, $statusId)
2791
{
2792
    $sessionId = (int) $sessionId;
2793
    $image = '';
2794
    if (STUDENT != $statusId) {
2795
        // Check whether is not a student
2796
        if ($sessionId > 0) {
2797
            $image = '&nbsp;&nbsp;'.Display::return_icon(
2798
                'star.png',
2799
                get_lang('Session-specific resource'),
2800
                ['align' => 'absmiddle'],
2801
                ICON_SIZE_SMALL
2802
            );
2803
        }
2804
    }
2805
2806
    return $image;
2807
}
2808
2809
/**
2810
 * This function add an additional condition according to the session of the course.
2811
 *
2812
 * @param int    $session_id        session id
2813
 * @param bool   $and               optional, true if more than one condition false if the only condition in the query
2814
 * @param bool   $with_base_content optional, true to accept content with session=0 as well,
2815
 *                                  false for strict session condition
2816
 * @param string $session_field
2817
 *
2818
 * @return string condition of the session
2819
 */
2820
function api_get_session_condition(
2821
    $session_id,
2822
    $and = true,
2823
    $with_base_content = false,
2824
    $session_field = 'session_id'
2825
) {
2826
    $session_id = (int) $session_id;
2827
2828
    if (empty($session_field)) {
2829
        $session_field = 'session_id';
2830
    }
2831
    // Condition to show resources by session
2832
    $condition_add = $and ? ' AND ' : ' WHERE ';
2833
2834
    if ($with_base_content) {
2835
        $condition_session = $condition_add." ( $session_field = $session_id OR $session_field = 0 OR $session_field IS NULL) ";
2836
    } else {
2837
        if (empty($session_id)) {
2838
            $condition_session = $condition_add." ($session_field = $session_id OR $session_field IS NULL)";
2839
        } else {
2840
            $condition_session = $condition_add." $session_field = $session_id ";
2841
        }
2842
    }
2843
2844
    return $condition_session;
2845
}
2846
2847
/**
2848
 * Returns the value of a setting from the web-adjustable admin config settings.
2849
 *
2850
 * WARNING true/false are stored as string, so when comparing you need to check e.g.
2851
 * if (api_get_setting('show_navigation_menu') == 'true') //CORRECT
2852
 * instead of
2853
 * if (api_get_setting('show_navigation_menu') == true) //INCORRECT
2854
 *
2855
 * @param string $variable The variable name
2856
 *
2857
 * @return string
2858
 */
2859
function api_get_setting($variable)
2860
{
2861
    $settingsManager = Container::getSettingsManager();
2862
    if (empty($settingsManager)) {
2863
        return '';
2864
    }
2865
    $variable = trim($variable);
2866
2867
    switch ($variable) {
2868
        /*case 'header_extra_content':
2869
            $filename = api_get_path(SYS_PATH).api_get_home_path().'header_extra_content.txt';
2870
            if (file_exists($filename)) {
2871
                $value = file_get_contents($filename);
2872
2873
                return $value;
2874
            } else {
2875
                return '';
2876
            }
2877
            break;
2878
        case 'footer_extra_content':
2879
            $filename = api_get_path(SYS_PATH).api_get_home_path().'footer_extra_content.txt';
2880
            if (file_exists($filename)) {
2881
                $value = file_get_contents($filename);
2882
2883
                return $value;
2884
            } else {
2885
                return '';
2886
            }
2887
            break;*/
2888
        case 'server_type':
2889
            $test = ['dev', 'test'];
2890
            $environment = Container::getEnvironment();
2891
            if (in_array($environment, $test)) {
2892
                return 'test';
2893
            }
2894
2895
            return 'prod';
2896
        case 'stylesheets':
2897
            $variable = 'platform.theme';
2898
        // deprecated settings
2899
        // no break
2900
        case 'openid_authentication':
2901
        case 'service_ppt2lp':
2902
        case 'formLogin_hide_unhide_label':
2903
            return false;
2904
            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...
2905
        case 'tool_visible_by_default_at_creation':
2906
            $values = $settingsManager->getSetting($variable);
2907
            $newResult = [];
2908
            foreach ($values as $parameter) {
2909
                $newResult[$parameter] = 'true';
2910
            }
2911
2912
            return $newResult;
2913
            break;
2914
        default:
2915
            return $settingsManager->getSetting($variable);
2916
            break;
2917
    }
2918
}
2919
2920
/**
2921
 * @param string $variable
2922
 * @param string $option
2923
 *
2924
 * @return bool
2925
 */
2926
function api_get_setting_in_list($variable, $option)
2927
{
2928
    $value = api_get_setting($variable);
2929
2930
    return in_array($option, $value);
2931
}
2932
2933
/**
2934
 * @param string $plugin
2935
 * @param string $variable
2936
 *
2937
 * @return string
2938
 */
2939
function api_get_plugin_setting($plugin, $variable)
2940
{
2941
    $variableName = $plugin.'_'.$variable;
2942
    //$result = api_get_setting($variableName);
2943
    $params = [
2944
        'category = ? AND subkey = ? AND variable = ?' => [
2945
            'Plugins',
2946
            $plugin,
2947
            $variableName,
2948
        ],
2949
    ];
2950
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2951
    $result = Database::select(
2952
        'selected_value',
2953
        $table,
2954
        ['where' => $params],
2955
        'one'
2956
    );
2957
    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...
2958
        $value = $result['selected_value'];
2959
        $serializedValue = @unserialize($result['selected_value'], []);
2960
        if (false !== $serializedValue) {
2961
            $value = $serializedValue;
2962
        }
2963
2964
        return $value;
2965
    }
2966
2967
    return null;
2968
    /// Old code
2969
2970
    $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...
2971
    $result = api_get_setting($variableName);
2972
2973
    if (isset($result[$plugin])) {
2974
        $value = $result[$plugin];
2975
2976
        $unserialized = UnserializeApi::unserialize('not_allowed_classes', $value, true);
2977
2978
        if (false !== $unserialized) {
2979
            $value = $unserialized;
2980
        }
2981
2982
        return $value;
2983
    }
2984
2985
    return null;
2986
}
2987
2988
/**
2989
 * Returns the value of a setting from the web-adjustable admin config settings.
2990
 */
2991
function api_get_settings_params($params)
2992
{
2993
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2994
    $result = Database::select('*', $table, ['where' => $params]);
2995
2996
    return $result;
2997
}
2998
2999
/**
3000
 * @param array $params example: [id = ? => '1']
3001
 *
3002
 * @return array
3003
 */
3004
function api_get_settings_params_simple($params)
3005
{
3006
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
3007
    $result = Database::select('*', $table, ['where' => $params], 'one');
3008
3009
    return $result;
3010
}
3011
3012
/**
3013
 * Returns the value of a setting from the web-adjustable admin config settings.
3014
 */
3015
function api_delete_settings_params($params)
3016
{
3017
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
3018
    $result = Database::delete($table, $params);
3019
3020
    return $result;
3021
}
3022
3023
/**
3024
 * Returns an escaped version of $_SERVER['PHP_SELF'] to avoid XSS injection.
3025
 *
3026
 * @return string Escaped version of $_SERVER['PHP_SELF']
3027
 */
3028
function api_get_self()
3029
{
3030
    return htmlentities($_SERVER['PHP_SELF']);
3031
}
3032
3033
/* USER PERMISSIONS */
3034
3035
/**
3036
 * Checks whether current user is a platform administrator.
3037
 *
3038
 * @param bool $allowSessionAdmins Whether session admins should be considered admins or not
3039
 * @param bool $allowDrh           Whether HR directors should be considered admins or not
3040
 *
3041
 * @return bool true if the user has platform admin rights,
3042
 *              false otherwise
3043
 *
3044
 * @see usermanager::is_admin(user_id) for a user-id specific function
3045
 */
3046
function api_is_platform_admin($allowSessionAdmins = false, $allowDrh = false)
3047
{
3048
    $currentUser = api_get_current_user();
3049
3050
    if (null === $currentUser) {
3051
        return false;
3052
    }
3053
3054
    $isAdmin = Session::read('is_platformAdmin');
3055
    if ($isAdmin) {
3056
        return true;
3057
    }
3058
    $user = api_get_user_info();
3059
3060
    return
3061
        isset($user['status']) &&
3062
        (
3063
            ($allowSessionAdmins && SESSIONADMIN == $user['status']) ||
3064
            ($allowDrh && DRH == $user['status'])
3065
        );
3066
}
3067
3068
/**
3069
 * Checks whether the user given as user id is in the admin table.
3070
 *
3071
 * @param int $user_id If none provided, will use current user
3072
 * @param int $url     URL ID. If provided, also check if the user is active on given URL
3073
 *
3074
 * @return bool True if the user is admin, false otherwise
3075
 */
3076
function api_is_platform_admin_by_id($user_id = null, $url = null)
3077
{
3078
    $user_id = (int) $user_id;
3079
    if (empty($user_id)) {
3080
        $user_id = api_get_user_id();
3081
    }
3082
    $admin_table = Database::get_main_table(TABLE_MAIN_ADMIN);
3083
    $sql = "SELECT * FROM $admin_table WHERE user_id = $user_id";
3084
    $res = Database::query($sql);
3085
    $is_admin = 1 === Database::num_rows($res);
3086
    if (!$is_admin || !isset($url)) {
3087
        return $is_admin;
3088
    }
3089
    // We get here only if $url is set
3090
    $url = (int) $url;
3091
    $url_user_table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
3092
    $sql = "SELECT * FROM $url_user_table
3093
            WHERE access_url_id = $url AND user_id = $user_id";
3094
    $res = Database::query($sql);
3095
    $result = 1 === Database::num_rows($res);
3096
3097
    return $result;
3098
}
3099
3100
/**
3101
 * Returns the user's numeric status ID from the users table.
3102
 *
3103
 * @param int $user_id If none provided, will use current user
3104
 *
3105
 * @return int User's status (1 for teacher, 5 for student, etc)
3106
 */
3107
function api_get_user_status($user_id = null)
3108
{
3109
    $user_id = (int) $user_id;
3110
    if (empty($user_id)) {
3111
        $user_id = api_get_user_id();
3112
    }
3113
    $table = Database::get_main_table(TABLE_MAIN_USER);
3114
    $sql = "SELECT status FROM $table WHERE user_id = $user_id ";
3115
    $result = Database::query($sql);
3116
    $status = null;
3117
    if (Database::num_rows($result)) {
3118
        $row = Database::fetch_array($result);
3119
        $status = $row['status'];
3120
    }
3121
3122
    return $status;
3123
}
3124
3125
/**
3126
 * Checks whether current user is allowed to create courses.
3127
 *
3128
 * @return bool true if the user has course creation rights,
3129
 *              false otherwise
3130
 */
3131
function api_is_allowed_to_create_course()
3132
{
3133
    if (api_is_platform_admin()) {
3134
        return true;
3135
    }
3136
3137
    // Teachers can only create courses
3138
    if (api_is_teacher()) {
3139
        if ('true' === api_get_setting('allow_users_to_create_courses')) {
3140
            return true;
3141
        } else {
3142
            return false;
3143
        }
3144
    }
3145
3146
    return Session::read('is_allowedCreateCourse');
3147
}
3148
3149
/**
3150
 * Checks whether the current user is a course administrator.
3151
 *
3152
 * @return bool True if current user is a course administrator
3153
 */
3154
function api_is_course_admin()
3155
{
3156
    if (api_is_platform_admin()) {
3157
        return true;
3158
    }
3159
3160
    $user = api_get_current_user();
3161
    if ($user) {
3162
        if (
3163
            $user->hasRole('ROLE_CURRENT_SESSION_COURSE_TEACHER') ||
3164
            $user->hasRole('ROLE_CURRENT_COURSE_TEACHER')
3165
        ) {
3166
            return true;
3167
        }
3168
    }
3169
3170
    return false;
3171
    //return Session::read('is_courseAdmin');
3172
}
3173
3174
/**
3175
 * Checks whether the current user is a course coach
3176
 * Based on the presence of user in session.id_coach (session general coach).
3177
 *
3178
 * @return bool True if current user is a course coach
3179
 */
3180
function api_is_session_general_coach()
3181
{
3182
    return Session::read('is_session_general_coach');
3183
}
3184
3185
/**
3186
 * Checks whether the current user is a course tutor
3187
 * Based on the presence of user in session_rel_course_rel_user.user_id with status = 2.
3188
 *
3189
 * @return bool True if current user is a course tutor
3190
 */
3191
function api_is_course_tutor()
3192
{
3193
    return Session::read('is_courseTutor');
3194
}
3195
3196
/**
3197
 * @param int $user_id
3198
 * @param int $courseId
3199
 * @param int $session_id
3200
 *
3201
 * @return bool
3202
 */
3203
function api_is_course_session_coach($user_id, $courseId, $session_id)
3204
{
3205
    $session_table = Database::get_main_table(TABLE_MAIN_SESSION);
3206
    $session_rel_course_rel_user_table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3207
3208
    $user_id = (int) $user_id;
3209
    $session_id = (int) $session_id;
3210
    $courseId = (int) $courseId;
3211
3212
    $sql = "SELECT DISTINCT session.id
3213
            FROM $session_table
3214
            INNER JOIN $session_rel_course_rel_user_table session_rc_ru
3215
            ON session.id = session_rc_ru.session_id
3216
            WHERE
3217
                session_rc_ru.user_id = '".$user_id."'  AND
3218
                session_rc_ru.c_id = '$courseId' AND
3219
                session_rc_ru.status = 2 AND
3220
                session_rc_ru.session_id = '$session_id'";
3221
    $result = Database::query($sql);
3222
3223
    return Database::num_rows($result) > 0;
3224
}
3225
3226
/**
3227
 * Checks whether the current user is a course or session coach.
3228
 *
3229
 * @param int $session_id
3230
 * @param int $courseId
3231
 * @param bool  Check whether we are in student view and, if we are, return false
3232
 *
3233
 * @return bool True if current user is a course or session coach
3234
 */
3235
function api_is_coach($session_id = 0, $courseId = null, $check_student_view = true)
3236
{
3237
    $userId = api_get_user_id();
3238
3239
    if (!empty($session_id)) {
3240
        $session_id = (int) $session_id;
3241
    } else {
3242
        $session_id = api_get_session_id();
3243
    }
3244
3245
    // The student preview was on
3246
    if ($check_student_view && api_is_student_view_active()) {
3247
        return false;
3248
    }
3249
3250
    if (!empty($courseId)) {
3251
        $courseId = (int) $courseId;
3252
    } else {
3253
        $courseId = api_get_course_int_id();
3254
    }
3255
3256
    $session_table = Database::get_main_table(TABLE_MAIN_SESSION);
3257
    $session_rel_course_rel_user_table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3258
    $sessionIsCoach = [];
3259
3260
    if (!empty($courseId)) {
3261
        $sql = "SELECT DISTINCT s.id, name, access_start_date, access_end_date
3262
                FROM $session_table s
3263
                INNER JOIN $session_rel_course_rel_user_table session_rc_ru
3264
                ON session_rc_ru.session_id = s.id AND session_rc_ru.user_id = '".$userId."'
3265
                WHERE
3266
                    session_rc_ru.c_id = '$courseId' AND
3267
                    session_rc_ru.status = 2 AND
3268
                    session_rc_ru.session_id = '$session_id'";
3269
        $result = Database::query($sql);
3270
        $sessionIsCoach = Database::store_result($result);
3271
    }
3272
3273
    if (!empty($session_id)) {
3274
        $sql = "SELECT DISTINCT id, name, access_start_date, access_end_date
3275
                FROM $session_table
3276
                WHERE session.id_coach = $userId AND id = $session_id
3277
                ORDER BY access_start_date, access_end_date, name";
3278
        $result = Database::query($sql);
3279
        if (!empty($sessionIsCoach)) {
3280
            $sessionIsCoach = array_merge(
3281
                $sessionIsCoach,
3282
                Database::store_result($result)
3283
            );
3284
        } else {
3285
            $sessionIsCoach = Database::store_result($result);
3286
        }
3287
    }
3288
3289
    return count($sessionIsCoach) > 0;
3290
}
3291
3292
/**
3293
 * Checks whether the current user is a session administrator.
3294
 *
3295
 * @return bool True if current user is a course administrator
3296
 */
3297
function api_is_session_admin()
3298
{
3299
    $user = api_get_user_info();
3300
3301
    return isset($user['status']) && SESSIONADMIN == $user['status'];
3302
}
3303
3304
/**
3305
 * Checks whether the current user is a human resources manager.
3306
 *
3307
 * @return bool True if current user is a human resources manager
3308
 */
3309
function api_is_drh()
3310
{
3311
    $user = api_get_user_info();
3312
3313
    return isset($user['status']) && DRH == $user['status'];
3314
}
3315
3316
/**
3317
 * Checks whether the current user is a student.
3318
 *
3319
 * @return bool True if current user is a human resources manager
3320
 */
3321
function api_is_student()
3322
{
3323
    $user = api_get_user_info();
3324
3325
    return isset($user['status']) && STUDENT == $user['status'];
3326
}
3327
3328
/**
3329
 * Checks whether the current user has the status 'teacher'.
3330
 *
3331
 * @return bool True if current user is a human resources manager
3332
 */
3333
function api_is_teacher()
3334
{
3335
    $user = api_get_user_info();
3336
3337
    return isset($user['status']) && COURSEMANAGER == $user['status'];
3338
}
3339
3340
/**
3341
 * Checks whether the current user is a invited user.
3342
 *
3343
 * @return bool
3344
 */
3345
function api_is_invitee()
3346
{
3347
    $user = api_get_user_info();
3348
3349
    return isset($user['status']) && INVITEE == $user['status'];
3350
}
3351
3352
/**
3353
 * This function checks whether a session is assigned into a category.
3354
 *
3355
 * @param int       - session id
0 ignored issues
show
Documentation Bug introduced by
The doc comment - at position 0 could not be parsed: Unknown type name '-' at position 0 in -.
Loading history...
3356
 * @param string    - category name
3357
 *
3358
 * @return bool - true if is found, otherwise false
3359
 */
3360
function api_is_session_in_category($session_id, $category_name)
3361
{
3362
    $session_id = (int) $session_id;
3363
    $category_name = Database::escape_string($category_name);
3364
    $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
3365
    $tbl_session_category = Database::get_main_table(TABLE_MAIN_SESSION_CATEGORY);
3366
3367
    $sql = "SELECT 1
3368
            FROM $tbl_session
3369
            WHERE $session_id IN (
3370
                SELECT s.id FROM $tbl_session s, $tbl_session_category sc
3371
                WHERE
3372
                  s.session_category_id = sc.id AND
3373
                  sc.name LIKE '%$category_name'
3374
            )";
3375
    $rs = Database::query($sql);
3376
3377
    if (Database::num_rows($rs) > 0) {
3378
        return true;
3379
    } else {
3380
        return false;
3381
    }
3382
}
3383
3384
/**
3385
 * Displays the title of a tool.
3386
 * Normal use: parameter is a string:
3387
 * api_display_tool_title("My Tool").
3388
 *
3389
 * Optionally, there can be a subtitle below
3390
 * the normal title, and / or a supra title above the normal title.
3391
 *
3392
 * e.g. supra title:
3393
 * group
3394
 * GROUP PROPERTIES
3395
 *
3396
 * e.g. subtitle:
3397
 * AGENDA
3398
 * calender & events tool
3399
 *
3400
 * @author Hugues Peeters <[email protected]>
3401
 *
3402
 * @param mixed $title_element - it could either be a string or an array
3403
 *                             containing 'supraTitle', 'mainTitle',
3404
 *                             'subTitle'
3405
 */
3406
function api_display_tool_title($title_element)
3407
{
3408
    if (is_string($title_element)) {
3409
        $tit = $title_element;
3410
        unset($title_element);
3411
        $title_element = [];
3412
        $title_element['mainTitle'] = $tit;
3413
    }
3414
    echo '<h3>';
3415
    if (!empty($title_element['supraTitle'])) {
3416
        echo '<small>'.$title_element['supraTitle'].'</small><br />';
3417
    }
3418
    if (!empty($title_element['mainTitle'])) {
3419
        echo $title_element['mainTitle'];
3420
    }
3421
    if (!empty($title_element['subTitle'])) {
3422
        echo '<br /><small>'.$title_element['subTitle'].'</small>';
3423
    }
3424
    echo '</h3>';
3425
}
3426
3427
/**
3428
 * Displays options for switching between student view and course manager view.
3429
 *
3430
 * Changes in version 1.2 (Patrick Cool)
3431
 * Student view switch now behaves as a real switch. It maintains its current state until the state
3432
 * is changed explicitly
3433
 *
3434
 * Changes in version 1.1 (Patrick Cool)
3435
 * student view now works correctly in subfolders of the document tool
3436
 * student view works correctly in the new links tool
3437
 *
3438
 * Example code for using this in your tools:
3439
 * //if ($is_courseAdmin && api_get_setting('student_view_enabled') == 'true') {
3440
 * //   display_tool_view_option($isStudentView);
3441
 * //}
3442
 * //and in later sections, use api_is_allowed_to_edit()
3443
 *
3444
 * @author Roan Embrechts
3445
 * @author Patrick Cool
3446
 * @author Julio Montoya, changes added in Chamilo
3447
 *
3448
 * @version 1.2
3449
 *
3450
 * @todo rewrite code so it is easier to understand
3451
 */
3452
function api_display_tool_view_option()
3453
{
3454
    if ('true' != api_get_setting('student_view_enabled')) {
3455
        return '';
3456
    }
3457
3458
    $sourceurl = '';
3459
    $is_framed = false;
3460
    // Exceptions apply for all multi-frames pages
3461
    if (false !== strpos($_SERVER['REQUEST_URI'], 'chat/chat_banner.php')) {
3462
        // The chat is a multiframe bit that doesn't work too well with the student_view, so do not show the link
3463
        return '';
3464
    }
3465
3466
    // Uncomment to remove student view link from document view page
3467
    if (false !== strpos($_SERVER['REQUEST_URI'], 'lp/lp_header.php')) {
3468
        if (empty($_GET['lp_id'])) {
3469
            return '';
3470
        }
3471
        $sourceurl = substr($_SERVER['REQUEST_URI'], 0, strpos($_SERVER['REQUEST_URI'], '?'));
3472
        $sourceurl = str_replace(
3473
            'lp/lp_header.php',
3474
            'lp/lp_controller.php?'.api_get_cidreq().'&action=view&lp_id='.intval($_GET['lp_id']).'&isStudentView='.('studentview' == $_SESSION['studentview'] ? 'false' : 'true'),
3475
            $sourceurl
3476
        );
3477
        //showinframes doesn't handle student view anyway...
3478
        //return '';
3479
        $is_framed = true;
3480
    }
3481
3482
    // Check whether the $_SERVER['REQUEST_URI'] contains already url parameters (thus a questionmark)
3483
    if (!$is_framed) {
3484
        if (false === strpos($_SERVER['REQUEST_URI'], '?')) {
3485
            $sourceurl = api_get_self().'?'.api_get_cidreq();
3486
        } else {
3487
            $sourceurl = $_SERVER['REQUEST_URI'];
3488
        }
3489
    }
3490
3491
    $output_string = '';
3492
    if (!empty($_SESSION['studentview'])) {
3493
        if ('studentview' == $_SESSION['studentview']) {
3494
            // We have to remove the isStudentView=true from the $sourceurl
3495
            $sourceurl = str_replace('&isStudentView=true', '', $sourceurl);
3496
            $sourceurl = str_replace('&isStudentView=false', '', $sourceurl);
3497
            $output_string .= '<a class="btn btn-primary btn-sm" href="'.$sourceurl.'&isStudentView=false" target="_self">'.
3498
                Display::returnFontAwesomeIcon('eye').' '.get_lang('Switch to teacher view').'</a>';
3499
        } elseif ('teacherview' == $_SESSION['studentview']) {
3500
            // Switching to teacherview
3501
            $sourceurl = str_replace('&isStudentView=true', '', $sourceurl);
3502
            $sourceurl = str_replace('&isStudentView=false', '', $sourceurl);
3503
            $output_string .= '<a class="btn btn-default btn-sm" href="'.$sourceurl.'&isStudentView=true" target="_self">'.
3504
                Display::returnFontAwesomeIcon('eye').' '.get_lang('Switch to student view').'</a>';
3505
        }
3506
    } else {
3507
        $output_string .= '<a class="btn btn-default btn-sm" href="'.$sourceurl.'&isStudentView=true" target="_self">'.
3508
            Display::returnFontAwesomeIcon('eye').' '.get_lang('Switch to student view').'</a>';
3509
    }
3510
    $output_string = Security::remove_XSS($output_string);
3511
    $html = Display::tag('div', $output_string, ['class' => 'view-options']);
3512
3513
    return $html;
3514
}
3515
3516
// TODO: This is for the permission section.
3517
/**
3518
 * Function that removes the need to directly use is_courseAdmin global in
3519
 * tool scripts. It returns true or false depending on the user's rights in
3520
 * this particular course.
3521
 * Optionally checking for tutor and coach roles here allows us to use the
3522
 * student_view feature altogether with these roles as well.
3523
 *
3524
 * @param bool  Whether to check if the user has the tutor role
3525
 * @param bool  Whether to check if the user has the coach role
3526
 * @param bool  Whether to check if the user has the session coach role
3527
 * @param bool  check the student view or not
3528
 *
3529
 * @author Roan Embrechts
3530
 * @author Patrick Cool
3531
 * @author Julio Montoya
3532
 *
3533
 * @version 1.1, February 2004
3534
 *
3535
 * @return bool true: the user has the rights to edit, false: he does not
3536
 */
3537
function api_is_allowed_to_edit(
3538
    $tutor = false,
3539
    $coach = false,
3540
    $session_coach = false,
3541
    $check_student_view = true
3542
) {
3543
    $allowSessionAdminEdit = true === api_get_setting('session.session_admins_edit_courses_content');
3544
    // Admins can edit anything.
3545
    if (api_is_platform_admin($allowSessionAdminEdit)) {
3546
        //The student preview was on
3547
        if ($check_student_view && api_is_student_view_active()) {
3548
            return false;
3549
        }
3550
3551
        return true;
3552
    }
3553
3554
    $sessionId = api_get_session_id();
3555
3556
    if ($sessionId && api_get_configuration_value('session_courses_read_only_mode')) {
3557
        $efv = new ExtraFieldValue('course');
3558
        $lockExrafieldField = $efv->get_values_by_handler_and_field_variable(
3559
            api_get_course_int_id(),
3560
            'session_courses_read_only_mode'
3561
        );
3562
3563
        if (!empty($lockExrafieldField['value'])) {
3564
            return false;
3565
        }
3566
    }
3567
3568
    $is_allowed_coach_to_edit = api_is_coach(null, null, $check_student_view);
3569
    $session_visibility = api_get_session_visibility($sessionId);
3570
    $is_courseAdmin = api_is_course_admin();
3571
3572
    if (!$is_courseAdmin && $tutor) {
3573
        // If we also want to check if the user is a tutor...
3574
        $is_courseAdmin = $is_courseAdmin || api_is_course_tutor();
3575
    }
3576
3577
    if (!$is_courseAdmin && $coach) {
3578
        // If we also want to check if the user is a coach...';
3579
        // Check if session visibility is read only for coaches.
3580
        if (SESSION_VISIBLE_READ_ONLY == $session_visibility) {
3581
            $is_allowed_coach_to_edit = false;
3582
        }
3583
3584
        if ('true' === api_get_setting('allow_coach_to_edit_course_session')) {
3585
            // Check if coach is allowed to edit a course.
3586
            $is_courseAdmin = $is_courseAdmin || $is_allowed_coach_to_edit;
3587
        }
3588
    }
3589
3590
    if (!$is_courseAdmin && $session_coach) {
3591
        $is_courseAdmin = $is_courseAdmin || $is_allowed_coach_to_edit;
3592
    }
3593
3594
    // Check if the student_view is enabled, and if so, if it is activated.
3595
    if ('true' === api_get_setting('student_view_enabled')) {
3596
        $studentView = api_is_student_view_active();
3597
        if (!empty($sessionId)) {
3598
            // Check if session visibility is read only for coaches.
3599
            if (SESSION_VISIBLE_READ_ONLY == $session_visibility) {
3600
                $is_allowed_coach_to_edit = false;
3601
            }
3602
3603
            $is_allowed = false;
3604
            if ('true' === api_get_setting('allow_coach_to_edit_course_session')) {
3605
                // Check if coach is allowed to edit a course.
3606
                $is_allowed = $is_allowed_coach_to_edit;
3607
            }
3608
            if ($check_student_view) {
3609
                $is_allowed = $is_allowed && false === $studentView;
3610
            }
3611
        } else {
3612
            $is_allowed = $is_courseAdmin;
3613
            if ($check_student_view) {
3614
                $is_allowed = $is_courseAdmin && false === $studentView;
3615
            }
3616
        }
3617
3618
        return $is_allowed;
3619
    } else {
3620
        return $is_courseAdmin;
3621
    }
3622
}
3623
3624
/**
3625
 * Returns true if user is a course coach of at least one course in session.
3626
 *
3627
 * @param int $sessionId
3628
 *
3629
 * @return bool
3630
 */
3631
function api_is_coach_of_course_in_session($sessionId)
3632
{
3633
    if (api_is_platform_admin()) {
3634
        return true;
3635
    }
3636
3637
    $userId = api_get_user_id();
3638
    $courseList = UserManager::get_courses_list_by_session(
3639
        $userId,
3640
        $sessionId
3641
    );
3642
3643
    // Session visibility.
3644
    $visibility = api_get_session_visibility(
3645
        $sessionId,
3646
        null,
3647
        false
3648
    );
3649
3650
    if (SESSION_VISIBLE != $visibility && !empty($courseList)) {
3651
        // Course Coach session visibility.
3652
        $blockedCourseCount = 0;
3653
        $closedVisibilityList = [
3654
            COURSE_VISIBILITY_CLOSED,
3655
            COURSE_VISIBILITY_HIDDEN,
3656
        ];
3657
3658
        foreach ($courseList as $course) {
3659
            // Checking session visibility
3660
            $sessionCourseVisibility = api_get_session_visibility(
3661
                $sessionId,
3662
                $course['real_id']
3663
            );
3664
3665
            $courseIsVisible = !in_array(
3666
                $course['visibility'],
3667
                $closedVisibilityList
3668
            );
3669
            if (false === $courseIsVisible || SESSION_INVISIBLE == $sessionCourseVisibility) {
3670
                $blockedCourseCount++;
3671
            }
3672
        }
3673
3674
        // If all courses are blocked then no show in the list.
3675
        if ($blockedCourseCount === count($courseList)) {
3676
            $visibility = SESSION_INVISIBLE;
3677
        } else {
3678
            $visibility = SESSION_VISIBLE;
3679
        }
3680
    }
3681
3682
    switch ($visibility) {
3683
        case SESSION_VISIBLE_READ_ONLY:
3684
        case SESSION_VISIBLE:
3685
        case SESSION_AVAILABLE:
3686
            return true;
3687
            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...
3688
        case SESSION_INVISIBLE:
3689
            return false;
3690
    }
3691
3692
    return false;
3693
}
3694
3695
/**
3696
 * Checks if a student can edit contents in a session depending
3697
 * on the session visibility.
3698
 *
3699
 * @param bool $tutor Whether to check if the user has the tutor role
3700
 * @param bool $coach Whether to check if the user has the coach role
3701
 *
3702
 * @return bool true: the user has the rights to edit, false: he does not
3703
 */
3704
function api_is_allowed_to_session_edit($tutor = false, $coach = false)
3705
{
3706
    if (api_is_allowed_to_edit($tutor, $coach)) {
3707
        // If I'm a teacher, I will return true in order to not affect the normal behaviour of Chamilo tools.
3708
        return true;
3709
    } else {
3710
        $sessionId = api_get_session_id();
3711
3712
        if (0 == $sessionId) {
3713
            // I'm not in a session so i will return true to not affect the normal behaviour of Chamilo tools.
3714
            return true;
3715
        } else {
3716
            // I'm in a session and I'm a student
3717
            // Get the session visibility
3718
            $session_visibility = api_get_session_visibility($sessionId);
3719
            // if 5 the session is still available
3720
            switch ($session_visibility) {
3721
                case SESSION_VISIBLE_READ_ONLY: // 1
3722
                    return false;
3723
                case SESSION_VISIBLE:           // 2
3724
                    return true;
3725
                case SESSION_INVISIBLE:         // 3
3726
                    return false;
3727
                case SESSION_AVAILABLE:         //5
3728
                    return true;
3729
            }
3730
        }
3731
    }
3732
3733
    return false;
3734
}
3735
3736
/**
3737
 * Checks whether the user is allowed in a specific tool for a specific action.
3738
 *
3739
 * @param string $tool   the tool we are checking if the user has a certain permission
3740
 * @param string $action the action we are checking (add, edit, delete, move, visibility)
3741
 *
3742
 * @return bool
3743
 *
3744
 * @author Patrick Cool <[email protected]>, Ghent University
3745
 * @author Julio Montoya
3746
 *
3747
 * @version 1.0
3748
 */
3749
function api_is_allowed($tool, $action, $task_id = 0)
3750
{
3751
    $_user = api_get_user_info();
3752
    $_course = api_get_course_info();
3753
3754
    if (api_is_course_admin()) {
3755
        return true;
3756
    }
3757
3758
    if (is_array($_course) and count($_course) > 0) {
3759
        require_once api_get_path(SYS_CODE_PATH).'permissions/permissions_functions.inc.php';
3760
3761
        // Getting the permissions of this user.
3762
        if (0 == $task_id) {
3763
            $user_permissions = get_permissions('user', $_user['user_id']);
3764
            $_SESSION['total_permissions'][$_course['code']] = $user_permissions;
3765
        }
3766
3767
        // Getting the permissions of the task.
3768
        if (0 != $task_id) {
3769
            $task_permissions = get_permissions('task', $task_id);
3770
            /* !!! */$_SESSION['total_permissions'][$_course['code']] = $task_permissions;
3771
        }
3772
    }
3773
3774
    // If the permissions are limited, we have to map the extended ones to the limited ones.
3775
    if ('limited' == api_get_setting('permissions')) {
3776
        if ('Visibility' == $action) {
3777
            $action = 'Edit';
3778
        }
3779
        if ('Move' == $action) {
3780
            $action = 'Edit';
3781
        }
3782
    }
3783
3784
    // The session that contains all the permissions already exists for this course
3785
    // so there is no need to requery everything.
3786
    //my_print_r($_SESSION['total_permissions'][$_course['code']][$tool]);
3787
    if (is_array($_SESSION['total_permissions'][$_course['code']][$tool])) {
3788
        if (in_array($action, $_SESSION['total_permissions'][$_course['code']][$tool])) {
3789
            return true;
3790
        } else {
3791
            return false;
3792
        }
3793
    }
3794
3795
    return false;
3796
}
3797
3798
/**
3799
 * Tells whether this user is an anonymous user.
3800
 *
3801
 * @param int  $user_id  User ID (optional, will take session ID if not provided)
3802
 * @param bool $db_check Whether to check in the database (true) or simply in
3803
 *                       the session (false) to see if the current user is the anonymous user
3804
 *
3805
 * @return bool true if this user is anonymous, false otherwise
3806
 */
3807
function api_is_anonymous($user_id = null, $db_check = false)
3808
{
3809
    /*if ($db_check) {
3810
        if (!isset($user_id)) {
3811
            $user_id = api_get_user_id();
3812
        }
3813
3814
        $info = api_get_user_info($user_id);
3815
3816
        if (6 == $info['status'] || 0 == $user_id || empty($info)) {
3817
            return true;
3818
        }
3819
    }*/
3820
3821
    return !Container::getAuthorizationChecker()->isGranted('IS_AUTHENTICATED_FULLY');
3822
}
3823
3824
/**
3825
 * Displays message "You are not allowed here..." and exits the entire script.
3826
 *
3827
 * @param bool   $print_headers Whether or not to print headers (default = false -> does not print them)
3828
 * @param string $message
3829
 * @param int    $responseCode
3830
 */
3831
function api_not_allowed(
3832
    $print_headers = false,
3833
    $message = null,
3834
    $responseCode = 0
3835
) {
3836
    throw new Exception('You are not allowed');
3837
}
3838
3839
/**
3840
 * Gets a UNIX timestamp from a database (MySQL) datetime format string.
3841
 *
3842
 * @param $last_post_datetime standard output date in a sql query
3843
 *
3844
 * @return int timestamp
3845
 *
3846
 * @author Toon Van Hoecke <[email protected]>
3847
 *
3848
 * @version October 2003
3849
 * @desc convert sql date to unix timestamp
3850
 */
3851
function convert_sql_date($last_post_datetime)
3852
{
3853
    list($last_post_date, $last_post_time) = explode(' ', $last_post_datetime);
3854
    list($year, $month, $day) = explode('-', $last_post_date);
3855
    list($hour, $min, $sec) = explode(':', $last_post_time);
3856
3857
    return mktime((int) $hour, (int) $min, (int) $sec, (int) $month, (int) $day, (int) $year);
3858
}
3859
3860
/**
3861
 * Delete a row in the c_item_property table.
3862
 *
3863
 * @param array  $courseInfo
3864
 * @param string $tool
3865
 * @param int    $itemId
3866
 * @param int    $userId
3867
 * @param int    $groupId    group.iid
3868
 * @param int    $sessionId
3869
 *
3870
 * @return false|null
3871
 */
3872
function api_item_property_delete(
3873
    $courseInfo,
3874
    $tool,
3875
    $itemId,
3876
    $userId,
3877
    $groupId = 0,
3878
    $sessionId = 0
3879
) {
3880
    if (empty($courseInfo)) {
3881
        return false;
3882
    }
3883
3884
    $courseId = (int) $courseInfo['real_id'];
3885
3886
    if (empty($courseId) || empty($tool) || empty($itemId)) {
3887
        return false;
3888
    }
3889
3890
    $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
3891
    $tool = Database::escape_string($tool);
3892
    $itemId = intval($itemId);
3893
    $userId = intval($userId);
3894
    $groupId = intval($groupId);
3895
    $sessionId = intval($sessionId);
3896
3897
    $groupCondition = " AND to_group_id = $groupId ";
3898
    if (empty($groupId)) {
3899
        $groupCondition = " AND (to_group_id is NULL OR to_group_id = 0) ";
3900
    }
3901
3902
    $userCondition = " AND to_user_id = $userId ";
3903
    if (empty($userId)) {
3904
        $userCondition = " AND (to_user_id is NULL OR to_user_id = 0) ";
3905
    }
3906
    $sessionCondition = api_get_session_condition($sessionId, true, false, 'session_id');
3907
    $sql = "DELETE FROM $table
3908
            WHERE
3909
                c_id = $courseId AND
3910
                tool  = '$tool' AND
3911
                ref = $itemId
3912
                $sessionCondition
3913
                $userCondition
3914
                $groupCondition
3915
            ";
3916
3917
    Database::query($sql);
3918
}
3919
3920
/**
3921
 * Gets item property by tool.
3922
 *
3923
 * @param string    course code
3924
 * @param string    tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
3925
 * @param int       id of the item itself, linked to key of every tool ('id', ...), "*" = all items of the tool
3926
 * @param int    $session_id
3927
 * @param string $tool
3928
 * @param string $course_code
3929
 *
3930
 * @return array All fields from c_item_property (all rows found) or empty array
3931
 */
3932
function api_get_item_property_by_tool($tool, $course_code, $session_id = null)
3933
{
3934
    $course_info = api_get_course_info($course_code);
3935
    $tool = Database::escape_string($tool);
3936
3937
    // Definition of tables.
3938
    $item_property_table = Database::get_course_table(TABLE_ITEM_PROPERTY);
3939
    $session_id = (int) $session_id;
3940
    $session_condition = ' AND session_id = '.$session_id;
3941
    if (empty($session_id)) {
3942
        $session_condition = " AND (session_id = 0 OR session_id IS NULL) ";
3943
    }
3944
    $course_id = $course_info['real_id'];
3945
3946
    $sql = "SELECT * FROM $item_property_table
3947
            WHERE
3948
                c_id = $course_id AND
3949
                tool = '$tool'
3950
                $session_condition ";
3951
    $rs = Database::query($sql);
3952
    $list = [];
3953
    if (Database::num_rows($rs) > 0) {
3954
        while ($row = Database::fetch_array($rs, 'ASSOC')) {
3955
            $list[] = $row;
3956
        }
3957
    }
3958
3959
    return $list;
3960
}
3961
3962
/**
3963
 * Gets item property by tool and user.
3964
 *
3965
 * @param int $userId
3966
 * @param int $tool
3967
 * @param int $courseId
3968
 * @param int $session_id
3969
 *
3970
 * @return array
3971
 */
3972
function api_get_item_property_list_by_tool_by_user(
3973
    $userId,
3974
    $tool,
3975
    $courseId,
3976
    $session_id = 0
3977
) {
3978
    $userId = intval($userId);
3979
    $tool = Database::escape_string($tool);
3980
    $session_id = intval($session_id);
3981
    $courseId = intval($courseId);
3982
3983
    // Definition of tables.
3984
    $item_property_table = Database::get_course_table(TABLE_ITEM_PROPERTY);
3985
    $session_condition = ' AND session_id = '.$session_id;
3986
    if (empty($session_id)) {
3987
        $session_condition = " AND (session_id = 0 OR session_id IS NULL) ";
3988
    }
3989
    $sql = "SELECT * FROM $item_property_table
3990
            WHERE
3991
                insert_user_id = $userId AND
3992
                c_id = $courseId AND
3993
                tool = '$tool'
3994
                $session_condition ";
3995
3996
    $rs = Database::query($sql);
3997
    $list = [];
3998
    if (Database::num_rows($rs) > 0) {
3999
        while ($row = Database::fetch_array($rs, 'ASSOC')) {
4000
            $list[] = $row;
4001
        }
4002
    }
4003
4004
    return $list;
4005
}
4006
4007
/**
4008
 * Gets item property id from tool of a course.
4009
 *
4010
 * @param string $course_code course code
4011
 * @param string $tool        tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4012
 * @param int    $ref         id of the item itself, linked to key of every tool ('id', ...), "*" = all items of the tool
4013
 * @param int    $sessionId   Session ID (optional)
4014
 *
4015
 * @return int
4016
 */
4017
function api_get_item_property_id($course_code, $tool, $ref, $sessionId = 0)
4018
{
4019
    $course_info = api_get_course_info($course_code);
4020
    $tool = Database::escape_string($tool);
4021
    $ref = (int) $ref;
4022
4023
    // Definition of tables.
4024
    $tableItemProperty = Database::get_course_table(TABLE_ITEM_PROPERTY);
4025
    $course_id = $course_info['real_id'];
4026
    $sessionId = (int) $sessionId;
4027
    $sessionCondition = " AND session_id = $sessionId ";
4028
    if (empty($sessionId)) {
4029
        $sessionCondition = ' AND (session_id = 0 OR session_id IS NULL) ';
4030
    }
4031
    $sql = "SELECT id FROM $tableItemProperty
4032
            WHERE
4033
                c_id = $course_id AND
4034
                tool = '$tool' AND
4035
                ref = $ref
4036
                $sessionCondition";
4037
    $rs = Database::query($sql);
4038
    $item_property_id = '';
4039
    if (Database::num_rows($rs) > 0) {
4040
        $row = Database::fetch_array($rs);
4041
        $item_property_id = $row['id'];
4042
    }
4043
4044
    return $item_property_id;
4045
}
4046
4047
/**
4048
 * Inserts a record in the track_e_item_property table (No update).
4049
 *
4050
 * @param string $tool
4051
 * @param int    $ref
4052
 * @param string $title
4053
 * @param string $content
4054
 * @param int    $progress
4055
 *
4056
 * @return bool|int
4057
 */
4058
function api_track_item_property_update($tool, $ref, $title, $content, $progress)
4059
{
4060
    $tbl_stats_item_property = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ITEM_PROPERTY);
4061
    $course_id = api_get_course_int_id(); //numeric
4062
    $course_code = api_get_course_id(); //alphanumeric
4063
    $item_property_id = api_get_item_property_id($course_code, $tool, $ref);
4064
    if (!empty($item_property_id)) {
4065
        $sql = "INSERT IGNORE INTO $tbl_stats_item_property SET
4066
                course_id           = '$course_id',
4067
                item_property_id    = '$item_property_id',
4068
                title               = '".Database::escape_string($title)."',
4069
                content             = '".Database::escape_string($content)."',
4070
                progress            = '".intval($progress)."',
4071
                lastedit_date       = '".api_get_utc_datetime()."',
4072
                lastedit_user_id    = '".api_get_user_id()."',
4073
                session_id          = '".api_get_session_id()."'";
4074
        $result = Database::query($sql);
4075
        $affected_rows = Database::affected_rows($result);
4076
4077
        return $affected_rows;
4078
    }
4079
4080
    return false;
4081
}
4082
4083
/**
4084
 * @param string $tool
4085
 * @param int    $ref
4086
 *
4087
 * @return array|resource
4088
 */
4089
function api_get_track_item_property_history($tool, $ref)
4090
{
4091
    $tbl_stats_item_property = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ITEM_PROPERTY);
4092
    $course_id = api_get_course_int_id(); //numeric
4093
    $course_code = api_get_course_id(); //alphanumeric
4094
    $item_property_id = api_get_item_property_id($course_code, $tool, $ref);
4095
    $sql = "SELECT * FROM $tbl_stats_item_property
4096
            WHERE item_property_id = $item_property_id AND course_id = $course_id
4097
            ORDER BY lastedit_date DESC";
4098
    $result = Database::query($sql);
4099
    if (false === $result or null === $result) {
4100
        $result = [];
4101
    } else {
4102
        $result = Database::store_result($result, 'ASSOC');
4103
    }
4104
4105
    return $result;
4106
}
4107
4108
/**
4109
 * Gets item property data from tool of a course id.
4110
 *
4111
 * @param int    $course_id
4112
 * @param string $tool       tool name, linked to 'rubrique' of the course tool_list (Warning: language sensitive !!)
4113
 * @param int    $ref        id of the item itself, linked to key of every tool ('id', ...), "*" = all items of the tool
4114
 * @param int    $session_id
4115
 * @param int    $groupId
4116
 *
4117
 * @return array with all fields from c_item_property, empty array if not found or false if course could not be found
4118
 */
4119
function api_get_item_property_info($course_id, $tool, $ref, $session_id = 0, $groupId = 0)
4120
{
4121
    $courseInfo = api_get_course_info_by_id($course_id);
4122
4123
    if (empty($courseInfo)) {
4124
        return false;
4125
    }
4126
4127
    $tool = Database::escape_string($tool);
4128
    $course_id = $courseInfo['real_id'];
4129
    $ref = (int) $ref;
4130
    $session_id = (int) $session_id;
4131
4132
    $sessionCondition = " session_id = $session_id";
4133
    if (empty($session_id)) {
4134
        $sessionCondition = ' (session_id = 0 OR session_id IS NULL) ';
4135
    }
4136
4137
    // Definition of tables.
4138
    $table = Database::get_course_table(TABLE_ITEM_PROPERTY);
4139
4140
    $sql = "SELECT * FROM $table
4141
            WHERE
4142
                c_id = $course_id AND
4143
                tool = '$tool' AND
4144
                ref = $ref AND
4145
                $sessionCondition ";
4146
4147
    if (!empty($groupId)) {
4148
        $groupId = (int) $groupId;
4149
        $sql .= " AND to_group_id = $groupId ";
4150
    }
4151
4152
    $rs = Database::query($sql);
4153
    $row = [];
4154
    if (Database::num_rows($rs) > 0) {
4155
        $row = Database::fetch_array($rs, 'ASSOC');
4156
    }
4157
4158
    return $row;
4159
}
4160
4161
/**
4162
 * Displays a combo box so the user can select his/her preferred language.
4163
 *
4164
 * @param string The desired name= value for the select
4165
 * @param bool Whether we use the JQuery Chozen library or not
4166
 * (in some cases, like the indexing language picker, it can alter the presentation)
4167
 *
4168
 * @deprecated
4169
 *
4170
 * @return string
4171
 */
4172
function api_get_languages_combo($name = 'language')
4173
{
4174
    $ret = '';
4175
    $platformLanguage = api_get_setting('platformLanguage');
4176
4177
    // Retrieve a complete list of all the languages.
4178
    $language_list = api_get_languages();
4179
4180
    if (count($language_list) < 2) {
4181
        return $ret;
4182
    }
4183
4184
    // The the current language of the user so that his/her language occurs as selected in the dropdown menu.
4185
    if (isset($_SESSION['user_language_choice'])) {
4186
        $default = $_SESSION['user_language_choice'];
4187
    } else {
4188
        $default = $platformLanguage;
4189
    }
4190
4191
    $ret .= '<select name="'.$name.'" id="language_chosen" class="selectpicker show-tick form-control">';
4192
    foreach ($language_list as $key => $value) {
4193
        if ($key == $default) {
4194
            $selected = ' selected="selected"';
4195
        } else {
4196
            $selected = '';
4197
        }
4198
        $ret .= sprintf('<option value=%s" %s>%s</option>', $key, $selected, $value);
4199
    }
4200
    $ret .= '</select>';
4201
4202
    return $ret;
4203
}
4204
4205
/**
4206
 * Displays a form (drop down menu) so the user can select his/her preferred language.
4207
 * The form works with or without javascript.
4208
 *
4209
 * @param  bool Hide form if only one language available (defaults to false = show the box anyway)
4210
 * @param bool $showAsButton
4211
 *
4212
 * @return string|null Display the box directly
4213
 */
4214
function api_display_language_form($hide_if_no_choice = false, $showAsButton = false)
4215
{
4216
    // Retrieve a complete list of all the languages.
4217
    $language_list = api_get_languages();
4218
    if (count($language_list['name']) <= 1 && $hide_if_no_choice) {
4219
        return; //don't show any form
4220
    }
4221
4222
    // The the current language of the user so that his/her language occurs as selected in the dropdown menu.
4223
    if (isset($_SESSION['user_language_choice'])) {
4224
        $user_selected_language = $_SESSION['user_language_choice'];
4225
    }
4226
    if (empty($user_selected_language)) {
4227
        $user_selected_language = api_get_setting('platformLanguage');
4228
    }
4229
4230
    $currentLanguageId = api_get_language_id($user_selected_language);
4231
    $currentLanguageInfo = api_get_language_info($currentLanguageId);
4232
    $countryCode = languageToCountryIsoCode($currentLanguageInfo['isocode']);
4233
    $url = api_get_self();
4234
    if ($showAsButton) {
4235
        $html = '<div class="btn-group">
4236
              <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
4237
                <span class="flag-icon flag-icon-'.$countryCode.'"></span>
4238
                '.$currentLanguageInfo['original_name'].'
4239
                <span class="caret">
4240
                </span>
4241
              </button>';
4242
    } else {
4243
        $html = '
4244
            <a href="'.$url.'" class="dropdown-toggle" data-toggle="dropdown" role="button">
4245
                <span class="flag-icon flag-icon-'.$countryCode.'"></span>
4246
                '.$currentLanguageInfo['original_name'].'
4247
                <span class="caret"></span>
4248
            </a>
4249
            ';
4250
    }
4251
4252
    $html .= '<ul class="dropdown-menu" role="menu">';
4253
    foreach ($language_list['all'] as $key => $data) {
4254
        $urlLink = $url.'?language='.$data['english_name'];
4255
        $html .= '<li><a href="'.$urlLink.'"><span class="flag-icon flag-icon-'.languageToCountryIsoCode($data['isocode']).'"></span> '.$data['original_name'].'</a></li>';
4256
    }
4257
    $html .= '</ul>';
4258
4259
    if ($showAsButton) {
4260
        $html .= '</div>';
4261
    }
4262
4263
    return $html;
4264
}
4265
4266
/**
4267
 * @param string $languageIsoCode
4268
 *
4269
 * @return string
4270
 */
4271
function languageToCountryIsoCode($languageIsoCode)
4272
{
4273
    $allow = api_get_configuration_value('language_flags_by_country');
4274
4275
    // @todo save in DB
4276
    switch ($languageIsoCode) {
4277
        case 'ar':
4278
            $country = 'ae';
4279
            break;
4280
        case 'bs':
4281
            $country = 'ba';
4282
            break;
4283
        case 'ca':
4284
            $country = 'es';
4285
            if ($allow) {
4286
                $country = 'catalan';
4287
            }
4288
            break;
4289
        case 'cs':
4290
            $country = 'cz';
4291
            break;
4292
        case 'da':
4293
            $country = 'dk';
4294
            break;
4295
        case 'el':
4296
            $country = 'ae';
4297
            break;
4298
        case 'en':
4299
            $country = 'gb';
4300
            break;
4301
        case 'eu': // Euskera
4302
            $country = 'es';
4303
            if ($allow) {
4304
                $country = 'basque';
4305
            }
4306
            break;
4307
        case 'gl': // galego
4308
            $country = 'es';
4309
            if ($allow) {
4310
                $country = 'galician';
4311
            }
4312
            break;
4313
        case 'he':
4314
            $country = 'il';
4315
            break;
4316
        case 'ja':
4317
            $country = 'jp';
4318
            break;
4319
        case 'ka':
4320
            $country = 'ge';
4321
            break;
4322
        case 'ko':
4323
            $country = 'kr';
4324
            break;
4325
        case 'ms':
4326
            $country = 'my';
4327
            break;
4328
        case 'pt-BR':
4329
            $country = 'br';
4330
            break;
4331
        case 'qu':
4332
            $country = 'pe';
4333
            break;
4334
        case 'sl':
4335
            $country = 'si';
4336
            break;
4337
        case 'sv':
4338
            $country = 'se';
4339
            break;
4340
        case 'uk': // Ukraine
4341
            $country = 'ua';
4342
            break;
4343
        case 'zh-TW':
4344
        case 'zh':
4345
            $country = 'cn';
4346
            break;
4347
        default:
4348
            $country = $languageIsoCode;
4349
            break;
4350
    }
4351
    $country = strtolower($country);
4352
4353
    return $country;
4354
}
4355
4356
/**
4357
 * Returns a list of all the languages that are made available by the admin.
4358
 *
4359
 * @return array An array with all languages. Structure of the array is
4360
 *               array['name'] = An array with the name of every language
4361
 *               array['folder'] = An array with the corresponding names of the language-folders in the filesystem
4362
 */
4363
function api_get_languages()
4364
{
4365
    $table = Database::get_main_table(TABLE_MAIN_LANGUAGE);
4366
    $sql = "SELECT * FROM $table WHERE available='1'
4367
            ORDER BY original_name ASC";
4368
    $result = Database::query($sql);
4369
    $languages = [];
4370
    while ($row = Database::fetch_array($result, 'ASSOC')) {
4371
        $languages[$row['isocode']] = $row['original_name'];
4372
    }
4373
4374
    return $languages;
4375
}
4376
4377
/**
4378
 * Returns a list of all the languages that are made available by the admin.
4379
 *
4380
 * @return array
4381
 */
4382
function api_get_languages_to_array()
4383
{
4384
    $tbl_language = Database::get_main_table(TABLE_MAIN_LANGUAGE);
4385
    $sql = "SELECT * FROM $tbl_language WHERE available='1' ORDER BY original_name ASC";
4386
    $result = Database::query($sql);
4387
    $languages = [];
4388
    while ($row = Database::fetch_array($result)) {
4389
        $languages[$row['dokeos_folder']] = $row['original_name'];
4390
    }
4391
4392
    return $languages;
4393
}
4394
4395
/**
4396
 * Returns the id (the database id) of a language.
4397
 *
4398
 * @param   string  language name (the corresponding name of the language-folder in the filesystem)
4399
 *
4400
 * @return int id of the language
4401
 */
4402
function api_get_language_id($language)
4403
{
4404
    $tbl_language = Database::get_main_table(TABLE_MAIN_LANGUAGE);
4405
    if (empty($language)) {
4406
        return null;
4407
    }
4408
    $language = Database::escape_string($language);
4409
    $sql = "SELECT id FROM $tbl_language
4410
            WHERE dokeos_folder = '$language' LIMIT 1";
4411
    $result = Database::query($sql);
4412
    $row = Database::fetch_array($result);
4413
4414
    return $row['id'];
4415
}
4416
4417
/**
4418
 * Get the language information by its id.
4419
 *
4420
 * @param int $languageId
4421
 *
4422
 * @throws Exception
4423
 *
4424
 * @return array
4425
 */
4426
function api_get_language_info($languageId)
4427
{
4428
    if (empty($languageId)) {
4429
        return [];
4430
    }
4431
4432
    $language = Database::getManager()
4433
        ->find('ChamiloCoreBundle:Language', $languageId);
4434
4435
    if (!$language) {
4436
        return [];
4437
    }
4438
4439
    return [
4440
        'id' => $language->getId(),
4441
        'original_name' => $language->getOriginalName(),
4442
        'english_name' => $language->getEnglishName(),
4443
        'isocode' => $language->getIsocode(),
4444
        'dokeos_folder' => $language->getDokeosFolder(),
4445
        'available' => $language->getAvailable(),
4446
        'parent_id' => $language->getParent() ? $language->getParent()->getId() : null,
4447
    ];
4448
}
4449
4450
/**
4451
 * @param string $code
4452
 *
4453
 * @return \Chamilo\CoreBundle\Entity\Language
4454
 */
4455
function api_get_language_from_iso($code)
4456
{
4457
    $em = Database::getManager();
4458
4459
    return $em->getRepository('ChamiloCoreBundle:Language')->findOneBy(['isocode' => $code]);
4460
}
4461
4462
/**
4463
 * Returns the name of the visual (CSS) theme to be applied on the current page.
4464
 * The returned name depends on the platform, course or user -wide settings.
4465
 *
4466
 * @return string The visual theme's name, it is the name of a folder inside web/css/themes
4467
 */
4468
function api_get_visual_theme()
4469
{
4470
    static $visual_theme;
4471
    if (!isset($visual_theme)) {
4472
        // Get style directly from DB
4473
        /*$styleFromDatabase = api_get_settings_params_simple(
4474
            [
4475
                'variable = ? AND access_url = ?' => [
4476
                    'stylesheets',
4477
                    api_get_current_access_url_id(),
4478
                ],
4479
            ]
4480
        );
4481
4482
        if ($styleFromDatabase) {
4483
            $platform_theme = $styleFromDatabase['selected_value'];
4484
        } else {
4485
            $platform_theme = api_get_setting('stylesheets');
4486
        }*/
4487
        $platform_theme = api_get_setting('stylesheets');
4488
4489
        // Platform's theme.
4490
        $visual_theme = $platform_theme;
4491
        if ('true' == api_get_setting('user_selected_theme')) {
4492
            $user_info = api_get_user_info();
4493
            if (isset($user_info['theme'])) {
4494
                $user_theme = $user_info['theme'];
4495
4496
                if (!empty($user_theme)) {
4497
                    $visual_theme = $user_theme;
4498
                    // User's theme.
4499
                }
4500
            }
4501
        }
4502
4503
        $course_id = api_get_course_id();
4504
        if (!empty($course_id)) {
4505
            if ('true' == api_get_setting('allow_course_theme')) {
4506
                $course_theme = api_get_course_setting('course_theme', $course_id);
4507
4508
                if (!empty($course_theme) && -1 != $course_theme) {
4509
                    if (!empty($course_theme)) {
4510
                        // Course's theme.
4511
                        $visual_theme = $course_theme;
4512
                    }
4513
                }
4514
4515
                $allow_lp_theme = api_get_course_setting('allow_learning_path_theme');
4516
                if (1 == $allow_lp_theme) {
4517
                    global $lp_theme_css, $lp_theme_config;
4518
                    // These variables come from the file lp_controller.php.
4519
                    if (!$lp_theme_config) {
4520
                        if (!empty($lp_theme_css)) {
4521
                            // LP's theme.
4522
                            $visual_theme = $lp_theme_css;
4523
                        }
4524
                    }
4525
                }
4526
            }
4527
        }
4528
4529
        if (empty($visual_theme)) {
4530
            $visual_theme = 'chamilo';
4531
        }
4532
4533
        global $lp_theme_log;
4534
        if ($lp_theme_log) {
4535
            $visual_theme = $platform_theme;
4536
        }
4537
    }
4538
4539
    return $visual_theme;
4540
}
4541
4542
/**
4543
 * Returns a list of CSS themes currently available in the CSS folder
4544
 * The folder must have a default.css file.
4545
 *
4546
 * @param bool $getOnlyThemeFromVirtualInstance Used by the vchamilo plugin
4547
 *
4548
 * @return array list of themes directories from the css folder
4549
 *               Note: Directory names (names of themes) in the file system should contain ASCII-characters only
4550
 */
4551
function api_get_themes($getOnlyThemeFromVirtualInstance = false)
4552
{
4553
    // This configuration value is set by the vchamilo plugin
4554
    $virtualTheme = api_get_configuration_value('virtual_css_theme_folder');
4555
4556
    $readCssFolder = function ($dir) use ($virtualTheme) {
4557
        $finder = new Finder();
4558
        $themes = $finder->directories()->in($dir)->depth(0)->sortByName();
4559
        $list = [];
4560
        /** @var Symfony\Component\Finder\SplFileInfo $theme */
4561
        foreach ($themes as $theme) {
4562
            $folder = $theme->getFilename();
4563
            // A theme folder is consider if there's a default.css file
4564
            if (!file_exists($theme->getPathname().'/default.css')) {
4565
                continue;
4566
            }
4567
            $name = ucwords(str_replace('_', ' ', $folder));
4568
            if ($folder == $virtualTheme) {
4569
                continue;
4570
            }
4571
            $list[$folder] = $name;
4572
        }
4573
4574
        return $list;
4575
    };
4576
4577
    $dir = api_get_path(SYS_CSS_PATH).'themes/';
4578
    $list = $readCssFolder($dir);
4579
4580
    if (!empty($virtualTheme)) {
4581
        $newList = $readCssFolder($dir.'/'.$virtualTheme);
4582
        if ($getOnlyThemeFromVirtualInstance) {
4583
            return $newList;
4584
        }
4585
        $list = $list + $newList;
4586
        asort($list);
4587
    }
4588
4589
    return $list;
4590
}
4591
4592
/**
4593
 * Find the largest sort value in a given user_course_category
4594
 * This function is used when we are moving a course to a different category
4595
 * and also when a user subscribes to courses (the new course is added at the end of the main category.
4596
 *
4597
 * @author Patrick Cool <[email protected]>, Ghent University
4598
 *
4599
 * @param int $user_course_category the id of the user_course_category
4600
 * @param int $user_id
4601
 *
4602
 * @return int the value of the highest sort of the user_course_category
4603
 */
4604
function api_max_sort_value($user_course_category, $user_id)
4605
{
4606
    $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4607
    $sql = "SELECT max(sort) as max_sort FROM $tbl_course_user
4608
            WHERE
4609
                user_id='".intval($user_id)."' AND
4610
                relation_type<>".COURSE_RELATION_TYPE_RRHH." AND
4611
                user_course_cat='".intval($user_course_category)."'";
4612
    $result_max = Database::query($sql);
4613
    if (1 == Database::num_rows($result_max)) {
4614
        $row_max = Database::fetch_array($result_max);
4615
4616
        return $row_max['max_sort'];
4617
    }
4618
4619
    return 0;
4620
}
4621
4622
/**
4623
 * Transforms a number of seconds in hh:mm:ss format.
4624
 *
4625
 * @author Julian Prud'homme
4626
 *
4627
 * @param int    $seconds      number of seconds
4628
 * @param string $space
4629
 * @param bool   $showSeconds
4630
 * @param bool   $roundMinutes
4631
 *
4632
 * @return string the formatted time
4633
 */
4634
function api_time_to_hms($seconds, $space = ':', $showSeconds = true, $roundMinutes = false)
4635
{
4636
    // $seconds = -1 means that we have wrong data in the db.
4637
    if (-1 == $seconds) {
4638
        return
4639
            get_lang('Unknown').
4640
            Display::return_icon(
4641
                'info2.gif',
4642
                get_lang('The datas about this user were registered when the calculation of time spent on the platform wasn\'t possible.'),
4643
                ['align' => 'absmiddle', 'hspace' => '3px']
4644
            );
4645
    }
4646
4647
    // How many hours ?
4648
    $hours = floor($seconds / 3600);
4649
4650
    // How many minutes ?
4651
    $min = floor(($seconds - ($hours * 3600)) / 60);
4652
4653
    if ($roundMinutes) {
4654
        if ($min >= 45) {
4655
            $min = 45;
4656
        }
4657
4658
        if ($min >= 30 && $min <= 44) {
4659
            $min = 30;
4660
        }
4661
4662
        if ($min >= 15 && $min <= 29) {
4663
            $min = 15;
4664
        }
4665
4666
        if ($min >= 0 && $min <= 14) {
4667
            $min = 0;
4668
        }
4669
    }
4670
4671
    // How many seconds
4672
    $sec = floor($seconds - ($hours * 3600) - ($min * 60));
4673
4674
    if ($hours < 10) {
4675
        $hours = "0$hours";
4676
    }
4677
4678
    if ($sec < 10) {
4679
        $sec = "0$sec";
4680
    }
4681
4682
    if ($min < 10) {
4683
        $min = "0$min";
4684
    }
4685
4686
    $seconds = '';
4687
    if ($showSeconds) {
4688
        $seconds = $space.$sec;
4689
    }
4690
4691
    return $hours.$space.$min.$seconds;
4692
}
4693
4694
/* FILE SYSTEM RELATED FUNCTIONS */
4695
4696
/**
4697
 * Returns the permissions to be assigned to every newly created directory by the web-server.
4698
 * The return value is based on the platform administrator's setting
4699
 * "Administration > Configuration settings > Security > Permissions for new directories".
4700
 *
4701
 * @return int returns the permissions in the format "Owner-Group-Others, Read-Write-Execute", as an integer value
4702
 */
4703
function api_get_permissions_for_new_directories()
4704
{
4705
    static $permissions;
4706
    if (!isset($permissions)) {
4707
        $permissions = trim(api_get_setting('permissions_for_new_directories'));
4708
        // The default value 0777 is according to that in the platform administration panel after fresh system installation.
4709
        $permissions = octdec(!empty($permissions) ? $permissions : '0777');
4710
    }
4711
4712
    return $permissions;
4713
}
4714
4715
/**
4716
 * Returns the permissions to be assigned to every newly created directory by the web-server.
4717
 * The return value is based on the platform administrator's setting
4718
 * "Administration > Configuration settings > Security > Permissions for new files".
4719
 *
4720
 * @return int returns the permissions in the format
4721
 *             "Owner-Group-Others, Read-Write-Execute", as an integer value
4722
 */
4723
function api_get_permissions_for_new_files()
4724
{
4725
    static $permissions;
4726
    if (!isset($permissions)) {
4727
        $permissions = trim(api_get_setting('permissions_for_new_files'));
4728
        // The default value 0666 is according to that in the platform
4729
        // administration panel after fresh system installation.
4730
        $permissions = octdec(!empty($permissions) ? $permissions : '0666');
4731
    }
4732
4733
    return $permissions;
4734
}
4735
4736
/**
4737
 * Deletes a file, or a folder and its contents.
4738
 *
4739
 * @author      Aidan Lister <[email protected]>
4740
 *
4741
 * @version     1.0.3
4742
 *
4743
 * @param string $dirname Directory to delete
4744
 * @param       bool     Deletes only the content or not
4745
 * @param bool $strict if one folder/file fails stop the loop
4746
 *
4747
 * @return bool Returns TRUE on success, FALSE on failure
4748
 *
4749
 * @see http://aidanlister.com/2004/04/recursively-deleting-a-folder-in-php/
4750
 *
4751
 * @author      Yannick Warnier, adaptation for the Chamilo LMS, April, 2008
4752
 * @author      Ivan Tcholakov, a sanity check about Directory class creation has been added, September, 2009
4753
 */
4754
function rmdirr($dirname, $delete_only_content_in_folder = false, $strict = false)
4755
{
4756
    $res = true;
4757
    // A sanity check.
4758
    if (!file_exists($dirname)) {
4759
        return false;
4760
    }
4761
    $php_errormsg = '';
4762
    // Simple delete for a file.
4763
    if (is_file($dirname) || is_link($dirname)) {
4764
        $res = unlink($dirname);
4765
        if (false === $res) {
4766
            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);
4767
        }
4768
4769
        return $res;
4770
    }
4771
4772
    // Loop through the folder.
4773
    $dir = dir($dirname);
4774
    // A sanity check.
4775
    $is_object_dir = is_object($dir);
4776
    if ($is_object_dir) {
4777
        while (false !== $entry = $dir->read()) {
4778
            // Skip pointers.
4779
            if ('.' == $entry || '..' == $entry) {
4780
                continue;
4781
            }
4782
4783
            // Recurse.
4784
            if ($strict) {
4785
                $result = rmdirr("$dirname/$entry");
4786
                if (false == $result) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

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

Loading history...
4787
                    $res = false;
4788
                    break;
4789
                }
4790
            } else {
4791
                rmdirr("$dirname/$entry");
4792
            }
4793
        }
4794
    }
4795
4796
    // Clean up.
4797
    if ($is_object_dir) {
4798
        $dir->close();
4799
    }
4800
4801
    if (false == $delete_only_content_in_folder) {
4802
        $res = rmdir($dirname);
4803
        if (false === $res) {
4804
            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);
4805
        }
4806
    }
4807
4808
    return $res;
4809
}
4810
4811
// TODO: This function is to be simplified. File access modes to be implemented.
4812
/**
4813
 * function adapted from a php.net comment
4814
 * copy recursively a folder.
4815
 *
4816
 * @param the source folder
4817
 * @param the dest folder
4818
 * @param an array of excluded file_name (without extension)
4819
 * @param copied_files the returned array of copied files
4820
 * @param string $source
4821
 * @param string $dest
4822
 */
4823
function copyr($source, $dest, $exclude = [], $copied_files = [])
4824
{
4825
    if (empty($dest)) {
4826
        return false;
4827
    }
4828
    // Simple copy for a file
4829
    if (is_file($source)) {
4830
        $path_info = pathinfo($source);
4831
        if (!in_array($path_info['filename'], $exclude)) {
4832
            copy($source, $dest);
4833
        }
4834
4835
        return true;
4836
    } elseif (!is_dir($source)) {
4837
        //then source is not a dir nor a file, return
4838
        return false;
4839
    }
4840
4841
    // Make destination directory.
4842
    if (!is_dir($dest)) {
4843
        mkdir($dest, api_get_permissions_for_new_directories());
4844
    }
4845
4846
    // Loop through the folder.
4847
    $dir = dir($source);
4848
    while (false !== $entry = $dir->read()) {
4849
        // Skip pointers
4850
        if ('.' == $entry || '..' == $entry) {
4851
            continue;
4852
        }
4853
4854
        // Deep copy directories.
4855
        if ($dest !== "$source/$entry") {
4856
            $files = copyr("$source/$entry", "$dest/$entry", $exclude, $copied_files);
4857
        }
4858
    }
4859
    // Clean up.
4860
    $dir->close();
4861
4862
    return true;
4863
}
4864
4865
/**
4866
 * @todo: Using DIRECTORY_SEPARATOR is not recommended, this is an obsolete approach.
4867
 * Documentation header to be added here.
4868
 *
4869
 * @param string $pathname
4870
 * @param string $base_path_document
4871
 * @param int    $session_id
4872
 *
4873
 * @return mixed True if directory already exists, false if a file already exists at
4874
 *               the destination and null if everything goes according to plan
4875
 */
4876
function copy_folder_course_session(
4877
    $pathname,
4878
    $base_path_document,
4879
    $session_id,
4880
    $course_info,
4881
    $document,
4882
    $source_course_id
4883
) {
4884
    $table = Database::get_course_table(TABLE_DOCUMENT);
4885
    $session_id = intval($session_id);
4886
    $source_course_id = intval($source_course_id);
4887
4888
    // Check whether directory already exists.
4889
    if (is_dir($pathname) || empty($pathname)) {
4890
        return true;
4891
    }
4892
4893
    // Ensure that a file with the same name does not already exist.
4894
    if (is_file($pathname)) {
4895
        trigger_error('copy_folder_course_session(): File exists', E_USER_WARNING);
4896
4897
        return false;
4898
    }
4899
4900
    $course_id = $course_info['real_id'];
4901
    $folders = explode(DIRECTORY_SEPARATOR, str_replace($base_path_document.DIRECTORY_SEPARATOR, '', $pathname));
4902
    $new_pathname = $base_path_document;
4903
    $path = '';
4904
4905
    foreach ($folders as $folder) {
4906
        $new_pathname .= DIRECTORY_SEPARATOR.$folder;
4907
        $path .= DIRECTORY_SEPARATOR.$folder;
4908
4909
        if (!file_exists($new_pathname)) {
4910
            $path = Database::escape_string($path);
4911
4912
            $sql = "SELECT * FROM $table
4913
                    WHERE
4914
                        c_id = $source_course_id AND
4915
                        path = '$path' AND
4916
                        filetype = 'folder' AND
4917
                        session_id = '$session_id'";
4918
            $rs1 = Database::query($sql);
4919
            $num_rows = Database::num_rows($rs1);
4920
4921
            if (0 == $num_rows) {
4922
                mkdir($new_pathname, api_get_permissions_for_new_directories());
4923
4924
                // Insert new folder with destination session_id.
4925
                $params = [
4926
                    'c_id' => $course_id,
4927
                    'path' => $path,
4928
                    'comment' => $document->comment,
4929
                    'title' => basename($new_pathname),
4930
                    'filetype' => 'folder',
4931
                    'size' => '0',
4932
                    'session_id' => $session_id,
4933
                ];
4934
                $document_id = Database::insert($table, $params);
4935
                if ($document_id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $document_id of type false|integer is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
4936
                    $sql = "UPDATE $table SET id = iid WHERE iid = $document_id";
4937
                    Database::query($sql);
4938
4939
                    api_item_property_update(
0 ignored issues
show
Bug introduced by
The function api_item_property_update was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

4939
                    /** @scrutinizer ignore-call */ 
4940
                    api_item_property_update(
Loading history...
4940
                        $course_info,
4941
                        TOOL_DOCUMENT,
4942
                        $document_id,
4943
                        'FolderCreated',
4944
                        api_get_user_id(),
4945
                        0,
4946
                        0,
4947
                        null,
4948
                        null,
4949
                        $session_id
4950
                    );
4951
                }
4952
            }
4953
        }
4954
    } // en foreach
4955
}
4956
4957
// TODO: chmodr() is a better name. Some corrections are needed. Documentation header to be added here.
4958
/**
4959
 * @param string $path
4960
 */
4961
function api_chmod_R($path, $filemode)
4962
{
4963
    if (!is_dir($path)) {
4964
        return chmod($path, $filemode);
4965
    }
4966
4967
    $handler = opendir($path);
4968
    while ($file = readdir($handler)) {
4969
        if ('.' != $file && '..' != $file) {
4970
            $fullpath = "$path/$file";
4971
            if (!is_dir($fullpath)) {
4972
                if (!chmod($fullpath, $filemode)) {
4973
                    return false;
4974
                }
4975
            } else {
4976
                if (!api_chmod_R($fullpath, $filemode)) {
4977
                    return false;
4978
                }
4979
            }
4980
        }
4981
    }
4982
4983
    closedir($handler);
4984
4985
    return chmod($path, $filemode);
4986
}
4987
4988
// TODO: Where the following function has been copy/pased from? There is no information about author and license. Style, coding conventions...
4989
/**
4990
 * Parse info file format. (e.g: file.info).
4991
 *
4992
 * Files should use an ini-like format to specify values.
4993
 * White-space generally doesn't matter, except inside values.
4994
 * e.g.
4995
 *
4996
 * @verbatim
4997
 *   key = value
4998
 *   key = "value"
4999
 *   key = 'value'
5000
 *   key = "multi-line
5001
 *
5002
 *   value"
5003
 *   key = 'multi-line
5004
 *
5005
 *   value'
5006
 *   key
5007
 *   =
5008
 *   'value'
5009
 * @endverbatim
5010
 *
5011
 * Arrays are created using a GET-like syntax:
5012
 *
5013
 * @verbatim
5014
 *   key[] = "numeric array"
5015
 *   key[index] = "associative array"
5016
 *   key[index][] = "nested numeric array"
5017
 *   key[index][index] = "nested associative array"
5018
 * @endverbatim
5019
 *
5020
 * PHP constants are substituted in, but only when used as the entire value:
5021
 *
5022
 * Comments should start with a semi-colon at the beginning of a line.
5023
 *
5024
 * This function is NOT for placing arbitrary module-specific settings. Use
5025
 * variable_get() and variable_set() for that.
5026
 *
5027
 * Information stored in the module.info file:
5028
 * - name: The real name of the module for display purposes.
5029
 * - description: A brief description of the module.
5030
 * - dependencies: An array of shortnames of other modules this module depends on.
5031
 * - package: The name of the package of modules this module belongs to.
5032
 *
5033
 * Example of .info file:
5034
 * <code>
5035
 * @verbatim
5036
 *   name = Forum
5037
 *   description = Enables threaded discussions about general topics.
5038
 *   dependencies[] = taxonomy
5039
 *   dependencies[] = comment
5040
 *   package = Core - optional
5041
 *   version = VERSION
5042
 * @endverbatim
5043
 * </code>
5044
 *
5045
 * @param string $filename
5046
 *                         The file we are parsing. Accepts file with relative or absolute path.
5047
 *
5048
 * @return
5049
 *   The info array
5050
 */
5051
function api_parse_info_file($filename)
5052
{
5053
    $info = [];
5054
5055
    if (!file_exists($filename)) {
5056
        return $info;
5057
    }
5058
5059
    $data = file_get_contents($filename);
5060
    if (preg_match_all('
5061
        @^\s*                           # Start at the beginning of a line, ignoring leading whitespace
5062
        ((?:
5063
          [^=;\[\]]|                    # Key names cannot contain equal signs, semi-colons or square brackets,
5064
          \[[^\[\]]*\]                  # unless they are balanced and not nested
5065
        )+?)
5066
        \s*=\s*                         # Key/value pairs are separated by equal signs (ignoring white-space)
5067
        (?:
5068
          ("(?:[^"]|(?<=\\\\)")*")|     # Double-quoted string, which may contain slash-escaped quotes/slashes
5069
          (\'(?:[^\']|(?<=\\\\)\')*\')| # Single-quoted string, which may contain slash-escaped quotes/slashes
5070
          ([^\r\n]*?)                   # Non-quoted string
5071
        )\s*$                           # Stop at the next end of a line, ignoring trailing whitespace
5072
        @msx', $data, $matches, PREG_SET_ORDER)) {
5073
        $key = $value1 = $value2 = $value3 = '';
5074
        foreach ($matches as $match) {
5075
            // Fetch the key and value string.
5076
            $i = 0;
5077
            foreach (['key', 'value1', 'value2', 'value3'] as $var) {
5078
                $$var = isset($match[++$i]) ? $match[$i] : '';
5079
            }
5080
            $value = stripslashes(substr($value1, 1, -1)).stripslashes(substr($value2, 1, -1)).$value3;
5081
5082
            // Parse array syntax.
5083
            $keys = preg_split('/\]?\[/', rtrim($key, ']'));
5084
            $last = array_pop($keys);
5085
            $parent = &$info;
5086
5087
            // Create nested arrays.
5088
            foreach ($keys as $key) {
5089
                if ('' == $key) {
5090
                    $key = count($parent);
5091
                }
5092
                if (!isset($parent[$key]) || !is_array($parent[$key])) {
5093
                    $parent[$key] = [];
5094
                }
5095
                $parent = &$parent[$key];
5096
            }
5097
5098
            // Handle PHP constants.
5099
            if (defined($value)) {
5100
                $value = constant($value);
5101
            }
5102
5103
            // Insert actual value.
5104
            if ('' == $last) {
5105
                $last = count($parent);
5106
            }
5107
            $parent[$last] = $value;
5108
        }
5109
    }
5110
5111
    return $info;
5112
}
5113
5114
/**
5115
 * Gets Chamilo version from the configuration files.
5116
 *
5117
 * @return string A string of type "1.8.4", or an empty string if the version could not be found
5118
 */
5119
function api_get_version()
5120
{
5121
    return (string) api_get_configuration_value('system_version');
5122
}
5123
5124
/**
5125
 * Gets the software name (the name/brand of the Chamilo-based customized system).
5126
 *
5127
 * @return string
5128
 */
5129
function api_get_software_name()
5130
{
5131
    $name = api_get_configuration_value('software_name');
5132
    if (!empty($name)) {
5133
        return $name;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $name also could return the type boolean which is incompatible with the documented return type string.
Loading history...
5134
    } else {
5135
        return 'Chamilo';
5136
    }
5137
}
5138
5139
function api_get_status_list()
5140
{
5141
    $list = [];
5142
    // Table of status
5143
    $list[COURSEMANAGER] = 'teacher'; // 1
5144
    $list[SESSIONADMIN] = 'session_admin'; // 3
5145
    $list[DRH] = 'drh'; // 4
5146
    $list[STUDENT] = 'user'; // 5
5147
    $list[ANONYMOUS] = 'anonymous'; // 6
5148
    $list[INVITEE] = 'invited'; // 20
5149
5150
    return $list;
5151
}
5152
5153
/**
5154
 * Checks whether status given in parameter exists in the platform.
5155
 *
5156
 * @param mixed the status (can be either int either string)
5157
 *
5158
 * @return bool if the status exists, else returns false
5159
 */
5160
function api_status_exists($status_asked)
5161
{
5162
    $list = api_get_status_list();
5163
5164
    return in_array($status_asked, $list) ? true : isset($list[$status_asked]);
5165
}
5166
5167
/**
5168
 * Checks whether status given in parameter exists in the platform. The function
5169
 * returns the status ID or false if it does not exist, but given the fact there
5170
 * is no "0" status, the return value can be checked against
5171
 * if(api_status_key()) to know if it exists.
5172
 *
5173
 * @param   mixed   The status (can be either int or string)
5174
 *
5175
 * @return mixed Status ID if exists, false otherwise
5176
 */
5177
function api_status_key($status)
5178
{
5179
    $list = api_get_status_list();
5180
5181
    return isset($list[$status]) ? $status : array_search($status, $list);
5182
}
5183
5184
/**
5185
 * Gets the status langvars list.
5186
 *
5187
 * @return string[] the list of status with their translations
5188
 */
5189
function api_get_status_langvars()
5190
{
5191
    return [
5192
        COURSEMANAGER => get_lang('Teacher'),
5193
        SESSIONADMIN => get_lang('SessionsAdmin'),
5194
        DRH => get_lang('Human Resources Manager'),
5195
        STUDENT => get_lang('Learner'),
5196
        ANONYMOUS => get_lang('Anonymous'),
5197
        STUDENT_BOSS => get_lang('RoleStudentBoss'),
5198
        INVITEE => get_lang('Invited'),
5199
    ];
5200
}
5201
5202
/**
5203
 * The function that retrieves all the possible settings for a certain config setting.
5204
 *
5205
 * @author Patrick Cool <[email protected]>, Ghent University
5206
 */
5207
function api_get_settings_options($var)
5208
{
5209
    $table_settings_options = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
5210
    $var = Database::escape_string($var);
5211
    $sql = "SELECT * FROM $table_settings_options
5212
            WHERE variable = '$var'
5213
            ORDER BY id";
5214
    $result = Database::query($sql);
5215
    $settings_options_array = [];
5216
    while ($row = Database::fetch_array($result, 'ASSOC')) {
5217
        $settings_options_array[] = $row;
5218
    }
5219
5220
    return $settings_options_array;
5221
}
5222
5223
/**
5224
 * @param array $params
5225
 */
5226
function api_set_setting_option($params)
5227
{
5228
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
5229
    if (empty($params['id'])) {
5230
        Database::insert($table, $params);
5231
    } else {
5232
        Database::update($table, $params, ['id = ? ' => $params['id']]);
5233
    }
5234
}
5235
5236
/**
5237
 * @param array $params
5238
 */
5239
function api_set_setting_simple($params)
5240
{
5241
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5242
    $url_id = api_get_current_access_url_id();
5243
5244
    if (empty($params['id'])) {
5245
        $params['access_url'] = $url_id;
5246
        Database::insert($table, $params);
5247
    } else {
5248
        Database::update($table, $params, ['id = ? ' => [$params['id']]]);
5249
    }
5250
}
5251
5252
/**
5253
 * @param int $id
5254
 */
5255
function api_delete_setting_option($id)
5256
{
5257
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_OPTIONS);
5258
    if (!empty($id)) {
5259
        Database::delete($table, ['id = ? ' => $id]);
5260
    }
5261
}
5262
5263
/**
5264
 * Sets a platform configuration setting to a given value.
5265
 *
5266
 * @param string    The variable we want to update
5267
 * @param string    The value we want to record
5268
 * @param string    The sub-variable if any (in most cases, this will remain null)
5269
 * @param string    The category if any (in most cases, this will remain null)
5270
 * @param int       The access_url for which this parameter is valid
5271
 * @param string $cat
5272
 *
5273
 * @return bool|null
5274
 */
5275
function api_set_setting($var, $value, $subvar = null, $cat = null, $access_url = 1)
5276
{
5277
    if (empty($var)) {
5278
        return false;
5279
    }
5280
    $t_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5281
    $var = Database::escape_string($var);
5282
    $value = Database::escape_string($value);
5283
    $access_url = (int) $access_url;
5284
    if (empty($access_url)) {
5285
        $access_url = 1;
5286
    }
5287
    $select = "SELECT id FROM $t_settings WHERE variable = '$var' ";
5288
    if (!empty($subvar)) {
5289
        $subvar = Database::escape_string($subvar);
5290
        $select .= " AND subkey = '$subvar'";
5291
    }
5292
    if (!empty($cat)) {
5293
        $cat = Database::escape_string($cat);
5294
        $select .= " AND category = '$cat'";
5295
    }
5296
    if ($access_url > 1) {
5297
        $select .= " AND access_url = $access_url";
5298
    } else {
5299
        $select .= " AND access_url = 1 ";
5300
    }
5301
5302
    $res = Database::query($select);
5303
    if (Database::num_rows($res) > 0) {
5304
        // Found item for this access_url.
5305
        $row = Database::fetch_array($res);
5306
        $sql = "UPDATE $t_settings SET selected_value = '$value'
5307
                WHERE id = ".$row['id'];
5308
        Database::query($sql);
5309
    } else {
5310
        // Item not found for this access_url, we have to check if it exist with access_url = 1
5311
        $select = "SELECT * FROM $t_settings
5312
                   WHERE variable = '$var' AND access_url = 1 ";
5313
        // Just in case
5314
        if (1 == $access_url) {
5315
            if (!empty($subvar)) {
5316
                $select .= " AND subkey = '$subvar'";
5317
            }
5318
            if (!empty($cat)) {
5319
                $select .= " AND category = '$cat'";
5320
            }
5321
            $res = Database::query($select);
5322
            if (Database::num_rows($res) > 0) {
5323
                // We have a setting for access_url 1, but none for the current one, so create one.
5324
                $row = Database::fetch_array($res);
5325
                $insert = "INSERT INTO $t_settings (variable, subkey, type,category, selected_value, title, comment, scope, subkeytext, access_url)
5326
                        VALUES
5327
                        ('".$row['variable']."',".(!empty($row['subkey']) ? "'".$row['subkey']."'" : "NULL").",".
5328
                    "'".$row['type']."','".$row['category']."',".
5329
                    "'$value','".$row['title']."',".
5330
                    "".(!empty($row['comment']) ? "'".$row['comment']."'" : "NULL").",".(!empty($row['scope']) ? "'".$row['scope']."'" : "NULL").",".
5331
                    "".(!empty($row['subkeytext']) ? "'".$row['subkeytext']."'" : "NULL").",$access_url)";
5332
                Database::query($insert);
5333
            } else {
5334
                // Such a setting does not exist.
5335
                //error_log(__FILE__.':'.__LINE__.': Attempting to update setting '.$var.' ('.$subvar.') which does not exist at all', 0);
5336
            }
5337
        } else {
5338
            // Other access url.
5339
            if (!empty($subvar)) {
5340
                $select .= " AND subkey = '$subvar'";
5341
            }
5342
            if (!empty($cat)) {
5343
                $select .= " AND category = '$cat'";
5344
            }
5345
            $res = Database::query($select);
5346
5347
            if (Database::num_rows($res) > 0) {
5348
                // We have a setting for access_url 1, but none for the current one, so create one.
5349
                $row = Database::fetch_array($res);
5350
                if (1 == $row['access_url_changeable']) {
5351
                    $insert = "INSERT INTO $t_settings (variable,subkey, type,category, selected_value,title, comment,scope, subkeytext,access_url, access_url_changeable) VALUES
5352
                            ('".$row['variable']."',".
5353
                        (!empty($row['subkey']) ? "'".$row['subkey']."'" : "NULL").",".
5354
                        "'".$row['type']."','".$row['category']."',".
5355
                        "'$value','".$row['title']."',".
5356
                        "".(!empty($row['comment']) ? "'".$row['comment']."'" : "NULL").",".
5357
                        (!empty($row['scope']) ? "'".$row['scope']."'" : "NULL").",".
5358
                        "".(!empty($row['subkeytext']) ? "'".$row['subkeytext']."'" : "NULL").",$access_url,".$row['access_url_changeable'].")";
5359
                    Database::query($insert);
5360
                }
5361
            } else { // Such a setting does not exist.
5362
                //error_log(__FILE__.':'.__LINE__.': Attempting to update setting '.$var.' ('.$subvar.') which does not exist at all. The access_url is: '.$access_url.' ',0);
5363
            }
5364
        }
5365
    }
5366
}
5367
5368
/**
5369
 * Sets a whole category of settings to one specific value.
5370
 *
5371
 * @param string    Category
5372
 * @param string    Value
5373
 * @param int       Access URL. Optional. Defaults to 1
5374
 * @param array     Optional array of filters on field type
5375
 * @param string $category
5376
 * @param string $value
5377
 *
5378
 * @return bool
5379
 */
5380
function api_set_settings_category($category, $value = null, $access_url = 1, $fieldtype = [])
5381
{
5382
    if (empty($category)) {
5383
        return false;
5384
    }
5385
    $category = Database::escape_string($category);
5386
    $t_s = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5387
    $access_url = (int) $access_url;
5388
    if (empty($access_url)) {
5389
        $access_url = 1;
5390
    }
5391
    if (isset($value)) {
5392
        $value = Database::escape_string($value);
5393
        $sql = "UPDATE $t_s SET selected_value = '$value'
5394
                WHERE category = '$category' AND access_url = $access_url";
5395
        if (is_array($fieldtype) && count($fieldtype) > 0) {
5396
            $sql .= " AND ( ";
5397
            $i = 0;
5398
            foreach ($fieldtype as $type) {
5399
                if ($i > 0) {
5400
                    $sql .= ' OR ';
5401
                }
5402
                $type = Database::escape_string($type);
5403
                $sql .= " type='".$type."' ";
5404
                $i++;
5405
            }
5406
            $sql .= ")";
5407
        }
5408
        $res = Database::query($sql);
5409
5410
        return false !== $res;
5411
    } else {
5412
        $sql = "UPDATE $t_s SET selected_value = NULL
5413
                WHERE category = '$category' AND access_url = $access_url";
5414
        if (is_array($fieldtype) && count($fieldtype) > 0) {
5415
            $sql .= " AND ( ";
5416
            $i = 0;
5417
            foreach ($fieldtype as $type) {
5418
                if ($i > 0) {
5419
                    $sql .= ' OR ';
5420
                }
5421
                $type = Database::escape_string($type);
5422
                $sql .= " type='".$type."' ";
5423
                $i++;
5424
            }
5425
            $sql .= ")";
5426
        }
5427
        $res = Database::query($sql);
5428
5429
        return false !== $res;
5430
    }
5431
}
5432
5433
/**
5434
 * Gets all available access urls in an array (as in the database).
5435
 *
5436
 * @return array An array of database records
5437
 */
5438
function api_get_access_urls($from = 0, $to = 1000000, $order = 'url', $direction = 'ASC')
5439
{
5440
    $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5441
    $from = (int) $from;
5442
    $to = (int) $to;
5443
    $order = Database::escape_string($order, null, false);
5444
    $direction = Database::escape_string($direction, null, false);
5445
    $sql = "SELECT id, url, description, active, created_by, tms
5446
            FROM $table
5447
            ORDER BY $order $direction
5448
            LIMIT $to OFFSET $from";
5449
    $res = Database::query($sql);
5450
5451
    return Database::store_result($res);
5452
}
5453
5454
/**
5455
 * Gets the access url info in an array.
5456
 *
5457
 * @param int  $id            Id of the access url
5458
 * @param bool $returnDefault Set to false if you want the real URL if URL 1 is still 'http://localhost/'
5459
 *
5460
 * @return array All the info (url, description, active, created_by, tms)
5461
 *               from the access_url table
5462
 *
5463
 * @author Julio Montoya
5464
 */
5465
function api_get_access_url($id, $returnDefault = true)
5466
{
5467
    static $staticResult;
5468
    $id = (int) $id;
5469
5470
    if (isset($staticResult[$id])) {
5471
        $result = $staticResult[$id];
5472
    } else {
5473
        // Calling the Database:: library dont work this is handmade.
5474
        $table_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5475
        $sql = "SELECT url, description, active, created_by, tms
5476
                FROM $table_access_url WHERE id = '$id' ";
5477
        $res = Database::query($sql);
5478
        $result = @Database::fetch_array($res);
5479
        $staticResult[$id] = $result;
5480
    }
5481
5482
    // If the result url is 'http://localhost/' (the default) and the root_web
5483
    // (=current url) is different, and the $id is = 1 (which might mean
5484
    // api_get_current_access_url_id() returned 1 by default), then return the
5485
    // root_web setting instead of the current URL
5486
    // This is provided as an option to avoid breaking the storage of URL-specific
5487
    // homepages in home/localhost/
5488
    if (1 === $id && false === $returnDefault) {
5489
        $currentUrl = api_get_current_access_url_id();
5490
        // only do this if we are on the main URL (=1), otherwise we could get
5491
        // information on another URL instead of the one asked as parameter
5492
        if (1 === $currentUrl) {
5493
            $rootWeb = api_get_path(WEB_PATH);
5494
            $default = 'http://localhost/';
5495
            if ($result['url'] === $default && $rootWeb != $default) {
5496
                $result['url'] = $rootWeb;
5497
            }
5498
        }
5499
    }
5500
5501
    return $result;
5502
}
5503
5504
/**
5505
 * Gets all the current settings for a specific access url.
5506
 *
5507
 * @param string    The category, if any, that we want to get
5508
 * @param string    Whether we want a simple list (display a category) or
5509
 * a grouped list (group by variable as in settings.php default). Values: 'list' or 'group'
5510
 * @param int       Access URL's ID. Optional. Uses 1 by default, which is the unique URL
5511
 *
5512
 * @return array Array of database results for the current settings of the current access URL
5513
 */
5514
function &api_get_settings($cat = null, $ordering = 'list', $access_url = 1, $url_changeable = 0)
5515
{
5516
    $table = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
5517
    $access_url = (int) $access_url;
5518
    $where_condition = '';
5519
    if (1 == $url_changeable) {
5520
        $where_condition = " AND access_url_changeable= '1' ";
5521
    }
5522
    if (empty($access_url) || -1 == $access_url) {
5523
        $access_url = 1;
5524
    }
5525
    $sql = "SELECT * FROM $table
5526
            WHERE access_url = $access_url  $where_condition ";
5527
5528
    if (!empty($cat)) {
5529
        $cat = Database::escape_string($cat);
5530
        $sql .= " AND category='$cat' ";
5531
    }
5532
    if ('group' == $ordering) {
5533
        $sql .= " ORDER BY id ASC";
5534
    } else {
5535
        $sql .= " ORDER BY 1,2 ASC";
5536
    }
5537
    $result = Database::query($sql);
5538
    if (null === $result) {
5539
        return [];
5540
    }
5541
    $result = Database::store_result($result, 'ASSOC');
5542
5543
    return $result;
5544
}
5545
5546
/**
5547
 * @param string $value       The value we want to record
5548
 * @param string $variable    The variable name we want to insert
5549
 * @param string $subKey      The subkey for the variable we want to insert
5550
 * @param string $type        The type for the variable we want to insert
5551
 * @param string $category    The category for the variable we want to insert
5552
 * @param string $title       The title
5553
 * @param string $comment     The comment
5554
 * @param string $scope       The scope
5555
 * @param string $subKeyText  The subkey text
5556
 * @param int    $accessUrlId The access_url for which this parameter is valid
5557
 * @param int    $visibility  The changeability of this setting for non-master urls
5558
 *
5559
 * @return int The setting ID
5560
 */
5561
function api_add_setting(
5562
    $value,
5563
    $variable,
5564
    $subKey = '',
5565
    $type = 'textfield',
5566
    $category = '',
5567
    $title = '',
5568
    $comment = '',
5569
    $scope = '',
5570
    $subKeyText = '',
5571
    $accessUrlId = 1,
5572
    $visibility = 0
5573
) {
5574
    $em = Database::getManager();
5575
    $settingRepo = $em->getRepository('ChamiloCoreBundle:SettingsCurrent');
5576
    $accessUrlId = (int) $accessUrlId ?: 1;
5577
5578
    if (is_array($value)) {
5579
        $value = serialize($value);
5580
    } else {
5581
        $value = trim($value);
5582
    }
5583
5584
    $criteria = ['variable' => $variable, 'url' => $accessUrlId];
5585
5586
    if (!empty($subKey)) {
5587
        $criteria['subkey'] = $subKey;
5588
    }
5589
5590
    // Check if this variable doesn't exist already
5591
    /** @var SettingsCurrent $setting */
5592
    $setting = $settingRepo->findOneBy($criteria);
5593
5594
    if ($setting) {
0 ignored issues
show
introduced by
$setting is of type Chamilo\CoreBundle\Entity\SettingsCurrent, thus it always evaluated to true.
Loading history...
5595
        $setting->setSelectedValue($value);
5596
5597
        $em->persist($setting);
5598
        $em->flush();
5599
5600
        return $setting->getId();
5601
    }
5602
5603
    // Item not found for this access_url, we have to check if the whole thing is missing
5604
    // (in which case we ignore the insert) or if there *is* a record but just for access_url = 1
5605
    $setting = new SettingsCurrent();
5606
    $url = api_get_url_entity();
5607
5608
    $setting
5609
        ->setVariable($variable)
5610
        ->setSelectedValue($value)
5611
        ->setType($type)
5612
        ->setCategory($category)
5613
        ->setSubkey($subKey)
5614
        ->setTitle($title)
5615
        ->setComment($comment)
5616
        ->setScope($scope)
5617
        ->setSubkeytext($subKeyText)
5618
        ->setUrl(api_get_url_entity())
5619
        ->setAccessUrlChangeable($visibility);
5620
5621
    $em->persist($setting);
5622
    $em->flush();
5623
5624
    return $setting->getId();
5625
}
5626
5627
/**
5628
 * Checks wether a user can or can't view the contents of a course.
5629
 *
5630
 * @deprecated use CourseManager::is_user_subscribed_in_course
5631
 *
5632
 * @param int $userid User id or NULL to get it from $_SESSION
5633
 * @param int $cid    course id to check whether the user is allowed
5634
 *
5635
 * @return bool
5636
 */
5637
function api_is_course_visible_for_user($userid = null, $cid = null)
5638
{
5639
    if (null === $userid) {
5640
        $userid = api_get_user_id();
5641
    }
5642
    if (empty($userid) || strval(intval($userid)) != $userid) {
5643
        if (api_is_anonymous()) {
5644
            $userid = api_get_anonymous_id();
5645
        } else {
5646
            return false;
5647
        }
5648
    }
5649
    $cid = Database::escape_string($cid);
5650
5651
    $courseInfo = api_get_course_info($cid);
5652
    $courseId = $courseInfo['real_id'];
5653
    $is_platformAdmin = api_is_platform_admin();
5654
5655
    $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
5656
    $course_cat_table = Database::get_main_table(TABLE_MAIN_CATEGORY);
5657
5658
    $sql = "SELECT
5659
                $course_cat_table.code AS category_code,
5660
                $course_table.visibility,
5661
                $course_table.code,
5662
                $course_cat_table.code
5663
            FROM $course_table
5664
            LEFT JOIN $course_cat_table
5665
                ON $course_table.category_id = $course_cat_table.id
5666
            WHERE
5667
                $course_table.code = '$cid'
5668
            LIMIT 1";
5669
5670
    $result = Database::query($sql);
5671
5672
    if (Database::num_rows($result) > 0) {
5673
        $visibility = Database::fetch_array($result);
5674
        $visibility = $visibility['visibility'];
5675
    } else {
5676
        $visibility = 0;
5677
    }
5678
    // Shortcut permissions in case the visibility is "open to the world".
5679
    if (COURSE_VISIBILITY_OPEN_WORLD === $visibility) {
5680
        return true;
5681
    }
5682
5683
    $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
5684
5685
    $sql = "SELECT
5686
                is_tutor, status
5687
            FROM $tbl_course_user
5688
            WHERE
5689
                user_id  = '$userid' AND
5690
                relation_type <> '".COURSE_RELATION_TYPE_RRHH."' AND
5691
                c_id = $courseId
5692
            LIMIT 1";
5693
5694
    $result = Database::query($sql);
5695
5696
    if (Database::num_rows($result) > 0) {
5697
        // This user has got a recorded state for this course.
5698
        $cuData = Database::fetch_array($result);
5699
        $is_courseMember = true;
5700
        $is_courseAdmin = (1 == $cuData['status']);
5701
    }
5702
5703
    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...
5704
        // This user has no status related to this course.
5705
        // Is it the session coach or the session admin?
5706
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
5707
        $tbl_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
5708
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
5709
5710
        $sql = "SELECT
5711
                    session.id_coach, session_admin_id, session.id
5712
                FROM
5713
                    $tbl_session as session
5714
                INNER JOIN $tbl_session_course
5715
                    ON session_rel_course.session_id = session.id
5716
                    AND session_rel_course.c_id = '$courseId'
5717
                LIMIT 1";
5718
5719
        $result = Database::query($sql);
5720
        $row = Database::store_result($result);
5721
5722
        if ($row[0]['id_coach'] == $userid) {
5723
            $is_courseMember = true;
5724
            $is_courseAdmin = false;
5725
        } elseif ($row[0]['session_admin_id'] == $userid) {
5726
            $is_courseMember = false;
5727
            $is_courseAdmin = false;
5728
        } else {
5729
            // Check if the current user is the course coach.
5730
            $sql = "SELECT 1
5731
                    FROM $tbl_session_course
5732
                    WHERE session_rel_course.c_id = '$courseId'
5733
                    AND session_rel_course.id_coach = '$userid'
5734
                    LIMIT 1";
5735
5736
            $result = Database::query($sql);
5737
5738
            //if ($row = Database::fetch_array($result)) {
5739
            if (Database::num_rows($result) > 0) {
5740
                $is_courseMember = true;
5741
                $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
5742
5743
                $sql = "SELECT status FROM $tbl_user
5744
                        WHERE user_id = $userid
5745
                        LIMIT 1";
5746
5747
                $result = Database::query($sql);
5748
5749
                if (1 == Database::result($result, 0, 0)) {
5750
                    $is_courseAdmin = true;
5751
                } else {
5752
                    $is_courseAdmin = false;
5753
                }
5754
            } else {
5755
                // Check if the user is a student is this session.
5756
                $sql = "SELECT  id
5757
                        FROM $tbl_session_course_user
5758
                        WHERE
5759
                            user_id  = '$userid' AND
5760
                            c_id = '$courseId'
5761
                        LIMIT 1";
5762
5763
                if (Database::num_rows($result) > 0) {
5764
                    // This user haa got a recorded state for this course.
5765
                    while ($row = Database::fetch_array($result)) {
5766
                        $is_courseMember = true;
5767
                        $is_courseAdmin = false;
5768
                    }
5769
                }
5770
            }
5771
        }
5772
    }
5773
5774
    switch ($visibility) {
5775
        case COURSE_VISIBILITY_OPEN_WORLD:
5776
            return true;
5777
        case COURSE_VISIBILITY_OPEN_PLATFORM:
5778
            return isset($userid);
5779
        case COURSE_VISIBILITY_REGISTERED:
5780
        case COURSE_VISIBILITY_CLOSED:
5781
            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...
5782
        case COURSE_VISIBILITY_HIDDEN:
5783
            return $is_platformAdmin;
5784
    }
5785
5786
    return false;
5787
}
5788
5789
/**
5790
 * Returns whether an element (forum, message, survey ...) belongs to a session or not.
5791
 *
5792
 * @param string the tool of the element
5793
 * @param int the element id in database
5794
 * @param int the session_id to compare with element session id
5795
 *
5796
 * @return bool true if the element is in the session, false else
5797
 */
5798
function api_is_element_in_the_session($tool, $element_id, $session_id = null)
5799
{
5800
    if (is_null($session_id)) {
5801
        $session_id = api_get_session_id();
5802
    }
5803
5804
    $element_id = (int) $element_id;
5805
5806
    if (empty($element_id)) {
5807
        return false;
5808
    }
5809
5810
    // Get information to build query depending of the tool.
5811
    switch ($tool) {
5812
        case TOOL_SURVEY:
5813
            $table_tool = Database::get_course_table(TABLE_SURVEY);
5814
            $key_field = 'survey_id';
5815
            break;
5816
        case TOOL_ANNOUNCEMENT:
5817
            $table_tool = Database::get_course_table(TABLE_ANNOUNCEMENT);
5818
            $key_field = 'id';
5819
            break;
5820
        case TOOL_AGENDA:
5821
            $table_tool = Database::get_course_table(TABLE_AGENDA);
5822
            $key_field = 'id';
5823
            break;
5824
        case TOOL_GROUP:
5825
            $table_tool = Database::get_course_table(TABLE_GROUP);
5826
            $key_field = 'id';
5827
            break;
5828
        default:
5829
            return false;
5830
    }
5831
    $course_id = api_get_course_int_id();
5832
5833
    $sql = "SELECT session_id FROM $table_tool
5834
            WHERE c_id = $course_id AND $key_field =  ".$element_id;
5835
    $rs = Database::query($sql);
5836
    if ($element_session_id = Database::result($rs, 0, 0)) {
5837
        if ($element_session_id == intval($session_id)) {
5838
            // The element belongs to the session.
5839
            return true;
5840
        }
5841
    }
5842
5843
    return false;
5844
}
5845
5846
/**
5847
 * Replaces "forbidden" characters in a filename string.
5848
 *
5849
 * @param string $filename
5850
 * @param bool   $treat_spaces_as_hyphens
5851
 *
5852
 * @return string
5853
 */
5854
function api_replace_dangerous_char($filename, $treat_spaces_as_hyphens = true)
5855
{
5856
    // Some non-properly encoded file names can cause the whole file to be
5857
    // skipped when uploaded. Avoid this by detecting the encoding and
5858
    // converting to UTF-8, setting the source as ASCII (a reasonably
5859
    // limited characters set) if nothing could be found (BT#
5860
    $encoding = api_detect_encoding($filename);
5861
    if (empty($encoding)) {
5862
        $encoding = 'ASCII';
5863
        if (!api_is_valid_ascii($filename)) {
5864
            // try iconv and try non standard ASCII a.k.a CP437
5865
            // see BT#15022
5866
            if (function_exists('iconv')) {
5867
                $result = iconv('CP437', 'UTF-8', $filename);
5868
                if (api_is_valid_utf8($result)) {
5869
                    $filename = $result;
5870
                    $encoding = 'UTF-8';
5871
                }
5872
            }
5873
        }
5874
    }
5875
5876
    $filename = api_to_system_encoding($filename, $encoding);
5877
5878
    $url = URLify::filter(
5879
        $filename,
5880
        250,
5881
        '',
5882
        true,
5883
        false,
5884
        false,
5885
        false
5886
    );
5887
5888
    return $url;
5889
}
5890
5891
/**
5892
 * Fixes the $_SERVER['REQUEST_URI'] that is empty in IIS6.
5893
 *
5894
 * @author Ivan Tcholakov, 28-JUN-2006.
5895
 */
5896
function api_request_uri()
5897
{
5898
    if (!empty($_SERVER['REQUEST_URI'])) {
5899
        return $_SERVER['REQUEST_URI'];
5900
    }
5901
    $uri = $_SERVER['SCRIPT_NAME'];
5902
    if (!empty($_SERVER['QUERY_STRING'])) {
5903
        $uri .= '?'.$_SERVER['QUERY_STRING'];
5904
    }
5905
    $_SERVER['REQUEST_URI'] = $uri;
5906
5907
    return $uri;
5908
}
5909
5910
/** Gets the current access_url id of the Chamilo Platform.
5911
 * @author Julio Montoya <[email protected]>
5912
 *
5913
 * @return int access_url_id of the current Chamilo Installation
5914
 */
5915
function api_get_current_access_url_id()
5916
{
5917
    if (false === api_get_multiple_access_url()) {
5918
        return 1;
5919
    }
5920
5921
    static $id;
5922
    if (!empty($id)) {
5923
        return $id;
5924
    }
5925
5926
    $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5927
    $path = Database::escape_string(api_get_path(WEB_PATH));
5928
    $sql = "SELECT id FROM $table WHERE url = '".$path."'";
5929
    $result = Database::query($sql);
5930
    if (Database::num_rows($result) > 0) {
5931
        $id = Database::result($result, 0, 0);
5932
        if (false === $id) {
5933
            return -1;
5934
        }
5935
5936
        return (int) $id;
5937
    }
5938
5939
    $id = 1;
5940
5941
    //if the url in WEB_PATH was not found, it can only mean that there is
5942
    // either a configuration problem or the first URL has not been defined yet
5943
    // (by default it is http://localhost/). Thus the more sensible thing we can
5944
    // do is return 1 (the main URL) as the user cannot hack this value anyway
5945
    return 1;
5946
}
5947
5948
/**
5949
 * Gets the registered urls from a given user id.
5950
 *
5951
 * @author Julio Montoya <[email protected]>
5952
 *
5953
 * @param int $user_id
5954
 *
5955
 * @return array
5956
 */
5957
function api_get_access_url_from_user($user_id)
5958
{
5959
    $user_id = (int) $user_id;
5960
    $table_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
5961
    $table_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL);
5962
    $sql = "SELECT access_url_id
5963
            FROM $table_url_rel_user url_rel_user
5964
            INNER JOIN $table_url u
5965
            ON (url_rel_user.access_url_id = u.id)
5966
            WHERE user_id = ".$user_id;
5967
    $result = Database::query($sql);
5968
    $list = [];
5969
    while ($row = Database::fetch_array($result, 'ASSOC')) {
5970
        $list[] = $row['access_url_id'];
5971
    }
5972
5973
    return $list;
5974
}
5975
5976
/**
5977
 * Checks whether the curent user is in a group or not.
5978
 *
5979
 * @param string        The group id - optional (takes it from session if not given)
5980
 * @param string        The course code - optional (no additional check by course if course code is not given)
5981
 *
5982
 * @return bool
5983
 *
5984
 * @author Ivan Tcholakov
5985
 */
5986
function api_is_in_group($groupIdParam = null, $courseCodeParam = null)
5987
{
5988
    if (!empty($courseCodeParam)) {
5989
        $courseCode = api_get_course_id();
5990
        if (!empty($courseCode)) {
5991
            if ($courseCodeParam != $courseCode) {
5992
                return false;
5993
            }
5994
        } else {
5995
            return false;
5996
        }
5997
    }
5998
5999
    $groupId = api_get_group_id();
6000
6001
    if (isset($groupId) && '' != $groupId) {
6002
        if (!empty($groupIdParam)) {
6003
            return $groupIdParam == $groupId;
6004
        } else {
6005
            return true;
6006
        }
6007
    }
6008
6009
    return false;
6010
}
6011
6012
/**
6013
 * Checks whether a secret key is valid.
6014
 *
6015
 * @param string $original_key_secret - secret key from (webservice) client
6016
 * @param string $security_key        - security key from Chamilo
6017
 *
6018
 * @return bool - true if secret key is valid, false otherwise
6019
 */
6020
function api_is_valid_secret_key($original_key_secret, $security_key)
6021
{
6022
    return $original_key_secret == sha1($security_key);
6023
}
6024
6025
/**
6026
 * Checks whether a user is into course.
6027
 *
6028
 * @param int $course_id - the course id
6029
 * @param int $user_id   - the user id
6030
 *
6031
 * @return bool
6032
 */
6033
function api_is_user_of_course($course_id, $user_id)
6034
{
6035
    $tbl_course_rel_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
6036
    $sql = 'SELECT user_id FROM '.$tbl_course_rel_user.'
6037
            WHERE
6038
                c_id ="'.intval($course_id).'" AND
6039
                user_id = "'.intval($user_id).'" AND
6040
                relation_type <> '.COURSE_RELATION_TYPE_RRHH.' ';
6041
    $result = Database::query($sql);
6042
6043
    return 1 == Database::num_rows($result);
6044
}
6045
6046
/**
6047
 * Checks whether the server's operating system is Windows (TM).
6048
 *
6049
 * @return bool - true if the operating system is Windows, false otherwise
6050
 */
6051
function api_is_windows_os()
6052
{
6053
    if (function_exists('php_uname')) {
6054
        // php_uname() exists as of PHP 4.0.2, according to the documentation.
6055
        // We expect that this function will always work for Chamilo 1.8.x.
6056
        $os = php_uname();
6057
    }
6058
    // The following methods are not needed, but let them stay, just in case.
6059
    elseif (isset($_ENV['OS'])) {
6060
        // Sometimes $_ENV['OS'] may not be present (bugs?)
6061
        $os = $_ENV['OS'];
6062
    } elseif (defined('PHP_OS')) {
6063
        // PHP_OS means on which OS PHP was compiled, this is why
6064
        // using PHP_OS is the last choice for detection.
6065
        $os = PHP_OS;
6066
    } else {
6067
        return false;
6068
    }
6069
6070
    return 'win' == strtolower(substr((string) $os, 0, 3));
6071
}
6072
6073
/**
6074
 * This function informs whether the sent request is XMLHttpRequest.
6075
 */
6076
function api_is_xml_http_request()
6077
{
6078
    return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && 'xmlhttprequest' == strtolower($_SERVER['HTTP_X_REQUESTED_WITH']);
6079
}
6080
6081
/**
6082
 * This wrapper function has been implemented for avoiding some known problems about the function getimagesize().
6083
 *
6084
 * @see http://php.net/manual/en/function.getimagesize.php
6085
 * @see http://www.dokeos.com/forum/viewtopic.php?t=12345
6086
 * @see http://www.dokeos.com/forum/viewtopic.php?t=16355
6087
 *
6088
 * @return int
6089
 */
6090
function api_getimagesize($path)
6091
{
6092
    $image = new Image($path);
6093
6094
    return $image->get_image_size();
6095
}
6096
6097
/**
6098
 * This function resizes an image, with preserving its proportions (or aspect ratio).
6099
 *
6100
 * @author Ivan Tcholakov, MAY-2009.
6101
 *
6102
 * @param int $image         System path or URL of the image
6103
 * @param int $target_width  Targeted width
6104
 * @param int $target_height Targeted height
6105
 *
6106
 * @return array Calculated new width and height
6107
 */
6108
function api_resize_image($image, $target_width, $target_height)
6109
{
6110
    $image_properties = api_getimagesize($image);
6111
6112
    return api_calculate_image_size(
6113
        $image_properties['width'],
6114
        $image_properties['height'],
6115
        $target_width,
6116
        $target_height
6117
    );
6118
}
6119
6120
/**
6121
 * This function calculates new image size, with preserving image's proportions (or aspect ratio).
6122
 *
6123
 * @author Ivan Tcholakov, MAY-2009.
6124
 * @author The initial idea has been taken from code by Patrick Cool, MAY-2004.
6125
 *
6126
 * @param int $image_width   Initial width
6127
 * @param int $image_height  Initial height
6128
 * @param int $target_width  Targeted width
6129
 * @param int $target_height Targeted height
6130
 *
6131
 * @return array Calculated new width and height
6132
 */
6133
function api_calculate_image_size(
6134
    $image_width,
6135
    $image_height,
6136
    $target_width,
6137
    $target_height
6138
) {
6139
    // Only maths is here.
6140
    $result = ['width' => $image_width, 'height' => $image_height];
6141
    if ($image_width <= 0 || $image_height <= 0) {
6142
        return $result;
6143
    }
6144
    $resize_factor_width = $target_width / $image_width;
6145
    $resize_factor_height = $target_height / $image_height;
6146
    $delta_width = $target_width - $image_width * $resize_factor_height;
6147
    $delta_height = $target_height - $image_height * $resize_factor_width;
6148
    if ($delta_width > $delta_height) {
6149
        $result['width'] = ceil($image_width * $resize_factor_height);
6150
        $result['height'] = ceil($image_height * $resize_factor_height);
6151
    } elseif ($delta_width < $delta_height) {
6152
        $result['width'] = ceil($image_width * $resize_factor_width);
6153
        $result['height'] = ceil($image_height * $resize_factor_width);
6154
    } else {
6155
        $result['width'] = ceil($target_width);
6156
        $result['height'] = ceil($target_height);
6157
    }
6158
6159
    return $result;
6160
}
6161
6162
/**
6163
 * Returns a list of Chamilo's tools or
6164
 * checks whether a given identificator is a valid Chamilo's tool.
6165
 *
6166
 * @author Isaac flores paz
6167
 *
6168
 * @param string The tool name to filter
6169
 *
6170
 * @return mixed Filtered string or array
6171
 */
6172
function api_get_tools_lists($my_tool = null)
6173
{
6174
    $tools_list = [
6175
        TOOL_DOCUMENT,
6176
        TOOL_THUMBNAIL,
6177
        TOOL_HOTPOTATOES,
6178
        TOOL_CALENDAR_EVENT,
6179
        TOOL_LINK,
6180
        TOOL_COURSE_DESCRIPTION,
6181
        TOOL_SEARCH,
6182
        TOOL_LEARNPATH,
6183
        TOOL_ANNOUNCEMENT,
6184
        TOOL_FORUM,
6185
        TOOL_THREAD,
6186
        TOOL_POST,
6187
        TOOL_DROPBOX,
6188
        TOOL_QUIZ,
6189
        TOOL_USER,
6190
        TOOL_GROUP,
6191
        TOOL_BLOGS,
6192
        TOOL_CHAT,
6193
        TOOL_STUDENTPUBLICATION,
6194
        TOOL_TRACKING,
6195
        TOOL_HOMEPAGE_LINK,
6196
        TOOL_COURSE_SETTING,
6197
        TOOL_BACKUP,
6198
        TOOL_COPY_COURSE_CONTENT,
6199
        TOOL_RECYCLE_COURSE,
6200
        TOOL_COURSE_HOMEPAGE,
6201
        TOOL_COURSE_RIGHTS_OVERVIEW,
6202
        TOOL_UPLOAD,
6203
        TOOL_COURSE_MAINTENANCE,
6204
        TOOL_SURVEY,
6205
        TOOL_WIKI,
6206
        TOOL_GLOSSARY,
6207
        TOOL_GRADEBOOK,
6208
        TOOL_NOTEBOOK,
6209
        TOOL_ATTENDANCE,
6210
        TOOL_COURSE_PROGRESS,
6211
    ];
6212
    if (empty($my_tool)) {
6213
        return $tools_list;
6214
    }
6215
6216
    return in_array($my_tool, $tools_list) ? $my_tool : '';
6217
}
6218
6219
/**
6220
 * Checks whether we already approved the last version term and condition.
6221
 *
6222
 * @param int user id
6223
 *
6224
 * @return bool true if we pass false otherwise
6225
 */
6226
function api_check_term_condition($userId)
6227
{
6228
    if ('true' === api_get_setting('allow_terms_conditions')) {
6229
        // Check if exists terms and conditions
6230
        if (0 == LegalManager::count()) {
6231
            return true;
6232
        }
6233
6234
        $extraFieldValue = new ExtraFieldValue('user');
6235
        $data = $extraFieldValue->get_values_by_handler_and_field_variable(
6236
            $userId,
6237
            'legal_accept'
6238
        );
6239
6240
        if (!empty($data) && isset($data['value']) && !empty($data['value'])) {
6241
            $result = $data['value'];
6242
            $user_conditions = explode(':', $result);
6243
            $version = $user_conditions[0];
6244
            $langId = $user_conditions[1];
6245
            $realVersion = LegalManager::get_last_version($langId);
6246
6247
            return $version >= $realVersion;
6248
        }
6249
6250
        return false;
6251
    }
6252
6253
    return false;
6254
}
6255
6256
/**
6257
 * Gets all information of a tool into course.
6258
 *
6259
 * @param int The tool id
6260
 *
6261
 * @return array
6262
 */
6263
function api_get_tool_information_by_name($name)
6264
{
6265
    $t_tool = Database::get_course_table(TABLE_TOOL_LIST);
6266
    $course_id = api_get_course_int_id();
6267
6268
    $sql = "SELECT id FROM tool
6269
            WHERE name = '".Database::escape_string($name)."' ";
6270
    $rs = Database::query($sql);
6271
    $data = Database::fetch_array($rs);
6272
    $tool = $data['id'];
6273
6274
    $sql = "SELECT * FROM $t_tool
6275
            WHERE c_id = $course_id  AND tool_id = '".$tool."' ";
6276
    $rs = Database::query($sql);
6277
6278
    return Database::fetch_array($rs, 'ASSOC');
6279
}
6280
6281
/**
6282
 * Function used to protect a "global" admin script.
6283
 * The function blocks access when the user has no global platform admin rights.
6284
 * Global admins are the admins that are registered in the main.admin table
6285
 * AND the users who have access to the "principal" portal.
6286
 * That means that there is a record in the main.access_url_rel_user table
6287
 * with his user id and the access_url_id=1.
6288
 *
6289
 * @author Julio Montoya
6290
 *
6291
 * @param int $user_id
6292
 *
6293
 * @return bool
6294
 */
6295
function api_is_global_platform_admin($user_id = null)
6296
{
6297
    $user_id = (int) $user_id;
6298
    if (empty($user_id)) {
6299
        $user_id = api_get_user_id();
6300
    }
6301
    if (api_is_platform_admin_by_id($user_id)) {
6302
        $urlList = api_get_access_url_from_user($user_id);
6303
        // The admin is registered in the first "main" site with access_url_id = 1
6304
        if (in_array(1, $urlList)) {
6305
            return true;
6306
        } else {
6307
            return false;
6308
        }
6309
    }
6310
6311
    return false;
6312
}
6313
6314
/**
6315
 * @param int  $admin_id_to_check
6316
 * @param int  $my_user_id
6317
 * @param bool $allow_session_admin
6318
 *
6319
 * @return bool
6320
 */
6321
function api_global_admin_can_edit_admin(
6322
    $admin_id_to_check,
6323
    $my_user_id = null,
6324
    $allow_session_admin = false
6325
) {
6326
    if (empty($my_user_id)) {
6327
        $my_user_id = api_get_user_id();
6328
    }
6329
6330
    $iam_a_global_admin = api_is_global_platform_admin($my_user_id);
6331
    $user_is_global_admin = api_is_global_platform_admin($admin_id_to_check);
6332
6333
    if ($iam_a_global_admin) {
6334
        // Global admin can edit everything
6335
        return true;
6336
    } else {
6337
        // If i'm a simple admin
6338
        $is_platform_admin = api_is_platform_admin_by_id($my_user_id);
6339
6340
        if ($allow_session_admin) {
6341
            $is_platform_admin = api_is_platform_admin_by_id($my_user_id) || (SESSIONADMIN == api_get_user_status($my_user_id));
6342
        }
6343
6344
        if ($is_platform_admin) {
6345
            if ($user_is_global_admin) {
6346
                return false;
6347
            } else {
6348
                return true;
6349
            }
6350
        } else {
6351
            return false;
6352
        }
6353
    }
6354
}
6355
6356
/**
6357
 * @param int  $admin_id_to_check
6358
 * @param int  $my_user_id
6359
 * @param bool $allow_session_admin
6360
 *
6361
 * @return bool|null
6362
 */
6363
function api_protect_super_admin($admin_id_to_check, $my_user_id = null, $allow_session_admin = false)
6364
{
6365
    if (api_global_admin_can_edit_admin($admin_id_to_check, $my_user_id, $allow_session_admin)) {
6366
        return true;
6367
    } else {
6368
        api_not_allowed();
6369
    }
6370
}
6371
6372
/**
6373
 * Function used to protect a global admin script.
6374
 * The function blocks access when the user has no global platform admin rights.
6375
 * See also the api_is_global_platform_admin() function wich defines who's a "global" admin.
6376
 *
6377
 * @author Julio Montoya
6378
 */
6379
function api_protect_global_admin_script()
6380
{
6381
    if (!api_is_global_platform_admin()) {
6382
        api_not_allowed();
6383
6384
        return false;
6385
    }
6386
6387
    return true;
6388
}
6389
6390
/**
6391
 * Check browser support for specific file types or features
6392
 * This function checks if the user's browser supports a file format or given
6393
 * feature, or returns the current browser and major version when
6394
 * $format=check_browser. Only a limited number of formats and features are
6395
 * checked by this method. Make sure you check its definition first.
6396
 *
6397
 * @param string $format Can be a file format (extension like svg, webm, ...) or a feature (like autocapitalize, ...)
6398
 *
6399
 * @deprecated
6400
 *
6401
 * @return bool or return text array if $format=check_browser
6402
 *
6403
 * @author Juan Carlos Raña Trabado
6404
 */
6405
function api_browser_support($format = '')
6406
{
6407
    return true;
6408
6409
    $browser = new Browser();
0 ignored issues
show
Unused Code introduced by
$browser = new Browser() is not reachable.

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

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

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

    return false;
}

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

Loading history...
6410
    $current_browser = $browser->getBrowser();
6411
    $a_versiontemp = explode('.', $browser->getVersion());
6412
    $current_majorver = $a_versiontemp[0];
6413
6414
    static $result;
6415
6416
    if (isset($result[$format])) {
6417
        return $result[$format];
6418
    }
6419
6420
    // Native svg support
6421
    if ('svg' == $format) {
6422
        if (('Internet Explorer' == $current_browser && $current_majorver >= 9) ||
6423
            ('Firefox' == $current_browser && $current_majorver > 1) ||
6424
            ('Safari' == $current_browser && $current_majorver >= 4) ||
6425
            ('Chrome' == $current_browser && $current_majorver >= 1) ||
6426
            ('Opera' == $current_browser && $current_majorver >= 9)
6427
        ) {
6428
            $result[$format] = true;
6429
6430
            return true;
6431
        } else {
6432
            $result[$format] = false;
6433
6434
            return false;
6435
        }
6436
    } elseif ('pdf' == $format) {
6437
        // native pdf support
6438
        if ('Chrome' == $current_browser && $current_majorver >= 6) {
6439
            $result[$format] = true;
6440
6441
            return true;
6442
        } else {
6443
            $result[$format] = false;
6444
6445
            return false;
6446
        }
6447
    } elseif ('tif' == $format || 'tiff' == $format) {
6448
        //native tif support
6449
        if ('Safari' == $current_browser && $current_majorver >= 5) {
6450
            $result[$format] = true;
6451
6452
            return true;
6453
        } else {
6454
            $result[$format] = false;
6455
6456
            return false;
6457
        }
6458
    } elseif ('ogg' == $format || 'ogx' == $format || 'ogv' == $format || 'oga' == $format) {
6459
        //native ogg, ogv,oga support
6460
        if (('Firefox' == $current_browser && $current_majorver >= 3) ||
6461
            ('Chrome' == $current_browser && $current_majorver >= 3) ||
6462
            ('Opera' == $current_browser && $current_majorver >= 9)) {
6463
            $result[$format] = true;
6464
6465
            return true;
6466
        } else {
6467
            $result[$format] = false;
6468
6469
            return false;
6470
        }
6471
    } elseif ('mpg' == $format || 'mpeg' == $format) {
6472
        //native mpg support
6473
        if (('Safari' == $current_browser && $current_majorver >= 5)) {
6474
            $result[$format] = true;
6475
6476
            return true;
6477
        } else {
6478
            $result[$format] = false;
6479
6480
            return false;
6481
        }
6482
    } elseif ('mp4' == $format) {
6483
        //native mp4 support (TODO: Android, iPhone)
6484
        if ('Android' == $current_browser || 'iPhone' == $current_browser) {
6485
            $result[$format] = true;
6486
6487
            return true;
6488
        } else {
6489
            $result[$format] = false;
6490
6491
            return false;
6492
        }
6493
    } elseif ('mov' == $format) {
6494
        //native mov support( TODO:check iPhone)
6495
        if ('Safari' == $current_browser && $current_majorver >= 5 || 'iPhone' == $current_browser) {
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: ('Safari' == $current_br...ne' == $current_browser, Probably Intended Meaning: 'Safari' == $current_bro...e' == $current_browser)
Loading history...
6496
            $result[$format] = true;
6497
6498
            return true;
6499
        } else {
6500
            $result[$format] = false;
6501
6502
            return false;
6503
        }
6504
    } elseif ('avi' == $format) {
6505
        //native avi support
6506
        if ('Safari' == $current_browser && $current_majorver >= 5) {
6507
            $result[$format] = true;
6508
6509
            return true;
6510
        } else {
6511
            $result[$format] = false;
6512
6513
            return false;
6514
        }
6515
    } elseif ('wmv' == $format) {
6516
        //native wmv support
6517
        if ('Firefox' == $current_browser && $current_majorver >= 4) {
6518
            $result[$format] = true;
6519
6520
            return true;
6521
        } else {
6522
            $result[$format] = false;
6523
6524
            return false;
6525
        }
6526
    } elseif ('webm' == $format) {
6527
        //native webm support (TODO:check IE9, Chrome9, Android)
6528
        if (('Firefox' == $current_browser && $current_majorver >= 4) ||
6529
            ('Opera' == $current_browser && $current_majorver >= 9) ||
6530
            ('Internet Explorer' == $current_browser && $current_majorver >= 9) ||
6531
            ('Chrome' == $current_browser && $current_majorver >= 9) ||
6532
            'Android' == $current_browser
6533
        ) {
6534
            $result[$format] = true;
6535
6536
            return true;
6537
        } else {
6538
            $result[$format] = false;
6539
6540
            return false;
6541
        }
6542
    } elseif ('wav' == $format) {
6543
        //native wav support (only some codecs !)
6544
        if (('Firefox' == $current_browser && $current_majorver >= 4) ||
6545
            ('Safari' == $current_browser && $current_majorver >= 5) ||
6546
            ('Opera' == $current_browser && $current_majorver >= 9) ||
6547
            ('Internet Explorer' == $current_browser && $current_majorver >= 9) ||
6548
            ('Chrome' == $current_browser && $current_majorver > 9) ||
6549
            'Android' == $current_browser ||
6550
            'iPhone' == $current_browser
6551
        ) {
6552
            $result[$format] = true;
6553
6554
            return true;
6555
        } else {
6556
            $result[$format] = false;
6557
6558
            return false;
6559
        }
6560
    } elseif ('mid' == $format || 'kar' == $format) {
6561
        //native midi support (TODO:check Android)
6562
        if ('Opera' == $current_browser && $current_majorver >= 9 || 'Android' == $current_browser) {
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: ('Opera' == $current_bro...id' == $current_browser, Probably Intended Meaning: 'Opera' == $current_brow...d' == $current_browser)
Loading history...
6563
            $result[$format] = true;
6564
6565
            return true;
6566
        } else {
6567
            $result[$format] = false;
6568
6569
            return false;
6570
        }
6571
    } elseif ('wma' == $format) {
6572
        //native wma support
6573
        if ('Firefox' == $current_browser && $current_majorver >= 4) {
6574
            $result[$format] = true;
6575
6576
            return true;
6577
        } else {
6578
            $result[$format] = false;
6579
6580
            return false;
6581
        }
6582
    } elseif ('au' == $format) {
6583
        //native au support
6584
        if ('Safari' == $current_browser && $current_majorver >= 5) {
6585
            $result[$format] = true;
6586
6587
            return true;
6588
        } else {
6589
            $result[$format] = false;
6590
6591
            return false;
6592
        }
6593
    } elseif ('mp3' == $format) {
6594
        //native mp3 support (TODO:check Android, iPhone)
6595
        if (('Safari' == $current_browser && $current_majorver >= 5) ||
6596
            ('Chrome' == $current_browser && $current_majorver >= 6) ||
6597
            ('Internet Explorer' == $current_browser && $current_majorver >= 9) ||
6598
            'Android' == $current_browser ||
6599
            'iPhone' == $current_browser ||
6600
            'Firefox' == $current_browser
6601
        ) {
6602
            $result[$format] = true;
6603
6604
            return true;
6605
        } else {
6606
            $result[$format] = false;
6607
6608
            return false;
6609
        }
6610
    } elseif ('autocapitalize' == $format) {
6611
        // Help avoiding showing the autocapitalize option if the browser doesn't
6612
        // support it: this attribute is against the HTML5 standard
6613
        if ('Safari' == $current_browser || 'iPhone' == $current_browser) {
6614
            return true;
6615
        } else {
6616
            return false;
6617
        }
6618
    } elseif ("check_browser" == $format) {
6619
        $array_check_browser = [$current_browser, $current_majorver];
6620
6621
        return $array_check_browser;
6622
    } else {
6623
        $result[$format] = false;
6624
6625
        return false;
6626
    }
6627
}
6628
6629
/**
6630
 * This function checks if exist path and file browscap.ini
6631
 * In order for this to work, your browscap configuration setting in php.ini
6632
 * must point to the correct location of the browscap.ini file on your system
6633
 * http://php.net/manual/en/function.get-browser.php.
6634
 *
6635
 * @return bool
6636
 *
6637
 * @author Juan Carlos Raña Trabado
6638
 */
6639
function api_check_browscap()
6640
{
6641
    $setting = ini_get('browscap');
6642
    if ($setting) {
6643
        $browser = get_browser($_SERVER['HTTP_USER_AGENT'], true);
6644
        if (strpos($setting, 'browscap.ini') && !empty($browser)) {
6645
            return true;
6646
        }
6647
    }
6648
6649
    return false;
6650
}
6651
6652
/**
6653
 * Returns the <script> HTML tag.
6654
 */
6655
function api_get_js($file)
6656
{
6657
    return '<script type="text/javascript" src="'.api_get_path(WEB_LIBRARY_PATH).'javascript/'.$file.'"></script>'."\n";
6658
}
6659
6660
function api_get_build_js($file)
6661
{
6662
    return '<script type="text/javascript" src="'.api_get_path(WEB_PUBLIC_PATH).'build/'.$file.'"></script>'."\n";
6663
}
6664
6665
/**
6666
 * Returns the <script> HTML tag.
6667
 *
6668
 * @return string
6669
 */
6670
function api_get_asset($file)
6671
{
6672
    return '<script type="text/javascript" src="'.api_get_path(WEB_PUBLIC_PATH).'build/libs/'.$file.'"></script>'."\n";
6673
}
6674
6675
/**
6676
 * Returns the <script> HTML tag.
6677
 *
6678
 * @param string $file
6679
 * @param string $media
6680
 *
6681
 * @return string
6682
 */
6683
function api_get_css_asset($file, $media = 'screen')
6684
{
6685
    return '<link href="'.api_get_path(WEB_PUBLIC_PATH).'libs/'.$file.'" rel="stylesheet" media="'.$media.'" type="text/css" />'."\n";
6686
}
6687
6688
/**
6689
 * Returns the <link> HTML tag.
6690
 *
6691
 * @param string $file
6692
 * @param string $media
6693
 */
6694
function api_get_css($file, $media = 'screen')
6695
{
6696
    return '<link href="'.$file.'" rel="stylesheet" media="'.$media.'" type="text/css" />'."\n";
6697
}
6698
6699
function api_get_bootstrap_and_font_awesome($returnOnlyPath = false)
6700
{
6701
    $url = api_get_path(WEB_PUBLIC_PATH).'build/css/bootstrap.css';
6702
    if ($returnOnlyPath) {
6703
        return $url;
6704
    }
6705
6706
    return '<link href="'.$url.'" rel="stylesheet" type="text/css" />'."\n";
6707
}
6708
6709
/**
6710
 * Returns the js header to include the jquery library.
6711
 */
6712
function api_get_jquery_js()
6713
{
6714
    return api_get_asset('jquery/jquery.min.js');
6715
}
6716
6717
/**
6718
 * Returns the jquery path.
6719
 *
6720
 * @return string
6721
 */
6722
function api_get_jquery_web_path()
6723
{
6724
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery/jquery.min.js';
6725
}
6726
6727
/**
6728
 * @return string
6729
 */
6730
function api_get_jquery_ui_js_web_path()
6731
{
6732
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery-ui/jquery-ui.min.js';
6733
}
6734
6735
/**
6736
 * @return string
6737
 */
6738
function api_get_jquery_ui_css_web_path()
6739
{
6740
    return api_get_path(WEB_PUBLIC_PATH).'assets/jquery-ui/themes/smoothness/jquery-ui.min.css';
6741
}
6742
6743
/**
6744
 * Returns the jquery-ui library js headers.
6745
 *
6746
 * @return string html tags
6747
 */
6748
function api_get_jquery_ui_js()
6749
{
6750
    $libraries = [];
6751
6752
    return api_get_jquery_libraries_js($libraries);
6753
}
6754
6755
function api_get_jqgrid_js()
6756
{
6757
    $routePublic = Container::getRouter()->generate('home');
6758
6759
    return api_get_css($routePublic.'build/free-jqgrid.css').PHP_EOL
6760
        .api_get_js_simple($routePublic.'build/free-jqgrid.js');
6761
}
6762
6763
/**
6764
 * Returns the jquery library js and css headers.
6765
 *
6766
 * @param   array   list of jquery libraries supported jquery-ui
6767
 * @param   bool    add the jquery library
6768
 *
6769
 * @return string html tags
6770
 */
6771
function api_get_jquery_libraries_js($libraries)
6772
{
6773
    $js = '';
6774
6775
    //Document multiple upload funcionality
6776
    if (in_array('jquery-uploadzs', $libraries)) {
6777
        $js .= api_get_asset('blueimp-load-image/js/load-image.all.min.js');
6778
        $js .= api_get_asset('blueimp-canvas-to-blob/js/canvas-to-blob.min.js');
6779
        $js .= api_get_asset('jquery-file-upload/js/jquery.iframe-transport.js');
6780
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload.js');
6781
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-process.js');
6782
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-image.js');
6783
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-audio.js');
6784
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-video.js');
6785
        $js .= api_get_asset('jquery-file-upload/js/jquery.fileupload-validate.js');
6786
6787
        $js .= api_get_css(api_get_path(WEB_PUBLIC_PATH).'assets/jquery-file-upload/css/jquery.fileupload.css');
6788
        $js .= api_get_css(api_get_path(WEB_PUBLIC_PATH).'assets/jquery-file-upload/css/jquery.fileupload-ui.css');
6789
    }
6790
6791
    // jquery datepicker
6792
    if (in_array('datepicker', $libraries)) {
6793
        $languaje = 'en-GB';
6794
        $platform_isocode = strtolower(api_get_language_isocode());
6795
6796
        $datapicker_langs = [
6797
            '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',
6798
        ];
6799
        if (in_array($platform_isocode, $datapicker_langs)) {
6800
            $languaje = $platform_isocode;
6801
        }
6802
6803
        $js .= api_get_js('jquery-ui/jquery-ui-i18n.min.js');
6804
        $script = '<script>
6805
        $(function(){
6806
            $.datepicker.setDefaults($.datepicker.regional["'.$languaje.'"]);
6807
            $.datepicker.regional["local"] = $.datepicker.regional["'.$languaje.'"];
6808
        });
6809
        </script>
6810
        ';
6811
        $js .= $script;
6812
    }
6813
6814
    return $js;
6815
}
6816
6817
/**
6818
 * Returns the URL to the course or session, removing the complexity of the URL
6819
 * building piece by piece.
6820
 *
6821
 * This function relies on api_get_course_info()
6822
 *
6823
 * @param string $courseCode The course code - optional (takes it from context if not given)
6824
 * @param int    $sessionId  The session ID  - optional (takes it from context if not given)
6825
 * @param int    $groupId    The group ID - optional (takes it from context if not given)
6826
 *
6827
 * @return string The URL to a course, a session, or empty string if nothing works e.g. https://localhost/courses/ABC/index.php?session_id=3&gidReq=1
6828
 *
6829
 * @author  Julio Montoya <[email protected]>
6830
 */
6831
function api_get_course_url($courseCode = null, $sessionId = null, $groupId = null)
6832
{
6833
    $courseDirectory = '';
6834
    $url = '';
6835
    // If courseCode not set, get context or []
6836
    if (empty($courseCode)) {
6837
        $courseInfo = api_get_course_info();
6838
    } else {
6839
        $courseInfo = api_get_course_info($courseCode);
6840
    }
6841
6842
    // If course defined, get directory, otherwise keep empty string
6843
    if (!empty($courseInfo['directory'])) {
6844
        $courseDirectory = $courseInfo['directory'];
6845
    }
6846
6847
    // If sessionId not set, get context or 0
6848
    if (empty($sessionId)) {
6849
        $sessionId = api_get_session_id();
6850
    }
6851
6852
    // If groupId not set, get context or 0
6853
    if (empty($groupId)) {
6854
        $groupId = api_get_group_id();
6855
    }
6856
6857
    // Build the URL
6858
    if (!empty($courseDirectory)) {
6859
        // directory not empty, so we do have a course
6860
        $url = api_get_path(WEB_COURSE_PATH).$courseDirectory.'/index.php?id_session='.$sessionId.'&gidReq='.$groupId;
6861
    } elseif (!empty($sessionId) &&
6862
        'true' !== api_get_setting('session.remove_session_url')
6863
    ) {
6864
        // if the course was unset and the session was set, send directly to the session
6865
        $url = api_get_path(WEB_CODE_PATH).'session/index.php?session_id='.$sessionId;
6866
    }
6867
6868
    // if not valid combination was found, return an empty string
6869
    return $url;
6870
}
6871
6872
/**
6873
 * Check if the current portal has the $_configuration['multiple_access_urls'] parameter on.
6874
 *
6875
 * @return bool true if multi site is enabled
6876
 */
6877
function api_get_multiple_access_url()
6878
{
6879
    global $_configuration;
6880
    if (isset($_configuration['multiple_access_urls']) && $_configuration['multiple_access_urls']) {
6881
        return true;
6882
    }
6883
6884
    return false;
6885
}
6886
6887
/**
6888
 * @return bool
6889
 */
6890
function api_is_multiple_url_enabled()
6891
{
6892
    return api_get_multiple_access_url();
6893
}
6894
6895
/**
6896
 * Returns a md5 unique id.
6897
 *
6898
 * @todo add more parameters
6899
 */
6900
function api_get_unique_id()
6901
{
6902
    $id = md5(time().uniqid().api_get_user_id().api_get_course_id().api_get_session_id());
6903
6904
    return $id;
6905
}
6906
6907
/**
6908
 * @param int Course id
6909
 * @param int tool id: TOOL_QUIZ, TOOL_FORUM, TOOL_STUDENTPUBLICATION, TOOL_LEARNPATH
6910
 * @param int the item id (tool id, exercise id, lp id)
6911
 *
6912
 * @return bool
6913
 */
6914
function api_resource_is_locked_by_gradebook($item_id, $link_type, $course_code = null)
6915
{
6916
    if (api_is_platform_admin()) {
6917
        return false;
6918
    }
6919
    if ('true' == api_get_setting('gradebook_locking_enabled')) {
6920
        if (empty($course_code)) {
6921
            $course_code = api_get_course_id();
6922
        }
6923
        $table = Database::get_main_table(TABLE_MAIN_GRADEBOOK_LINK);
6924
        $item_id = (int) $item_id;
6925
        $link_type = (int) $link_type;
6926
        $course_code = Database::escape_string($course_code);
6927
        $sql = "SELECT locked FROM $table
6928
                WHERE locked = 1 AND ref_id = $item_id AND type = $link_type AND course_code = '$course_code' ";
6929
        $result = Database::query($sql);
6930
        if (Database::num_rows($result)) {
6931
            return true;
6932
        }
6933
    }
6934
6935
    return false;
6936
}
6937
6938
/**
6939
 * Blocks a page if the item was added in a gradebook.
6940
 *
6941
 * @param int       exercise id, work id, thread id,
6942
 * @param int       LINK_EXERCISE, LINK_STUDENTPUBLICATION, LINK_LEARNPATH LINK_FORUM_THREAD, LINK_ATTENDANCE
6943
 * see gradebook/lib/be/linkfactory
6944
 * @param string    course code
6945
 *
6946
 * @return false|null
6947
 */
6948
function api_block_course_item_locked_by_gradebook($item_id, $link_type, $course_code = null)
6949
{
6950
    if (api_is_platform_admin()) {
6951
        return false;
6952
    }
6953
6954
    if (api_resource_is_locked_by_gradebook($item_id, $link_type, $course_code)) {
6955
        $message = Display::return_message(get_lang('This option is not available because this activity is contained by an assessment, which is currently locked. To unlock the assessment, ask your platform administrator.'), 'warning');
6956
        api_not_allowed(true, $message);
6957
    }
6958
}
6959
6960
/**
6961
 * Checks the PHP version installed is enough to run Chamilo.
6962
 *
6963
 * @param string Include path (used to load the error page)
6964
 */
6965
function api_check_php_version()
6966
{
6967
    if (!function_exists('version_compare') ||
6968
        version_compare(phpversion(), REQUIRED_PHP_VERSION, '<')
6969
    ) {
6970
        throw new Exception('Wrong PHP version');
6971
    }
6972
}
6973
6974
/**
6975
 * Checks whether the Archive directory is present and writeable. If not,
6976
 * prints a warning message.
6977
 */
6978
function api_check_archive_dir()
6979
{
6980
    if (is_dir(api_get_path(SYS_ARCHIVE_PATH)) && !is_writable(api_get_path(SYS_ARCHIVE_PATH))) {
6981
        $message = Display::return_message(get_lang('The app/cache/ directory, used by this tool, is not writeable. Please contact your platform administrator.'), 'warning');
6982
        api_not_allowed(true, $message);
6983
    }
6984
}
6985
6986
/**
6987
 * Returns an array of global configuration settings which should be ignored
6988
 * when printing the configuration settings screens.
6989
 *
6990
 * @return array Array of strings, each identifying one of the excluded settings
6991
 */
6992
function api_get_locked_settings()
6993
{
6994
    return [
6995
        'permanently_remove_deleted_files',
6996
        'account_valid_duration',
6997
        'service_ppt2lp',
6998
        'wcag_anysurfer_public_pages',
6999
        'upload_extensions_list_type',
7000
        'upload_extensions_blacklist',
7001
        'upload_extensions_whitelist',
7002
        'upload_extensions_skip',
7003
        'upload_extensions_replace_by',
7004
        'hide_dltt_markup',
7005
        'split_users_upload_directory',
7006
        'permissions_for_new_directories',
7007
        'permissions_for_new_files',
7008
        'platform_charset',
7009
        'ldap_description',
7010
        'cas_activate',
7011
        'cas_server',
7012
        'cas_server_uri',
7013
        'cas_port',
7014
        'cas_protocol',
7015
        'cas_add_user_activate',
7016
        'update_user_info_cas_with_ldap',
7017
        'languagePriority1',
7018
        'languagePriority2',
7019
        'languagePriority3',
7020
        'languagePriority4',
7021
        'login_is_email',
7022
        'chamilo_database_version',
7023
    ];
7024
}
7025
7026
/**
7027
 * Guess the real ip for register in the database, even in reverse proxy cases.
7028
 * To be recognized, the IP has to be found in either $_SERVER['REMOTE_ADDR'] or
7029
 * in $_SERVER['HTTP_X_FORWARDED_FOR'], which is in common use with rproxies.
7030
 * Note: the result of this function is not SQL-safe. Please escape it before
7031
 * inserting in a database.
7032
 *
7033
 * @return string the user's real ip (unsafe - escape it before inserting to db)
7034
 *
7035
 * @author Jorge Frisancho Jibaja <[email protected]>, USIL - Some changes to allow the use of real IP using reverse proxy
7036
 *
7037
 * @version CEV CHANGE 24APR2012
7038
 */
7039
function api_get_real_ip()
7040
{
7041
    $ip = trim($_SERVER['REMOTE_ADDR']);
7042
    if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
7043
        if (preg_match('/,/', $_SERVER['HTTP_X_FORWARDED_FOR'])) {
7044
            @list($ip1, $ip2) = @explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
7045
        } else {
7046
            $ip1 = $_SERVER['HTTP_X_FORWARDED_FOR'];
7047
        }
7048
        $ip = trim($ip1);
7049
    }
7050
7051
    return $ip;
7052
}
7053
7054
/**
7055
 * Checks whether an IP is included inside an IP range.
7056
 *
7057
 * @param string IP address
7058
 * @param string IP range
7059
 * @param string $ip
7060
 *
7061
 * @return bool True if IP is in the range, false otherwise
7062
 *
7063
 * @author claudiu at cnixs dot com  on http://www.php.net/manual/fr/ref.network.php#55230
7064
 * @author Yannick Warnier for improvements and managment of multiple ranges
7065
 *
7066
 * @todo check for IPv6 support
7067
 */
7068
function api_check_ip_in_range($ip, $range)
7069
{
7070
    if (empty($ip) or empty($range)) {
7071
        return false;
7072
    }
7073
    $ip_ip = ip2long($ip);
7074
    // divide range param into array of elements
7075
    if (false !== strpos($range, ',')) {
7076
        $ranges = explode(',', $range);
7077
    } else {
7078
        $ranges = [$range];
7079
    }
7080
    foreach ($ranges as $range) {
0 ignored issues
show
introduced by
$range is overwriting one of the parameters of this function.
Loading history...
7081
        $range = trim($range);
7082
        if (empty($range)) {
7083
            continue;
7084
        }
7085
        if (false === strpos($range, '/')) {
7086
            if (0 === strcmp($ip, $range)) {
7087
                return true; // there is a direct IP match, return OK
7088
            }
7089
            continue; //otherwise, get to the next range
7090
        }
7091
        // the range contains a "/", so analyse completely
7092
        list($net, $mask) = explode("/", $range);
7093
7094
        $ip_net = ip2long($net);
7095
        // mask binary magic
7096
        $ip_mask = ~((1 << (32 - $mask)) - 1);
7097
7098
        $ip_ip_net = $ip_ip & $ip_mask;
7099
        if ($ip_ip_net == $ip_net) {
7100
            return true;
7101
        }
7102
    }
7103
7104
    return false;
7105
}
7106
7107
function api_check_user_access_to_legal($course_visibility)
7108
{
7109
    $course_visibility_list = [COURSE_VISIBILITY_OPEN_WORLD, COURSE_VISIBILITY_OPEN_PLATFORM];
7110
7111
    return in_array($course_visibility, $course_visibility_list) || api_is_drh();
7112
}
7113
7114
/**
7115
 * Checks if the global chat is enabled or not.
7116
 *
7117
 * @return bool
7118
 */
7119
function api_is_global_chat_enabled()
7120
{
7121
    return
7122
        !api_is_anonymous() &&
7123
        'true' === api_get_setting('allow_global_chat') &&
7124
        'true' === api_get_setting('allow_social_tool');
7125
}
7126
7127
/**
7128
 * @todo Fix tool_visible_by_default_at_creation labels
7129
 * @todo Add sessionId parameter to avoid using context
7130
 *
7131
 * @param int   $item_id
7132
 * @param int   $tool_id
7133
 * @param int   $group_id   id
7134
 * @param array $courseInfo
7135
 * @param int   $sessionId
7136
 * @param int   $userId
7137
 */
7138
function api_set_default_visibility(
7139
    $item_id,
7140
    $tool_id,
7141
    $group_id = 0,
7142
    $courseInfo = [],
7143
    $sessionId = 0,
7144
    $userId = 0
7145
) {
7146
    $courseInfo = empty($courseInfo) ? api_get_course_info() : $courseInfo;
7147
    $courseId = $courseInfo['real_id'];
7148
    $courseCode = $courseInfo['code'];
7149
    $sessionId = empty($sessionId) ? api_get_session_id() : $sessionId;
7150
    $userId = empty($userId) ? api_get_user_id() : $userId;
7151
7152
    // if group is null force group_id = 0, this force is needed to create a LP folder with group = 0
7153
    if (is_null($group_id)) {
7154
        $group_id = 0;
7155
    } else {
7156
        $group_id = empty($group_id) ? api_get_group_id() : $group_id;
7157
    }
7158
7159
    $groupInfo = [];
7160
    if (!empty($group_id)) {
7161
        $groupInfo = GroupManager::get_group_properties($group_id);
7162
    }
7163
    $original_tool_id = $tool_id;
7164
7165
    switch ($tool_id) {
7166
        case TOOL_LINK:
7167
        case TOOL_LINK_CATEGORY:
7168
            $tool_id = 'links';
7169
            break;
7170
        case TOOL_DOCUMENT:
7171
            $tool_id = 'documents';
7172
            break;
7173
        case TOOL_LEARNPATH:
7174
            $tool_id = 'learning';
7175
            break;
7176
        case TOOL_ANNOUNCEMENT:
7177
            $tool_id = 'announcements';
7178
            break;
7179
        case TOOL_FORUM:
7180
        case TOOL_FORUM_CATEGORY:
7181
        case TOOL_FORUM_THREAD:
7182
            $tool_id = 'forums';
7183
            break;
7184
        case TOOL_QUIZ:
7185
            $tool_id = 'quiz';
7186
            break;
7187
    }
7188
    $setting = api_get_setting('tool_visible_by_default_at_creation');
7189
7190
    if (isset($setting[$tool_id])) {
7191
        $visibility = 'invisible';
7192
        if ('true' == $setting[$tool_id]) {
7193
            $visibility = 'visible';
7194
        }
7195
7196
        // Read the portal and course default visibility
7197
        if ('documents' === $tool_id) {
7198
            $visibility = DocumentManager::getDocumentDefaultVisibility($courseInfo);
7199
        }
7200
7201
        api_item_property_update(
0 ignored issues
show
Bug introduced by
The function api_item_property_update was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

7201
        /** @scrutinizer ignore-call */ 
7202
        api_item_property_update(
Loading history...
7202
            $courseInfo,
7203
            $original_tool_id,
7204
            $item_id,
7205
            $visibility,
7206
            $userId,
7207
            $groupInfo,
7208
            null,
7209
            null,
7210
            null,
7211
            $sessionId
7212
        );
7213
7214
        // Fixes default visibility for tests
7215
        switch ($original_tool_id) {
7216
            case TOOL_QUIZ:
7217
                if (empty($sessionId)) {
7218
                    $objExerciseTmp = new Exercise($courseId);
7219
                    $objExerciseTmp->read($item_id);
7220
                    if ('visible' == $visibility) {
7221
                        $objExerciseTmp->enable();
7222
                        $objExerciseTmp->save();
7223
                    } else {
7224
                        $objExerciseTmp->disable();
7225
                        $objExerciseTmp->save();
7226
                    }
7227
                }
7228
                break;
7229
        }
7230
    }
7231
}
7232
7233
/**
7234
 * @return string
7235
 */
7236
function api_get_security_key()
7237
{
7238
    return api_get_configuration_value('security_key');
0 ignored issues
show
Bug Best Practice introduced by
The expression return api_get_configura...n_value('security_key') also could return the type boolean which is incompatible with the documented return type string.
Loading history...
7239
}
7240
7241
/**
7242
 * @param int $user_id
7243
 * @param int $courseId
7244
 * @param int $session_id
7245
 *
7246
 * @return array
7247
 */
7248
function api_detect_user_roles($user_id, $courseId, $session_id = 0)
7249
{
7250
    $user_roles = [];
7251
    $courseInfo = api_get_course_info_by_id($courseId);
7252
    $course_code = $courseInfo['code'];
7253
7254
    $url_id = api_get_current_access_url_id();
7255
    if (api_is_platform_admin_by_id($user_id, $url_id)) {
7256
        $user_roles[] = PLATFORM_ADMIN;
7257
    }
7258
7259
    /*if (api_is_drh()) {
7260
        $user_roles[] = DRH;
7261
    }*/
7262
7263
    if (!empty($session_id)) {
7264
        if (SessionManager::user_is_general_coach($user_id, $session_id)) {
7265
            $user_roles[] = SESSION_GENERAL_COACH;
7266
        }
7267
    }
7268
7269
    if (!empty($course_code)) {
7270
        if (empty($session_id)) {
7271
            if (CourseManager::is_course_teacher($user_id, $course_code)) {
7272
                $user_roles[] = COURSEMANAGER;
7273
            }
7274
            if (CourseManager::get_tutor_in_course_status($user_id, $courseInfo['real_id'])) {
7275
                $user_roles[] = COURSE_TUTOR;
7276
            }
7277
7278
            if (CourseManager::is_user_subscribed_in_course($user_id, $course_code)) {
7279
                $user_roles[] = COURSE_STUDENT;
7280
            }
7281
        } else {
7282
            $user_status_in_session = SessionManager::get_user_status_in_course_session(
7283
                $user_id,
7284
                $courseId,
7285
                $session_id
7286
            );
7287
7288
            if (!empty($user_status_in_session)) {
7289
                if (0 == $user_status_in_session) {
7290
                    $user_roles[] = SESSION_STUDENT;
7291
                }
7292
                if (2 == $user_status_in_session) {
7293
                    $user_roles[] = SESSION_COURSE_COACH;
7294
                }
7295
            }
7296
7297
            /*if (api_is_course_session_coach($user_id, $course_code, $session_id)) {
7298
               $user_roles[] = SESSION_COURSE_COACH;
7299
            }*/
7300
        }
7301
    }
7302
7303
    return $user_roles;
7304
}
7305
7306
/**
7307
 * @param int $courseId
7308
 * @param int $session_id
7309
 *
7310
 * @return bool
7311
 */
7312
function api_coach_can_edit_view_results($courseId = null, $session_id = null)
7313
{
7314
    if (api_is_platform_admin()) {
7315
        return true;
7316
    }
7317
7318
    $user_id = api_get_user_id();
7319
7320
    if (empty($courseId)) {
7321
        $courseId = api_get_course_int_id();
7322
    }
7323
7324
    if (empty($session_id)) {
7325
        $session_id = api_get_session_id();
7326
    }
7327
7328
    $roles = api_detect_user_roles($user_id, $courseId, $session_id);
7329
7330
    if (in_array(SESSION_COURSE_COACH, $roles)) {
7331
        //return api_get_setting('session_tutor_reports_visibility') == 'true';
7332
        return true;
7333
    } else {
7334
        if (in_array(COURSEMANAGER, $roles)) {
7335
            return true;
7336
        }
7337
7338
        return false;
7339
    }
7340
}
7341
7342
/**
7343
 * @param string $file
7344
 *
7345
 * @return string
7346
 */
7347
function api_get_js_simple($file)
7348
{
7349
    return '<script type="text/javascript" src="'.$file.'"></script>'."\n";
7350
}
7351
7352
/**
7353
 * Modify default memory_limit and max_execution_time limits
7354
 * Needed when processing long tasks.
7355
 */
7356
function api_set_more_memory_and_time_limits()
7357
{
7358
    if (function_exists('ini_set')) {
7359
        api_set_memory_limit('256M');
7360
        ini_set('max_execution_time', 1800);
7361
    }
7362
}
7363
7364
/**
7365
 * Tries to set memory limit, if authorized and new limit is higher than current.
7366
 *
7367
 * @param string $mem New memory limit
7368
 *
7369
 * @return bool True on success, false on failure or current is higher than suggested
7370
 * @assert (null) === false
7371
 * @assert (-1) === false
7372
 * @assert (0) === true
7373
 * @assert ('1G') === true
7374
 */
7375
function api_set_memory_limit($mem)
7376
{
7377
    //if ini_set() not available, this function is useless
7378
    if (!function_exists('ini_set') || is_null($mem) || -1 == $mem) {
7379
        return false;
7380
    }
7381
7382
    $memory_limit = ini_get('memory_limit');
7383
    if (api_get_bytes_memory_limit($mem) > api_get_bytes_memory_limit($memory_limit)) {
7384
        ini_set('memory_limit', $mem);
7385
7386
        return true;
7387
    }
7388
7389
    return false;
7390
}
7391
7392
/**
7393
 * Gets memory limit in bytes.
7394
 *
7395
 * @param string The memory size (128M, 1G, 1000K, etc)
7396
 *
7397
 * @return int
7398
 * @assert (null) === false
7399
 * @assert ('1t')  === 1099511627776
7400
 * @assert ('1g')  === 1073741824
7401
 * @assert ('1m')  === 1048576
7402
 * @assert ('100k') === 102400
7403
 */
7404
function api_get_bytes_memory_limit($mem)
7405
{
7406
    $size = strtolower(substr($mem, -1));
7407
7408
    switch ($size) {
7409
        case 't':
7410
            $mem = intval(substr($mem, -1)) * 1024 * 1024 * 1024 * 1024;
7411
            break;
7412
        case 'g':
7413
            $mem = intval(substr($mem, 0, -1)) * 1024 * 1024 * 1024;
7414
            break;
7415
        case 'm':
7416
            $mem = intval(substr($mem, 0, -1)) * 1024 * 1024;
7417
            break;
7418
        case 'k':
7419
            $mem = intval(substr($mem, 0, -1)) * 1024;
7420
            break;
7421
        default:
7422
            // we assume it's integer only
7423
            $mem = intval($mem);
7424
            break;
7425
    }
7426
7427
    return $mem;
7428
}
7429
7430
/**
7431
 * Finds all the information about a user from username instead of user id.
7432
 *
7433
 * @param string $officialCode
7434
 *
7435
 * @return array $user_info user_id, lastname, firstname, username, email, ...
7436
 *
7437
 * @author Yannick Warnier <[email protected]>
7438
 */
7439
function api_get_user_info_from_official_code($officialCode)
7440
{
7441
    if (empty($officialCode)) {
7442
        return false;
7443
    }
7444
    $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_USER)."
7445
            WHERE official_code ='".Database::escape_string($officialCode)."'";
7446
    $result = Database::query($sql);
7447
    if (Database::num_rows($result) > 0) {
7448
        $result_array = Database::fetch_array($result);
7449
7450
        return _api_format_user($result_array);
7451
    }
7452
7453
    return false;
7454
}
7455
7456
/**
7457
 * @param string $usernameInputId
7458
 * @param string $passwordInputId
7459
 *
7460
 * @return string|null
7461
 */
7462
function api_get_password_checker_js($usernameInputId, $passwordInputId)
7463
{
7464
    $checkPass = api_get_setting('allow_strength_pass_checker');
7465
    $useStrengthPassChecker = 'true' === $checkPass;
7466
7467
    if (false === $useStrengthPassChecker) {
7468
        return null;
7469
    }
7470
7471
    $translations = [
7472
        'wordLength' => get_lang('The password is too short'),
7473
        'wordNotEmail' => get_lang('Your password cannot be the same as your email'),
7474
        'wordSimilarToUsername' => get_lang('Your password cannot contain your username'),
7475
        'wordTwoCharacterClasses' => get_lang('Use different character classes'),
7476
        'wordRepetitions' => get_lang('Too many repetitions'),
7477
        'wordSequences' => get_lang('Your password contains sequences'),
7478
        'errorList' => get_lang('errors found'),
7479
        'veryWeak' => get_lang('Very weak'),
7480
        'weak' => get_lang('Weak'),
7481
        'normal' => get_lang('Normal'),
7482
        'medium' => get_lang('Medium'),
7483
        'strong' => get_lang('Strong'),
7484
        'veryStrong' => get_lang('Very strong'),
7485
    ];
7486
7487
    $js = api_get_asset('pwstrength-bootstrap/dist/pwstrength-bootstrap.min.js');
7488
    $js .= "<script>
7489
    var errorMessages = {
7490
        password_to_short : \"".get_lang('The password is too short')."\",
7491
        same_as_username : \"".get_lang('Your password cannot be the same as your username')."\"
7492
    };
7493
7494
    $(function() {
7495
        var lang = ".json_encode($translations).";
7496
        var options = {
7497
            onLoad : function () {
7498
                //$('#messages').text('Start typing password');
7499
            },
7500
            onKeyUp: function (evt) {
7501
                $(evt.target).pwstrength('outputErrorList');
7502
            },
7503
            errorMessages : errorMessages,
7504
            viewports: {
7505
                progress: '#password_progress',
7506
                verdict: '#password-verdict',
7507
                errors: '#password-errors'
7508
            },
7509
            usernameField: '$usernameInputId'
7510
        };
7511
        options.i18n = {
7512
            t: function (key) {
7513
                var result = lang[key];
7514
                return result === key ? '' : result; // This assumes you return the
7515
            }
7516
        };
7517
        $('".$passwordInputId."').pwstrength(options);
7518
    });
7519
    </script>";
7520
7521
    return $js;
7522
}
7523
7524
/**
7525
 * create an user extra field called 'captcha_blocked_until_date'.
7526
 *
7527
 * @param string $username
7528
 *
7529
 * @return bool
7530
 */
7531
function api_block_account_captcha($username)
7532
{
7533
    $userInfo = api_get_user_info_from_username($username);
7534
    if (empty($userInfo)) {
7535
        return false;
7536
    }
7537
    $minutesToBlock = api_get_setting('captcha_time_to_block');
7538
    $time = time() + $minutesToBlock * 60;
7539
    UserManager::update_extra_field_value(
7540
        $userInfo['user_id'],
7541
        'captcha_blocked_until_date',
7542
        api_get_utc_datetime($time)
7543
    );
7544
7545
    return true;
7546
}
7547
7548
/**
7549
 * @param string $username
7550
 *
7551
 * @return bool
7552
 */
7553
function api_clean_account_captcha($username)
7554
{
7555
    $userInfo = api_get_user_info_from_username($username);
7556
    if (empty($userInfo)) {
7557
        return false;
7558
    }
7559
    Session::erase('loginFailedCount');
7560
    UserManager::update_extra_field_value(
7561
        $userInfo['user_id'],
7562
        'captcha_blocked_until_date',
7563
        null
7564
    );
7565
7566
    return true;
7567
}
7568
7569
/**
7570
 * @param string $username
7571
 *
7572
 * @return bool
7573
 */
7574
function api_get_user_blocked_by_captcha($username)
7575
{
7576
    $userInfo = api_get_user_info_from_username($username);
7577
    if (empty($userInfo)) {
7578
        return false;
7579
    }
7580
    $data = UserManager::get_extra_user_data_by_field(
7581
        $userInfo['user_id'],
7582
        'captcha_blocked_until_date'
7583
    );
7584
    if (isset($data) && isset($data['captcha_blocked_until_date'])) {
7585
        return $data['captcha_blocked_until_date'];
7586
    }
7587
7588
    return false;
7589
}
7590
7591
/**
7592
 * Remove tags from HTML anf return the $in_number_char first non-HTML char
7593
 * Postfix the text with "..." if it has been truncated.
7594
 *
7595
 * @param string $text
7596
 * @param int    $number
7597
 *
7598
 * @return string
7599
 *
7600
 * @author hubert borderiou
7601
 */
7602
function api_get_short_text_from_html($text, $number)
7603
{
7604
    // Delete script and style tags
7605
    $text = preg_replace('/(<(script|style)\b[^>]*>).*?(<\/\2>)/is', "$1$3", $text);
7606
    $text = api_html_entity_decode($text);
7607
    $out_res = api_remove_tags_with_space($text, false);
7608
    $postfix = "...";
7609
    if (strlen($out_res) > $number) {
7610
        $out_res = substr($out_res, 0, $number).$postfix;
7611
    }
7612
7613
    return $out_res;
7614
}
7615
7616
/**
7617
 * Replace tags with a space in a text.
7618
 * If $in_double_quote_replace, replace " with '' (for HTML attribute purpose, for exemple).
7619
 *
7620
 * @return string
7621
 *
7622
 * @author hubert borderiou
7623
 */
7624
function api_remove_tags_with_space($in_html, $in_double_quote_replace = true)
7625
{
7626
    $out_res = $in_html;
7627
    if ($in_double_quote_replace) {
7628
        $out_res = str_replace('"', "''", $out_res);
7629
    }
7630
    // avoid text stuck together when tags are removed, adding a space after >
7631
    $out_res = str_replace(">", "> ", $out_res);
7632
    $out_res = strip_tags($out_res);
7633
7634
    return $out_res;
7635
}
7636
7637
/**
7638
 * If true, the drh can access all content (courses, users) inside a session.
7639
 *
7640
 * @return bool
7641
 */
7642
function api_drh_can_access_all_session_content()
7643
{
7644
    return api_get_setting('drh_can_access_all_session_content') === 'true';
7645
}
7646
7647
/**
7648
 * @param string $tool
7649
 * @param string $setting
7650
 * @param int    $defaultValue
7651
 *
7652
 * @return string
7653
 */
7654
function api_get_default_tool_setting($tool, $setting, $defaultValue)
7655
{
7656
    global $_configuration;
7657
    if (isset($_configuration[$tool]) &&
7658
        isset($_configuration[$tool]['default_settings']) &&
7659
        isset($_configuration[$tool]['default_settings'][$setting])
7660
    ) {
7661
        return $_configuration[$tool]['default_settings'][$setting];
7662
    }
7663
7664
    return $defaultValue;
7665
}
7666
7667
/**
7668
 * Checks if user can login as another user.
7669
 *
7670
 * @param int $loginAsUserId the user id to log in
7671
 * @param int $userId        my user id
7672
 *
7673
 * @return bool
7674
 */
7675
function api_can_login_as($loginAsUserId, $userId = null)
7676
{
7677
    if (empty($userId)) {
7678
        $userId = api_get_user_id();
7679
    }
7680
    if ($loginAsUserId == $userId) {
7681
        return false;
7682
    }
7683
7684
    if (empty($loginAsUserId)) {
7685
        return false;
7686
    }
7687
7688
    if ($loginAsUserId != strval(intval($loginAsUserId))) {
7689
        return false;
7690
    }
7691
7692
    // Check if the user to login is an admin
7693
    if (api_is_platform_admin_by_id($loginAsUserId)) {
7694
        // Only super admins can login to admin accounts
7695
        if (!api_global_admin_can_edit_admin($loginAsUserId)) {
7696
            return false;
7697
        }
7698
    }
7699
7700
    $userInfo = api_get_user_info($loginAsUserId);
7701
    $isDrh = function () use ($loginAsUserId) {
7702
        if (api_is_drh()) {
7703
            if (api_drh_can_access_all_session_content()) {
7704
                $users = SessionManager::getAllUsersFromCoursesFromAllSessionFromStatus(
7705
                    'drh_all',
7706
                    api_get_user_id()
7707
                );
7708
                $userList = [];
7709
                if (is_array($users)) {
7710
                    foreach ($users as $user) {
7711
                        $userList[] = $user['user_id'];
7712
                    }
7713
                }
7714
                if (in_array($loginAsUserId, $userList)) {
7715
                    return true;
7716
                }
7717
            } else {
7718
                if (api_is_drh() &&
7719
                    UserManager::is_user_followed_by_drh($loginAsUserId, api_get_user_id())
7720
                ) {
7721
                    return true;
7722
                }
7723
            }
7724
        }
7725
7726
        return false;
7727
    };
7728
7729
    $loginAsStatusForSessionAdmins = [STUDENT];
7730
7731
    if (api_get_setting('session.allow_session_admin_login_as_teacher')) {
7732
        $loginAsStatusForSessionAdmins[] = COURSEMANAGER;
7733
    }
7734
7735
    return api_is_platform_admin() ||
7736
        (api_is_session_admin() && in_array($userInfo['status'], $loginAsStatusForSessionAdmins)) ||
7737
        $isDrh();
7738
}
7739
7740
/**
7741
 * @return bool
7742
 */
7743
function api_is_allowed_in_course()
7744
{
7745
    if (api_is_platform_admin()) {
7746
        return true;
7747
    }
7748
7749
    $user = api_get_current_user();
7750
    if ($user instanceof User) {
7751
        if ($user->hasRole('ROLE_CURRENT_SESSION_COURSE_STUDENT') ||
7752
            $user->hasRole('ROLE_CURRENT_SESSION_COURSE_TEACHER') ||
7753
            $user->hasRole('ROLE_CURRENT_COURSE_STUDENT') ||
7754
            $user->hasRole('ROLE_CURRENT_COURSE_TEACHER')
7755
        ) {
7756
            return true;
7757
        }
7758
    }
7759
7760
    return false;
7761
}
7762
7763
/**
7764
 * Set the cookie to go directly to the course code $in_firstpage
7765
 * after login.
7766
 *
7767
 * @param string $value is the course code of the course to go
7768
 */
7769
function api_set_firstpage_parameter($value)
7770
{
7771
    setcookie('GotoCourse', $value);
7772
}
7773
7774
/**
7775
 * Delete the cookie to go directly to the course code $in_firstpage
7776
 * after login.
7777
 */
7778
function api_delete_firstpage_parameter()
7779
{
7780
    setcookie('GotoCourse', '', time() - 3600);
7781
}
7782
7783
/**
7784
 * @return bool if course_code for direct course access after login is set
7785
 */
7786
function exist_firstpage_parameter()
7787
{
7788
    return isset($_COOKIE['GotoCourse']) && '' != $_COOKIE['GotoCourse'];
7789
}
7790
7791
/**
7792
 * @return return the course_code of the course where user login
7793
 */
7794
function api_get_firstpage_parameter()
7795
{
7796
    return $_COOKIE['GotoCourse'];
7797
}
7798
7799
/**
7800
 * Return true on https install.
7801
 *
7802
 * @return bool
7803
 */
7804
function api_is_https()
7805
{
7806
    if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) &&
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: (! empty($_SERVER['HTTP_...ttps_forwarded_proto']), Probably Intended Meaning: ! empty($_SERVER['HTTP_X...tps_forwarded_proto']))
Loading history...
7807
        'https' == $_SERVER['HTTP_X_FORWARDED_PROTO'] || !empty($_configuration['force_https_forwarded_proto'])
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $_configuration seems to never exist and therefore empty should always be true.
Loading history...
7808
    ) {
7809
        $isSecured = true;
7810
    } else {
7811
        if (!empty($_SERVER['HTTPS']) && 'off' != $_SERVER['HTTPS']) {
7812
            $isSecured = true;
7813
        } else {
7814
            $isSecured = false;
7815
            // last chance
7816
            if (!empty($_SERVER['SERVER_PORT']) && 443 == $_SERVER['SERVER_PORT']) {
7817
                $isSecured = true;
7818
            }
7819
        }
7820
    }
7821
7822
    return $isSecured;
7823
}
7824
7825
/**
7826
 * Return protocol (http or https).
7827
 *
7828
 * @return string
7829
 */
7830
function api_get_protocol()
7831
{
7832
    return api_is_https() ? 'https' : 'http';
7833
}
7834
7835
/**
7836
 * Return a string where " are replaced with 2 '
7837
 * It is useful when you pass a PHP variable in a Javascript browser dialog
7838
 * e.g. : alert("<?php get_lang('Message') ?>");
7839
 * and message contains character ".
7840
 *
7841
 * @param string $in_text
7842
 *
7843
 * @return string
7844
 */
7845
function convert_double_quote_to_single($in_text)
7846
{
7847
    return api_preg_replace('/"/', "''", $in_text);
7848
}
7849
7850
/**
7851
 * Get origin.
7852
 *
7853
 * @param string
7854
 *
7855
 * @return string
7856
 */
7857
function api_get_origin()
7858
{
7859
    return isset($_REQUEST['origin']) ? Security::remove_XSS($_REQUEST['origin']) : '';
7860
}
7861
7862
/**
7863
 * Warns an user that the portal reach certain limit.
7864
 *
7865
 * @param string $limitName
7866
 */
7867
function api_warn_hosting_contact($limitName)
7868
{
7869
    $hostingParams = api_get_configuration_value(1);
7870
    $email = null;
7871
7872
    if (!empty($hostingParams)) {
7873
        if (isset($hostingParams['hosting_contact_mail'])) {
7874
            $email = $hostingParams['hosting_contact_mail'];
7875
        }
7876
    }
7877
7878
    if (!empty($email)) {
7879
        $subject = get_lang('Hosting warning reached');
7880
        $body = get_lang('Portal name').': '.api_get_path(WEB_PATH)." \n ";
7881
        $body .= get_lang('Portal\'s limit type').': '.$limitName." \n ";
7882
        if (isset($hostingParams[$limitName])) {
7883
            $body .= get_lang('Value').': '.$hostingParams[$limitName];
7884
        }
7885
        api_mail_html(null, $email, $subject, $body);
7886
    }
7887
}
7888
7889
/**
7890
 * Gets value of a variable from config/configuration.php
7891
 * Variables that are not set in the configuration.php file but set elsewhere:
7892
 * - virtual_css_theme_folder (vchamilo plugin)
7893
 * - access_url (global.inc.php)
7894
 * - apc/apc_prefix (global.inc.php).
7895
 *
7896
 * @param string $variable
7897
 *
7898
 * @return bool|mixed
7899
 */
7900
function api_get_configuration_value($variable)
7901
{
7902
    global $_configuration;
7903
    // Check the current url id, id = 1 by default
7904
    $urlId = isset($_configuration['access_url']) ? (int) $_configuration['access_url'] : 1;
7905
7906
    $variable = trim($variable);
7907
7908
    // Check if variable exists
7909
    if (isset($_configuration[$variable])) {
7910
        if (is_array($_configuration[$variable])) {
7911
            // Check if it exists for the sub portal
7912
            if (array_key_exists($urlId, $_configuration[$variable])) {
7913
                return $_configuration[$variable][$urlId];
7914
            } else {
7915
                // Try to found element with id = 1 (master portal)
7916
                if (array_key_exists(1, $_configuration[$variable])) {
7917
                    return $_configuration[$variable][1];
7918
                }
7919
            }
7920
        }
7921
7922
        return $_configuration[$variable];
7923
    }
7924
7925
    return false;
7926
}
7927
7928
/**
7929
 * Retreives and returns a value in a hierarchical configuration array
7930
 * api_get_configuration_sub_value('a/b/c') returns api_get_configuration_value('a')['b']['c'].
7931
 *
7932
 * @param string $path      the successive array keys, separated by the separator
7933
 * @param mixed  $default   value to be returned if not found, null by default
7934
 * @param string $separator '/' by default
7935
 * @param array  $array     the active configuration array by default
7936
 *
7937
 * @return mixed the found value or $default
7938
 */
7939
function api_get_configuration_sub_value($path, $default = null, $separator = '/', $array = null)
7940
{
7941
    $pos = strpos($path, $separator);
7942
    if (false === $pos) {
7943
        if (is_null($array)) {
7944
            return api_get_configuration_value($path);
7945
        }
7946
        if (is_array($array) && array_key_exists($path, $array)) {
7947
            return $array[$path];
7948
        }
7949
7950
        return $default;
7951
    }
7952
    $key = substr($path, 0, $pos);
7953
    if (is_null($array)) {
7954
        $newArray = api_get_configuration_value($key);
7955
    } elseif (is_array($array) && array_key_exists($key, $array)) {
7956
        $newArray = $array[$key];
7957
    } else {
7958
        return $default;
7959
    }
7960
    if (is_array($newArray)) {
7961
        $newPath = substr($path, $pos + 1);
7962
7963
        return api_get_configuration_sub_value($newPath, $default, $separator, $newArray);
7964
    }
7965
7966
    return $default;
7967
}
7968
7969
/**
7970
 * Retrieves and returns a value in a hierarchical configuration array
7971
 * api_array_sub_value($array, 'a/b/c') returns $array['a']['b']['c'].
7972
 *
7973
 * @param array  $array     the recursive array that contains the value to be returned (or not)
7974
 * @param string $path      the successive array keys, separated by the separator
7975
 * @param mixed  $default   the value to be returned if not found
7976
 * @param string $separator the separator substring
7977
 *
7978
 * @return mixed the found value or $default
7979
 */
7980
function api_array_sub_value($array, $path, $default = null, $separator = '/')
7981
{
7982
    $pos = strpos($path, $separator);
7983
    if (false === $pos) {
7984
        if (is_array($array) && array_key_exists($path, $array)) {
7985
            return $array[$path];
7986
        }
7987
7988
        return $default;
7989
    }
7990
    $key = substr($path, 0, $pos);
7991
    if (is_array($array) && array_key_exists($key, $array)) {
7992
        $newArray = $array[$key];
7993
    } else {
7994
        return $default;
7995
    }
7996
    if (is_array($newArray)) {
7997
        $newPath = substr($path, $pos + 1);
7998
7999
        return api_array_sub_value($newArray, $newPath, $default);
8000
    }
8001
8002
    return $default;
8003
}
8004
8005
/**
8006
 * Returns supported image extensions in the portal.
8007
 *
8008
 * @param bool $supportVectors Whether vector images should also be accepted or not
8009
 *
8010
 * @return array Supported image extensions in the portal
8011
 */
8012
function api_get_supported_image_extensions($supportVectors = true)
8013
{
8014
    // jpg can also be called jpeg, jpe, jfif and jif. See https://en.wikipedia.org/wiki/JPEG#JPEG_filename_extensions
8015
    $supportedImageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'jpe', 'jfif', 'jif'];
8016
    if ($supportVectors) {
8017
        array_push($supportedImageExtensions, 'svg');
8018
    }
8019
    if (version_compare(PHP_VERSION, '5.5.0', '>=')) {
8020
        array_push($supportedImageExtensions, 'webp');
8021
    }
8022
8023
    return $supportedImageExtensions;
8024
}
8025
8026
/**
8027
 * This setting changes the registration status for the campus.
8028
 *
8029
 * @author Patrick Cool <[email protected]>, Ghent University
8030
 *
8031
 * @version August 2006
8032
 *
8033
 * @param bool $listCampus Whether we authorize
8034
 *
8035
 * @todo the $_settings should be reloaded here. => write api function for this and use this in global.inc.php also.
8036
 */
8037
function api_register_campus($listCampus = true)
8038
{
8039
    $tbl_settings = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
8040
8041
    $sql = "UPDATE $tbl_settings SET selected_value='true' WHERE variable='registered'";
8042
    Database::query($sql);
8043
8044
    if (!$listCampus) {
8045
        $sql = "UPDATE $tbl_settings SET selected_value='true' WHERE variable='donotlistcampus'";
8046
        Database::query($sql);
8047
    }
8048
}
8049
8050
/**
8051
 * Checks whether current user is a student boss.
8052
 *
8053
 * @global array $_user
8054
 *
8055
 * @return bool
8056
 */
8057
function api_is_student_boss()
8058
{
8059
    $_user = api_get_user_info();
8060
8061
    return isset($_user['status']) && STUDENT_BOSS == $_user['status'];
8062
}
8063
8064
/**
8065
 * Check whether the user type should be exclude.
8066
 * Such as invited or anonymous users.
8067
 *
8068
 * @param bool $checkDB Optional. Whether check the user status
8069
 * @param int  $userId  Options. The user id
8070
 *
8071
 * @return bool
8072
 */
8073
function api_is_excluded_user_type($checkDB = false, $userId = 0)
8074
{
8075
    if ($checkDB) {
8076
        $userId = empty($userId) ? api_get_user_id() : (int) $userId;
8077
8078
        if (0 == $userId) {
8079
            return true;
8080
        }
8081
8082
        $userInfo = api_get_user_info($userId);
8083
8084
        switch ($userInfo['status']) {
8085
            case INVITEE:
8086
            case ANONYMOUS:
8087
                return true;
8088
            default:
8089
                return false;
8090
        }
8091
    }
8092
8093
    $isInvited = api_is_invitee();
8094
    $isAnonymous = api_is_anonymous();
8095
8096
    if ($isInvited || $isAnonymous) {
8097
        return true;
8098
    }
8099
8100
    return false;
8101
}
8102
8103
/**
8104
 * Get the user status to ignore in reports.
8105
 *
8106
 * @param string $format Optional. The result type (array or string)
8107
 *
8108
 * @return array|string
8109
 */
8110
function api_get_users_status_ignored_in_reports($format = 'array')
8111
{
8112
    $excludedTypes = [
8113
        INVITEE,
8114
        ANONYMOUS,
8115
    ];
8116
8117
    if ('string' == $format) {
8118
        return implode(', ', $excludedTypes);
8119
    }
8120
8121
    return $excludedTypes;
8122
}
8123
8124
/**
8125
 * Set the Site Use Cookie Warning for 1 year.
8126
 */
8127
function api_set_site_use_cookie_warning_cookie()
8128
{
8129
    setcookie('ChamiloUsesCookies', 'ok', time() + 31556926);
8130
}
8131
8132
/**
8133
 * Return true if the Site Use Cookie Warning Cookie warning exists.
8134
 *
8135
 * @return bool
8136
 */
8137
function api_site_use_cookie_warning_cookie_exist()
8138
{
8139
    return isset($_COOKIE['ChamiloUsesCookies']);
8140
}
8141
8142
/**
8143
 * Given a number of seconds, format the time to show hours, minutes and seconds.
8144
 *
8145
 * @param int    $time         The time in seconds
8146
 * @param string $originFormat Optional. PHP o JS
8147
 *
8148
 * @return string (00h00'00")
8149
 */
8150
function api_format_time($time, $originFormat = 'php')
8151
{
8152
    $h = get_lang('h');
8153
    $hours = $time / 3600;
8154
    $mins = ($time % 3600) / 60;
8155
    $secs = ($time % 60);
8156
8157
    if ($time < 0) {
8158
        $hours = 0;
8159
        $mins = 0;
8160
        $secs = 0;
8161
    }
8162
8163
    if ('js' == $originFormat) {
8164
        $formattedTime = trim(sprintf("%02d : %02d : %02d", $hours, $mins, $secs));
8165
    } else {
8166
        $formattedTime = trim(sprintf("%02d$h%02d'%02d\"", $hours, $mins, $secs));
8167
    }
8168
8169
    return $formattedTime;
8170
}
8171
8172
/**
8173
 * Create a new empty directory with index.html file.
8174
 *
8175
 * @param string $name            The new directory name
8176
 * @param string $parentDirectory Directory parent directory name
8177
 *
8178
 * @deprecated use Resources
8179
 *
8180
 * @return bool Return true if the directory was create. Otherwise return false
8181
 */
8182
function api_create_protected_dir($name, $parentDirectory)
8183
{
8184
    $isCreated = false;
8185
8186
    if (!is_writable($parentDirectory)) {
8187
        return false;
8188
    }
8189
8190
    $fullPath = $parentDirectory.api_replace_dangerous_char($name);
8191
8192
    if (mkdir($fullPath, api_get_permissions_for_new_directories(), true)) {
8193
        $fp = fopen($fullPath.'/index.html', 'w');
8194
8195
        if ($fp) {
0 ignored issues
show
introduced by
$fp is of type false|resource, thus it always evaluated to false.
Loading history...
8196
            if (fwrite($fp, '<html><head></head><body></body></html>')) {
8197
                $isCreated = true;
8198
            }
8199
        }
8200
8201
        fclose($fp);
8202
    }
8203
8204
    return $isCreated;
8205
}
8206
8207
/**
8208
 * Sends an email
8209
 * Sender name and email can be specified, if not specified
8210
 * name and email of the platform admin are used.
8211
 *
8212
 * @param string    name of recipient
8213
 * @param string    email of recipient
8214
 * @param string    email subject
8215
 * @param string    email body
8216
 * @param string    sender name
8217
 * @param string    sender e-mail
8218
 * @param array     extra headers in form $headers = array($name => $value) to allow parsing
8219
 * @param array     data file (path and filename)
8220
 * @param bool      True for attaching a embedded file inside content html (optional)
8221
 * @param array     Additional parameters
8222
 *
8223
 * @return bool true if mail was sent
8224
 */
8225
function api_mail_html(
8226
    $recipientName,
8227
    $recipientEmail,
8228
    $subject,
8229
    $body,
8230
    $senderName = '',
8231
    $senderEmail = '',
8232
    $extra_headers = [],
8233
    $data_file = [],
8234
    $embeddedImage = false,
8235
    $additionalParameters = []
8236
) {
8237
    if (!api_valid_email($recipientEmail)) {
8238
        return false;
8239
    }
8240
8241
    // Default values
8242
    $notification = new Notification();
8243
    $defaultEmail = $notification->getDefaultPlatformSenderEmail();
8244
    $defaultName = $notification->getDefaultPlatformSenderName();
8245
8246
    // If the parameter is set don't use the admin.
8247
    $senderName = !empty($senderName) ? $senderName : $defaultName;
8248
    $senderEmail = !empty($senderEmail) ? $senderEmail : $defaultEmail;
8249
8250
    // Reply to first
8251
    $replyToName = '';
8252
    $replyToEmail = '';
8253
    if (isset($extra_headers['reply_to'])) {
8254
        $replyToEmail = $extra_headers['reply_to']['mail'];
8255
        $replyToName = $extra_headers['reply_to']['name'];
8256
    }
8257
8258
    try {
8259
        $message = new TemplatedEmail();
8260
        $message->subject($subject);
8261
8262
        $list = api_get_configuration_value('send_all_emails_to');
8263
        if (!empty($list) && isset($list['emails'])) {
8264
            foreach ($list['emails'] as $email) {
8265
                $message->cc($email);
8266
            }
8267
        }
8268
8269
        // Attachment
8270
        if (!empty($data_file)) {
8271
            foreach ($data_file as $file_attach) {
8272
                if (!empty($file_attach['path']) && !empty($file_attach['filename'])) {
8273
                    $message->attachFromPath($file_attach['path'], $file_attach['filename']);
8274
                }
8275
            }
8276
        }
8277
8278
        $noReply = api_get_setting('noreply_email_address');
8279
        $automaticEmailText = '';
8280
        if (!empty($noReply)) {
8281
            $automaticEmailText = '<br />'.get_lang('This is an automatic email message. Please do not reply to it.');
8282
        }
8283
8284
        $params = [
8285
            'mail_header_style' => api_get_configuration_value('mail_header_style'),
8286
            'mail_content_style' => api_get_configuration_value('mail_content_style'),
8287
            'link' => $additionalParameters['link'] ?? '',
8288
            'automatic_email_text' => $automaticEmailText,
8289
            'content' => $body,
8290
            'theme' => api_get_visual_theme(),
8291
        ];
8292
8293
        if (!empty($senderEmail)) {
8294
            $message->from(new Address($senderEmail, $senderName));
8295
        }
8296
8297
        if (!empty($recipientEmail)) {
8298
            $message->to(new Address($recipientEmail, $recipientName));
8299
        }
8300
8301
        if (!empty($replyToEmail)) {
8302
            $message->replyTo(new Address($replyToEmail, $replyToName));
8303
        }
8304
8305
        $message
8306
            ->htmlTemplate('ChamiloCoreBundle:Mailer:Default/default.html.twig')
8307
            ->textTemplate('ChamiloCoreBundle:Mailer:Default/default.text.twig')
8308
        ;
8309
        $message->context($params);
8310
        Container::getMailer()->send($message);
8311
8312
        return true;
8313
    } catch (Exception $e) {
8314
        error_log($e->getMessage());
8315
    }
8316
8317
    if (!empty($additionalParameters)) {
8318
        $plugin = new AppPlugin();
8319
        $smsPlugin = $plugin->getSMSPluginLibrary();
8320
        if ($smsPlugin) {
0 ignored issues
show
introduced by
$smsPlugin is of type SmsPluginLibraryInterface, thus it always evaluated to true.
Loading history...
8321
            $smsPlugin->send($additionalParameters);
8322
        }
8323
    }
8324
8325
    return 1;
8326
}
8327
8328
/**
8329
 * @param string $tool       Possible values: GroupManager::GROUP_TOOL_*
8330
 * @param bool   $showHeader
8331
 */
8332
function api_protect_course_group($tool, $showHeader = true)
8333
{
8334
    $groupId = api_get_group_id();
8335
    if (!empty($groupId)) {
8336
        if (api_is_platform_admin()) {
8337
            return true;
8338
        }
8339
8340
        if (api_is_allowed_to_edit(false, true, true)) {
8341
            return true;
8342
        }
8343
8344
        $userId = api_get_user_id();
8345
        $sessionId = api_get_session_id();
8346
        if (!empty($sessionId)) {
8347
            if (api_is_coach($sessionId, api_get_course_int_id())) {
8348
                return true;
8349
            }
8350
8351
            if (api_is_drh()) {
8352
                if (SessionManager::isUserSubscribedAsHRM($sessionId, $userId)) {
8353
                    return true;
8354
                }
8355
            }
8356
        }
8357
8358
        $groupInfo = GroupManager::get_group_properties($groupId);
8359
8360
        // Group doesn't exists
8361
        if (empty($groupInfo)) {
8362
            api_not_allowed($showHeader);
8363
        }
8364
8365
        // Check group access
8366
        $allow = GroupManager::user_has_access(
8367
            $userId,
8368
            $groupInfo['iid'],
8369
            $tool
8370
        );
8371
8372
        if (!$allow) {
8373
            api_not_allowed($showHeader);
8374
        }
8375
    }
8376
8377
    return false;
8378
}
8379
8380
/**
8381
 * Check if a date is in a date range.
8382
 *
8383
 * @param datetime $startDate
8384
 * @param datetime $endDate
8385
 * @param datetime $currentDate
8386
 *
8387
 * @return bool true if date is in rage, false otherwise
8388
 */
8389
function api_is_date_in_date_range($startDate, $endDate, $currentDate = null)
8390
{
8391
    $startDate = strtotime(api_get_local_time($startDate));
8392
    $endDate = strtotime(api_get_local_time($endDate));
8393
    $currentDate = strtotime(api_get_local_time($currentDate));
8394
8395
    if ($currentDate >= $startDate && $currentDate <= $endDate) {
8396
        return true;
8397
    }
8398
8399
    return false;
8400
}
8401
8402
/**
8403
 * Eliminate the duplicates of a multidimensional array by sending the key.
8404
 *
8405
 * @param array $array multidimensional array
8406
 * @param int   $key   key to find to compare
8407
 *
8408
 * @return array
8409
 */
8410
function api_unique_multidim_array($array, $key)
8411
{
8412
    $temp_array = [];
8413
    $i = 0;
8414
    $key_array = [];
8415
8416
    foreach ($array as $val) {
8417
        if (!in_array($val[$key], $key_array)) {
8418
            $key_array[$i] = $val[$key];
8419
            $temp_array[$i] = $val;
8420
        }
8421
        $i++;
8422
    }
8423
8424
    return $temp_array;
8425
}
8426
8427
/**
8428
 * Limit the access to Session Admins when the limit_session_admin_role
8429
 * configuration variable is set to true.
8430
 */
8431
function api_protect_limit_for_session_admin()
8432
{
8433
    $limitAdmin = api_get_setting('limit_session_admin_role');
8434
    if (api_is_session_admin() && 'true' === $limitAdmin) {
8435
        api_not_allowed(true);
8436
    }
8437
}
8438
8439
/**
8440
 * Limits that a session admin has access to list users.
8441
 * When limit_session_admin_list_users configuration variable is set to true.
8442
 */
8443
function api_protect_session_admin_list_users()
8444
{
8445
    $limitAdmin = api_get_configuration_value('limit_session_admin_list_users');
8446
8447
    if (api_is_session_admin() && true === $limitAdmin) {
8448
        api_not_allowed(true);
8449
    }
8450
}
8451
8452
/**
8453
 * @return bool
8454
 */
8455
function api_is_student_view_active()
8456
{
8457
    $studentView = Session::read('studentview');
8458
8459
    return 'studentview' === $studentView;
8460
}
8461
8462
/**
8463
 * Adds a file inside the upload/$type/id.
8464
 *
8465
 * @param string $type
8466
 * @param array  $file
8467
 * @param int    $itemId
8468
 * @param string $cropParameters
8469
 *
8470
 * @deprecated use Resources
8471
 *
8472
 * @return array|bool
8473
 */
8474
function api_upload_file($type, $file, $itemId, $cropParameters = '')
8475
{
8476
    $upload = process_uploaded_file($file);
8477
    if ($upload) {
8478
        $name = api_replace_dangerous_char($file['name']);
8479
8480
        // No "dangerous" files
8481
        $name = disable_dangerous_file($name);
8482
8483
        $pathId = '/'.substr((string) $itemId, 0, 1).'/'.$itemId.'/';
8484
        $path = api_get_path(SYS_UPLOAD_PATH).$type.$pathId;
8485
8486
        if (!is_dir($path)) {
8487
            mkdir($path, api_get_permissions_for_new_directories(), true);
8488
        }
8489
8490
        $pathToSave = $path.$name;
8491
        $result = moveUploadedFile($file, $pathToSave);
8492
8493
        if ($result) {
8494
            if (!empty($cropParameters)) {
8495
                $image = new Image($pathToSave);
8496
                $image->crop($cropParameters);
8497
            }
8498
8499
            return ['path_to_save' => $pathId.$name];
8500
        }
8501
    }
8502
8503
    return false;
8504
}
8505
8506
/**
8507
 * @param string $type
8508
 * @param int    $itemId
8509
 * @param string $file
8510
 *
8511
 * @return bool
8512
 */
8513
function api_get_uploaded_web_url($type, $itemId, $file)
8514
{
8515
    return api_get_uploaded_file($type, $itemId, $file, true);
8516
}
8517
8518
/**
8519
 * @param string $type
8520
 * @param int    $itemId
8521
 * @param string $file
8522
 * @param bool   $getUrl
8523
 *
8524
 * @return bool
8525
 */
8526
function api_get_uploaded_file($type, $itemId, $file, $getUrl = false)
8527
{
8528
    $itemId = (int) $itemId;
8529
    $pathId = '/'.substr((string) $itemId, 0, 1).'/'.$itemId.'/';
8530
    $path = api_get_path(SYS_UPLOAD_PATH).$type.$pathId;
8531
    $file = basename($file);
8532
    $file = $path.'/'.$file;
8533
    if (Security::check_abs_path($file, $path) && is_file($file) && file_exists($file)) {
8534
        if ($getUrl) {
8535
            return str_replace(api_get_path(SYS_UPLOAD_PATH), api_get_path(WEB_UPLOAD_PATH), $file);
8536
        }
8537
8538
        return $file;
8539
    }
8540
8541
    return false;
8542
}
8543
8544
/**
8545
 * @param string $type
8546
 * @param int    $itemId
8547
 * @param string $file
8548
 * @param string $title
8549
 */
8550
function api_download_uploaded_file($type, $itemId, $file, $title = '')
8551
{
8552
    $file = api_get_uploaded_file($type, $itemId, $file);
8553
    if ($file) {
8554
        if (Security::check_abs_path($file, api_get_path(SYS_UPLOAD_PATH).$type)) {
8555
            DocumentManager::file_send_for_download($file, true, $title);
8556
            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...
8557
        }
8558
    }
8559
    api_not_allowed(true);
8560
}
8561
8562
/**
8563
 * @param string $type
8564
 * @param string $file
8565
 */
8566
function api_remove_uploaded_file($type, $file)
8567
{
8568
    $typePath = api_get_path(SYS_UPLOAD_PATH).$type;
8569
    $path = $typePath.'/'.$file;
8570
    if (Security::check_abs_path($path, $typePath) && file_exists($path) && is_file($path)) {
8571
        unlink($path);
8572
    }
8573
}
8574
8575
/**
8576
 * @param string $type
8577
 * @param int    $itemId
8578
 * @param string $file
8579
 *
8580
 * @return bool
8581
 */
8582
function api_remove_uploaded_file_by_id($type, $itemId, $file)
8583
{
8584
    $file = api_get_uploaded_file($type, $itemId, $file, false);
8585
    $typePath = api_get_path(SYS_UPLOAD_PATH).$type;
8586
    if (Security::check_abs_path($file, $typePath) && file_exists($file) && is_file($file)) {
8587
        unlink($file);
8588
8589
        return true;
8590
    }
8591
8592
    return false;
8593
}
8594
8595
/**
8596
 * Converts string value to float value.
8597
 *
8598
 * 3.141516 => 3.141516
8599
 * 3,141516 => 3.141516
8600
 *
8601
 * @todo WIP
8602
 *
8603
 * @param string $number
8604
 *
8605
 * @return float
8606
 */
8607
function api_float_val($number)
8608
{
8609
    $number = (float) str_replace(',', '.', trim($number));
8610
8611
    return $number;
8612
}
8613
8614
/**
8615
 * Converts float values
8616
 * Example if $decimals = 2.
8617
 *
8618
 * 3.141516 => 3.14
8619
 * 3,141516 => 3,14
8620
 *
8621
 * @param string $number            number in iso code
8622
 * @param int    $decimals
8623
 * @param string $decimalSeparator
8624
 * @param string $thousandSeparator
8625
 *
8626
 * @return bool|string
8627
 */
8628
function api_number_format($number, $decimals = 0, $decimalSeparator = '.', $thousandSeparator = ',')
8629
{
8630
    $number = api_float_val($number);
8631
8632
    return number_format($number, $decimals, $decimalSeparator, $thousandSeparator);
8633
}
8634
8635
/**
8636
 * Set location url with a exit break by default.
8637
 *
8638
 * @param string $url
8639
 * @param bool $exit
8640
 */
8641
function api_location($url, $exit = true)
8642
{
8643
    header('Location: '.$url);
8644
8645
    if ($exit) {
8646
        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...
8647
    }
8648
}
8649
8650
/**
8651
 * @return string
8652
 */
8653
function api_get_web_url()
8654
{
8655
    if ('test' === api_get_setting('server_type')) {
8656
        return api_get_path(WEB_PATH).'web/app_dev.php/';
8657
    } else {
8658
        return api_get_path(WEB_PATH).'web/';
8659
    }
8660
}
8661
8662
/**
8663
 * @param string $from
8664
 * @param string $to
8665
 *
8666
 * @return string
8667
 */
8668
function api_get_relative_path($from, $to)
8669
{
8670
    // some compatibility fixes for Windows paths
8671
    $from = is_dir($from) ? rtrim($from, '\/').'/' : $from;
8672
    $to = is_dir($to) ? rtrim($to, '\/').'/' : $to;
8673
    $from = str_replace('\\', '/', $from);
8674
    $to = str_replace('\\', '/', $to);
8675
8676
    $from = explode('/', $from);
8677
    $to = explode('/', $to);
8678
    $relPath = $to;
8679
8680
    foreach ($from as $depth => $dir) {
8681
        // find first non-matching dir
8682
        if ($dir === $to[$depth]) {
8683
            // ignore this directory
8684
            array_shift($relPath);
8685
        } else {
8686
            // get number of remaining dirs to $from
8687
            $remaining = count($from) - $depth;
8688
            if ($remaining > 1) {
8689
                // add traversals up to first matching dir
8690
                $padLength = (count($relPath) + $remaining - 1) * -1;
8691
                $relPath = array_pad($relPath, $padLength, '..');
8692
                break;
8693
            } else {
8694
                $relPath[0] = './'.$relPath[0];
8695
            }
8696
        }
8697
    }
8698
8699
    return implode('/', $relPath);
8700
}
8701
8702
/**
8703
 * Unserialize content using Brummann\Polyfill\Unserialize.
8704
 *
8705
 * @param string $type
8706
 * @param string $serialized
8707
 * @param bool   $ignoreErrors. Optional.
8708
 *
8709
 * @return mixed
8710
 */
8711
function api_unserialize_content($type, $serialized, $ignoreErrors = false)
8712
{
8713
    switch ($type) {
8714
        case 'career':
8715
        case 'sequence_graph':
8716
            $allowedClasses = [Graph::class, VerticesMap::class, Vertices::class, Edges::class];
8717
            break;
8718
        case 'lp':
8719
            $allowedClasses = [
8720
                learnpath::class,
8721
                learnpathItem::class,
8722
                aicc::class,
8723
                aiccBlock::class,
8724
                aiccItem::class,
8725
                aiccObjective::class,
8726
                aiccResource::class,
8727
                scorm::class,
8728
                scormItem::class,
8729
                scormMetadata::class,
8730
                scormOrganization::class,
8731
                scormResource::class,
8732
                Link::class,
8733
                LpItem::class,
8734
            ];
8735
            break;
8736
        case 'course':
8737
            $allowedClasses = [
8738
                Course::class,
8739
                Announcement::class,
8740
                Attendance::class,
8741
                CalendarEvent::class,
8742
                CourseCopyLearnpath::class,
8743
                CourseCopyTestCategory::class,
8744
                CourseDescription::class,
8745
                CourseSession::class,
8746
                Document::class,
8747
                Forum::class,
8748
                ForumCategory::class,
8749
                ForumPost::class,
8750
                ForumTopic::class,
8751
                Glossary::class,
8752
                GradeBookBackup::class,
8753
                Link::class,
8754
                LinkCategory::class,
8755
                Quiz::class,
8756
                QuizQuestion::class,
8757
                QuizQuestionOption::class,
8758
                ScormDocument::class,
8759
                Survey::class,
8760
                SurveyInvitation::class,
8761
                SurveyQuestion::class,
8762
                Thematic::class,
8763
                ToolIntro::class,
8764
                Wiki::class,
8765
                Work::class,
8766
                stdClass::class,
8767
            ];
8768
            break;
8769
        case 'not_allowed_classes':
8770
        default:
8771
            $allowedClasses = false;
8772
    }
8773
8774
    if ($ignoreErrors) {
8775
        return @Unserialize::unserialize(
8776
            $serialized,
8777
            ['allowed_classes' => $allowedClasses]
8778
        );
8779
    }
8780
8781
    return Unserialize::unserialize(
8782
        $serialized,
8783
        ['allowed_classes' => $allowedClasses]
8784
    );
8785
}
8786
8787
/**
8788
 * @param string $template
8789
 *
8790
 * @return string
8791
 */
8792
function api_find_template($template)
8793
{
8794
    return Template::findTemplateFilePath($template);
8795
}
8796
8797
/**
8798
 * @return array
8799
 */
8800
function api_get_language_list_for_flag()
8801
{
8802
    $table = Database::get_main_table(TABLE_MAIN_LANGUAGE);
8803
    $sql = "SELECT english_name, isocode FROM $table
8804
            ORDER BY original_name ASC";
8805
    static $languages = [];
8806
    if (empty($languages)) {
8807
        $result = Database::query($sql);
8808
        while ($row = Database::fetch_array($result)) {
8809
            $languages[$row['english_name']] = $row['isocode'];
8810
        }
8811
        $languages['english'] = 'gb';
8812
    }
8813
8814
    return $languages;
8815
}
8816
8817
/**
8818
 * @param string $name
8819
 *
8820
 * @return \ZipStream\ZipStream
8821
 */
8822
function api_create_zip($name)
8823
{
8824
    $zipStreamOptions = new \ZipStream\Option\Archive();
8825
    $zipStreamOptions->setSendHttpHeaders(true);
8826
    $zipStreamOptions->setContentDisposition('attachment');
8827
    $zipStreamOptions->setContentType('application/x-zip');
8828
8829
    $zip = new \ZipStream\ZipStream($name, $zipStreamOptions);
8830
8831
    return $zip;
8832
}
8833
8834
/**
8835
 * @return string
8836
 */
8837
function api_get_language_translate_html()
8838
{
8839
    $translate = api_get_configuration_value('translate_html');
8840
8841
    if (!$translate) {
8842
        return '';
8843
    }
8844
8845
    $languageList = api_get_languages();
8846
    $hideAll = '';
8847
    foreach ($languageList['all'] as $language) {
8848
        $hideAll .= '
8849
        $("span:lang('.$language['isocode'].')").filter(
8850
            function(e, val) {
8851
                // Only find the spans if they have set the lang
8852
                if ($(this).attr("lang") == null) {
8853
                    return false;
8854
                }
8855
8856
                // Ignore ckeditor classes
8857
                return !this.className.match(/cke(.*)/);
8858
        }).hide();'."\n";
8859
    }
8860
8861
    $userInfo = api_get_user_info();
8862
    $languageId = api_get_language_id($userInfo['language']);
8863
    $languageInfo = api_get_language_info($languageId);
8864
    $isoCode = 'en';
8865
8866
    if (!empty($languageInfo)) {
8867
        $isoCode = $languageInfo['isocode'];
8868
    }
8869
8870
    return '
8871
            $(function() {
8872
                '.$hideAll.'
8873
                var defaultLanguageFromUser = "'.$isoCode.'";
8874
8875
                $("span:lang('.$isoCode.')").filter(
8876
                    function() {
8877
                        // Ignore ckeditor classes
8878
                        return !this.className.match(/cke(.*)/);
8879
                }).show();
8880
8881
                var defaultLanguage = "";
8882
                var langFromUserFound = false;
8883
8884
                $(this).find("span").filter(
8885
                    function() {
8886
                        // Ignore ckeditor classes
8887
                        return !this.className.match(/cke(.*)/);
8888
                }).each(function() {
8889
                    defaultLanguage = $(this).attr("lang");
8890
                    if (defaultLanguage) {
8891
                        $(this).before().next("br").remove();
8892
                        if (defaultLanguageFromUser == defaultLanguage) {
8893
                            langFromUserFound = true;
8894
                        }
8895
                    }
8896
                });
8897
8898
                // Show default language
8899
                if (langFromUserFound == false && defaultLanguage) {
8900
                    $("span:lang("+defaultLanguage+")").filter(
8901
                    function() {
8902
                            // Ignore ckeditor classes
8903
                            return !this.className.match(/cke(.*)/);
8904
                    }).show();
8905
                }
8906
            });
8907
    ';
8908
}
8909