Passed
Push — 1.11.x ( 32ddc3...4cbd8d )
by Julito
12:12
created

handlePlugins()   F

Complexity

Conditions 14
Paths 1032

Size

Total Lines 154
Code Lines 107

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 14
eloc 107
c 1
b 0
f 0
nc 1032
nop 0
dl 0
loc 154
rs 1.68

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
/* For licensing terms, see /license.txt */
3
4
use Chamilo\CoreBundle\Component\Utils\ChamiloApi;
5
use Chamilo\CoreBundle\Entity\SystemTemplate;
6
use ChamiloSession as Session;
7
use Symfony\Component\Filesystem\Filesystem;
8
9
/**
10
 * Library of the settings.php file.
11
 *
12
 * @author Julio Montoya <[email protected]>
13
 * @author Guillaume Viguier <[email protected]>
14
 *
15
 * @since Chamilo 1.8.7
16
 */
17
define('CSS_UPLOAD_PATH', api_get_path(SYS_APP_PATH).'Resources/public/css/themes/');
18
19
/**
20
 * This function allows easy activating and inactivating of regions.
21
 *
22
 * @author Julio Montoya <[email protected]> Beeznest 2012
23
 */
24
function handleRegions()
25
{
26
    if (isset($_POST['submit_plugins'])) {
27
        storeRegions();
28
        // Add event to the system log.
29
        $user_id = api_get_user_id();
30
        $category = $_GET['category'];
31
        Event::addEvent(
0 ignored issues
show
Bug introduced by
The method addEvent() does not exist on Event. ( Ignorable by Annotation )

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

31
        Event::/** @scrutinizer ignore-call */ 
32
               addEvent(

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
32
            LOG_CONFIGURATION_SETTINGS_CHANGE,
33
            LOG_CONFIGURATION_SETTINGS_CATEGORY,
34
            $category,
35
            api_get_utc_datetime(),
36
            $user_id
37
        );
38
        echo Display::return_message(get_lang('SettingsStored'), 'confirmation');
39
    }
40
41
    $plugin_obj = new AppPlugin();
42
    $installed_plugins = $plugin_obj->getInstalledPlugins();
43
44
    echo '<form name="plugins" method="post" action="'.api_get_self().'?category='.Security::remove_XSS($_GET['category']).'">';
45
    echo '<table class="data_table">';
46
    echo '<tr>';
47
    echo '<th width="400px">';
48
    echo get_lang('Plugin');
49
    echo '</th><th>';
50
    echo get_lang('Regions');
51
    echo '</th>';
52
    echo '</th>';
53
    echo '</tr>';
54
55
    /* We display all the possible plugins and the checkboxes */
56
    $plugin_region_list = [];
57
    $my_plugin_list = $plugin_obj->get_plugin_regions();
58
    foreach ($my_plugin_list as $plugin_item) {
59
        $plugin_region_list[$plugin_item] = $plugin_item;
60
    }
61
62
    // Removing course tool
63
    unset($plugin_region_list['course_tool_plugin']);
64
65
    foreach ($installed_plugins as $pluginName) {
66
        $plugin_info_file = api_get_path(SYS_PLUGIN_PATH).$pluginName.'/plugin.php';
67
68
        if (file_exists($plugin_info_file)) {
69
            $plugin_info = [];
70
            require $plugin_info_file;
71
            if (isset($_GET['name']) && $_GET['name'] === $pluginName) {
72
                echo '<tr class="row_selected">';
73
            } else {
74
                echo '<tr>';
75
            }
76
            echo '<td>';
77
            echo '<h4>'.$plugin_info['title'].' <small>v'.$plugin_info['version'].'</small></h4>';
78
            echo '<p>'.$plugin_info['comment'].'</p>';
79
            echo '</td><td>';
80
            $selected_plugins = $plugin_obj->get_areas_by_plugin($pluginName);
81
            $region_list = [];
82
            $isAdminPlugin = isset($plugin_info['is_admin_plugin']) && $plugin_info['is_admin_plugin'];
83
            $isCoursePlugin = isset($plugin_info['is_course_plugin']) && $plugin_info['is_course_plugin'];
84
85
            if (!$isAdminPlugin && !$isCoursePlugin) {
86
                $region_list = $plugin_region_list;
87
            } else {
88
                if ($isAdminPlugin) {
89
                    $region_list['menu_administrator'] = 'menu_administrator';
90
                }
91
                if ($isCoursePlugin) {
92
                    $region_list['course_tool_plugin'] = 'course_tool_plugin';
93
                }
94
            }
95
96
            echo Display::select(
97
                'plugin_'.$pluginName.'[]',
98
                $region_list,
99
                $selected_plugins,
100
                ['multiple' => 'multiple', 'style' => 'width:500px'],
101
                true,
102
                get_lang('None')
103
            );
104
            echo '</td></tr>';
105
        }
106
    }
107
    echo '</table>';
108
    echo '<br />';
109
    echo '<button class="btn btn-success" type="submit" name="submit_plugins">'.get_lang('EnablePlugins').'</button></form>';
110
}
111
112
function handleExtensions()
113
{
114
    echo Display::page_subheader(get_lang('ConfigureExtensions'));
115
    echo '<a class="btn btn-success" href="configure_extensions.php?display=ppt2lp" role="button">'.get_lang('Ppt2lp').'</a>';
116
}
117
118
/**
119
 * Show form for plugin and validates inputs. Calls uploadPlugin() if everything OK.
120
 *
121
 * @throws Exception
122
 *
123
 * @return string|void The HTML form, or displays a message and returns nothing on error
124
 */
125
function handlePluginUpload()
126
{
127
    $allowPluginUpload = true == api_get_configuration_value('plugin_upload_enable');
128
    if (!$allowPluginUpload) {
129
        echo Display::return_message(
130
            get_lang('PluginUploadIsNotEnabled'),
131
            'error',
132
            false
133
        );
134
135
        return;
136
    }
137
    $pluginPath = api_get_path(SYS_PLUGIN_PATH);
138
    if (!is_writable($pluginPath)) {
139
        echo Display::return_message(
140
            $pluginPath.' '.get_lang('IsNotWritable'),
141
            'error',
142
            false
143
        );
144
145
        return;
146
    }
147
148
    echo Display::return_message(
149
        get_lang('PluginUploadPleaseRememberUploadingThirdPartyPluginsCanBeDangerous'),
150
        'warning',
151
        false
152
    );
153
    echo Display::return_message(
154
        get_lang('PluginUploadingTwiceWillReplacePreviousFiles'),
155
        'normal',
156
        false
157
    );
158
    $form = new FormValidator(
159
        'plugin_upload',
160
        'post',
161
        'settings.php?category=Plugins#tabs-4'
162
    );
163
    $form->addElement(
164
        'file',
165
        'new_plugin',
166
        [get_lang('UploadNewPlugin'), '.zip']
167
    );
168
    // Only zip files are allowed
169
    $allowed_file_types[] = 'zip';
0 ignored issues
show
Comprehensibility Best Practice introduced by
$allowed_file_types was never initialized. Although not strictly required by PHP, it is generally a good practice to add $allowed_file_types = array(); before regardless.
Loading history...
170
171
    $form->addRule(
172
        'new_plugin',
173
        get_lang('InvalidExtension').' ('.implode(',', $allowed_file_types).')',
174
        'filetype',
175
        $allowed_file_types
176
    );
177
    $form->addRule(
178
        'new_plugin',
179
        get_lang('ThisFieldIsRequired'),
180
        'required'
181
    );
182
    $form->addButtonUpload(get_lang('Upload'), 'plugin_upload');
183
184
    // Plugin upload.
185
    if (isset($_POST['plugin_upload'])) {
186
        if ($form->validate()) {
187
            $values = $form->exportValues();
188
            $fileElement = $form->getElement('new_plugin');
189
            $file = $fileElement->getValue();
190
            $result = uploadPlugin($values, $file);
0 ignored issues
show
Bug introduced by
The call to uploadPlugin() has too few arguments starting with officialPlugins. ( Ignorable by Annotation )

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

190
            $result = /** @scrutinizer ignore-call */ uploadPlugin($values, $file);

This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
191
192
            // Add event to the system log.
193
            $user_id = api_get_user_id();
194
            $category = $_GET['category'];
195
            Event::addEvent(
196
                LOG_PLUGIN_CHANGE,
197
                LOG_PLUGIN_UPLOAD,
198
                $file['filename'],
199
                api_get_utc_datetime(),
200
                $user_id
201
            );
202
203
            if ($result) {
204
                Display::addFlash(Display::return_message(get_lang('PluginUploaded'), 'success', false));
205
                header('Location: ?category=Plugins#');
206
                exit;
207
            }
208
        }
209
    }
210
    echo $form->returnForm();
211
}
212
213
/**
214
 * This function allows easy activating and inactivating of plugins.
215
 *
216
 * @todo: a similar function needs to be written to activate or inactivate additional tools.
217
 *
218
 * @author Patrick Cool <[email protected]>, Ghent University
219
 * @author Julio Montoya <[email protected]> Beeznest 2012
220
 */
221
function handlePlugins()
222
{
223
    Session::erase('plugin_data');
224
    $plugin_obj = new AppPlugin();
225
    $token = Security::get_token();
226
    if (isset($_POST['submit_plugins'])) {
227
        storePlugins();
228
        // Add event to the system log.
229
        $user_id = api_get_user_id();
230
        $installed = $plugin_obj->getInstalledPlugins();
231
        Event::addEvent(
232
            LOG_PLUGIN_CHANGE,
233
            LOG_PLUGIN_ENABLE,
234
            implode(',', $installed),
235
            api_get_utc_datetime(),
236
            $user_id
237
        );
238
        echo Display::return_message(get_lang('SettingsStored'), 'confirmation');
239
    }
240
241
    $all_plugins = $plugin_obj->read_plugins_from_path();
242
    $installed_plugins = $plugin_obj->getInstalledPlugins();
243
    $officialPlugins = $plugin_obj->getOfficialPlugins();
244
245
    // Plugins NOT installed
246
    echo Display::page_subheader(get_lang('Plugins'));
247
    echo '<form
248
        class="form-horizontal"
249
        name="plugins"
250
        method="post"
251
        action="'.api_get_self().'?category='.Security::remove_XSS($_GET['category']).'&sec_token='.$token.'"
252
    >';
253
    echo '<table class="table table-hover table-striped table-bordered">';
254
    echo '<tr>';
255
    echo '<th width="20px">';
256
    echo get_lang('Action');
257
    echo '</th><th>';
258
    echo get_lang('Description');
259
    echo '</th>';
260
    echo '</tr>';
261
262
    $installed = '';
263
    $notInstalled = '';
264
    $isMainPortal = 1 === api_get_current_access_url_id();
265
    foreach ($all_plugins as $pluginName) {
266
        $plugin_info_file = api_get_path(SYS_PLUGIN_PATH).$pluginName.'/plugin.php';
267
        if (file_exists($plugin_info_file)) {
268
            $plugin_info = [];
269
            require $plugin_info_file;
270
271
            if (in_array($pluginName, $officialPlugins)) {
272
                $officialRibbon = '<div class="ribbon-diagonal ribbon-diagonal-top-right ribbon-diagonal-official">
273
                    <span>'.get_lang('PluginOfficial').'</span></div>';
274
            } else {
275
                $officialRibbon = '<div class="ribbon-diagonal ribbon-diagonal-top-right ribbon-diagonal-thirdparty">
276
                    <span>'.get_lang('PluginThirdParty').'</span></div>';
277
            }
278
            $pluginRow = '';
279
280
            $isInstalled = in_array($pluginName, $installed_plugins);
281
282
            if ($isInstalled) {
283
                $pluginRow .= '<tr class="row_selected">';
284
            } else {
285
                $pluginRow .= '<tr>';
286
            }
287
288
            $pluginRow .= '<td>';
289
290
            if ($isMainPortal) {
291
                if ($isInstalled) {
292
                    $pluginRow .= '<input type="checkbox" name="plugin_'.$pluginName.'[]" checked="checked">';
293
                } else {
294
                    $pluginRow .= '<input type="checkbox" name="plugin_'.$pluginName.'[]">';
295
                }
296
            } else {
297
                if ($isInstalled) {
298
                    $pluginRow .= Display::return_icon('check.png');
299
                } else {
300
                    $pluginRow .= Display::return_icon('checkbox_off.gif');
301
                }
302
            }
303
304
            $pluginRow .= '</td><td>';
305
            $pluginRow .= $officialRibbon;
306
            $pluginRow .= '<h4>'.$plugin_info['title'].' <small>v '.$plugin_info['version'].'</small></h4>';
307
            $pluginRow .= '<p>'.$plugin_info['comment'].'</p>';
308
            $pluginRow .= '<p>'.get_lang('Author').': '.$plugin_info['author'].'</p>';
309
310
            $pluginRow .= '<div class="btn-group">';
311
            if ($isInstalled) {
312
                $pluginRow .= Display::url(
313
                    '<em class="fa fa-cogs"></em> '.get_lang('Configure'),
314
                    'configure_plugin.php?name='.$pluginName,
315
                    ['class' => 'btn btn-default']
316
                );
317
                $pluginRow .= Display::url(
318
                    '<em class="fa fa-th-large"></em> '.get_lang('Regions'),
319
                    'settings.php?category=Regions&name='.$pluginName,
320
                    ['class' => 'btn btn-default']
321
                );
322
            }
323
324
            if (file_exists(api_get_path(SYS_PLUGIN_PATH).$pluginName.'/readme.txt')) {
325
                $pluginRow .= Display::url(
326
                    "<em class='fa fa-file-text-o'></em> readme.txt",
327
                    api_get_path(WEB_PLUGIN_PATH).$pluginName."/readme.txt",
328
                    [
329
                        'class' => 'btn btn-default ajax',
330
                        'data-title' => $plugin_info['title'],
331
                        'data-size' => 'lg',
332
                        '_target' => '_blank',
333
                    ]
334
                );
335
            }
336
337
            $readmeFile = api_get_path(SYS_PLUGIN_PATH).$pluginName.'/README.md';
338
            if (file_exists($readmeFile)) {
339
                $pluginRow .= Display::url(
340
                    "<em class='fa fa-file-text-o'></em> README.md",
341
                    api_get_path(WEB_AJAX_PATH).'plugin.ajax.php?a=md_to_html&plugin='.$pluginName,
342
                    [
343
                        'class' => 'btn btn-default ajax',
344
                        'data-title' => $plugin_info['title'],
345
                        'data-size' => 'lg',
346
                        '_target' => '_blank',
347
                    ]
348
                );
349
            }
350
351
            $pluginRow .= '</div>';
352
            $pluginRow .= '</td></tr>';
353
354
            if ($isInstalled) {
355
                $installed .= $pluginRow;
356
            } else {
357
                $notInstalled .= $pluginRow;
358
            }
359
        }
360
    }
361
362
    echo $installed;
363
    echo $notInstalled;
364
    echo '</table>';
365
366
    if ($isMainPortal) {
367
        echo '<div class="form-actions bottom_actions">';
368
        echo '<button class="btn btn-primary" type="submit" name="submit_plugins">';
369
        echo '<i class="fa fa-check" aria-hidden="true"></i> ';
370
        echo get_lang('EnablePlugins').'</button>';
371
        echo '</div>';
372
    }
373
374
    echo '</form>';
375
}
376
377
/**
378
 * This function allows the platform admin to choose the default stylesheet.
379
 *
380
 * @author Patrick Cool <[email protected]>, Ghent University
381
 * @author Julio Montoya <[email protected]>, Chamilo
382
 */
383
function handleStylesheets()
384
{
385
    $is_style_changeable = isStyleChangeable();
386
    $allowedFileTypes = ['png'];
387
388
    $form = new FormValidator(
389
        'stylesheet_upload',
390
        'post',
391
        'settings.php?category=Stylesheets#tabs-3'
392
    );
393
    $form->addElement(
394
        'text',
395
        'name_stylesheet',
396
        get_lang('NameStylesheet'),
397
        ['size' => '40', 'maxlength' => '40']
398
    );
399
    $form->addRule(
400
        'name_stylesheet',
401
        get_lang('ThisFieldIsRequired'),
402
        'required'
403
    );
404
    $form->addElement(
405
        'file',
406
        'new_stylesheet',
407
        get_lang('UploadNewStylesheet')
408
    );
409
    $allowed_file_types = getAllowedFileTypes();
410
411
    $form->addRule(
412
        'new_stylesheet',
413
        get_lang('InvalidExtension').' ('.implode(',', $allowed_file_types).')',
414
        'filetype',
415
        $allowed_file_types
416
    );
417
    $form->addRule(
418
        'new_stylesheet',
419
        get_lang('ThisFieldIsRequired'),
420
        'required'
421
    );
422
    $form->addButtonUpload(get_lang('Upload'), 'stylesheet_upload');
423
424
    $show_upload_form = false;
425
    $urlId = api_get_current_access_url_id();
426
427
    if (!is_writable(CSS_UPLOAD_PATH)) {
428
        echo Display::return_message(
429
            CSS_UPLOAD_PATH.get_lang('IsNotWritable'),
430
            'error',
431
            false
432
        );
433
    } else {
434
        // Uploading a new stylesheet.
435
        if ($urlId == 1) {
436
            $show_upload_form = true;
437
        } else {
438
            if ($is_style_changeable) {
439
                $show_upload_form = true;
440
            }
441
        }
442
    }
443
444
    // Stylesheet upload.
445
    if (isset($_POST['stylesheet_upload'])) {
446
        if ($form->validate()) {
447
            $values = $form->exportValues();
448
            $picture_element = $form->getElement('new_stylesheet');
449
            $picture = $picture_element->getValue();
450
            $result = uploadStylesheet($values, $picture);
451
452
            // Add event to the system log.
453
            $user_id = api_get_user_id();
454
            $category = $_GET['category'];
455
            Event::addEvent(
456
                LOG_CONFIGURATION_SETTINGS_CHANGE,
457
                LOG_CONFIGURATION_SETTINGS_CATEGORY,
458
                $category,
459
                api_get_utc_datetime(),
460
                $user_id
461
            );
462
463
            if ($result) {
464
                echo Display::return_message(get_lang('StylesheetAdded'));
465
            }
466
        }
467
    }
468
469
    // Current style.
470
    $selected = $currentStyle = api_get_setting('stylesheets');
471
    $styleFromDatabase = api_get_settings_params_simple(
472
        ['variable = ? AND access_url = ?' => ['stylesheets', api_get_current_access_url_id()]]
473
    );
474
    if ($styleFromDatabase) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $styleFromDatabase of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

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

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

Loading history...
475
        $selected = $currentStyle = $styleFromDatabase['selected_value'];
476
    }
477
478
    if (isset($_POST['preview'])) {
479
        $selected = $currentStyle = Security::remove_XSS($_POST['style']);
480
    }
481
482
    $themeDir = Template::getThemeDir($selected);
483
    $dir = api_get_path(SYS_PUBLIC_PATH).'css/'.$themeDir.'/images/';
484
    $url = api_get_path(WEB_CSS_PATH).'/'.$themeDir.'/images/';
485
    $logoFileName = 'header-logo.png';
486
    $newLogoFileName = 'header-logo-custom'.api_get_current_access_url_id().'.png';
487
    $webPlatformLogoPath = ChamiloApi::getPlatformLogoPath($selected);
488
489
    $logoForm = new FormValidator(
490
        'logo_upload',
491
        'post',
492
        'settings.php?category=Stylesheets#tabs-2'
493
    );
494
495
    $logoForm->addHtml(
496
        Display::return_message(
497
            sprintf(
498
                get_lang('TheLogoMustBeSizeXAndFormatY'),
499
                '250 x 70',
500
                'PNG'
501
            ),
502
            'info'
503
        )
504
    );
505
506
    if ($webPlatformLogoPath !== null) {
507
        $logoForm->addLabel(
508
            get_lang('CurrentLogo'),
509
            '<img id="header-logo-custom" src="'.$webPlatformLogoPath.'?'.time().'">'
510
        );
511
    }
512
    $logoForm->addFile('new_logo', get_lang('UpdateLogo'));
513
    if ($is_style_changeable) {
514
        $logoGroup = [
515
            $logoForm->addButtonUpload(get_lang('Upload'), 'logo_upload', true),
516
            $logoForm->addButtonCancel(get_lang('Reset'), 'logo_reset', true),
517
        ];
518
519
        $logoForm->addGroup($logoGroup);
520
    }
521
522
    if (isset($_POST['logo_reset'])) {
523
        if (is_file($dir.$newLogoFileName)) {
524
            unlink($dir.$newLogoFileName);
525
            echo Display::return_message(get_lang('ResetToTheOriginalLogo'));
526
            echo '<script>'
527
                .'$("#header-logo").attr("src","'.$url.$logoFileName.'");'
528
            .'</script>';
529
        }
530
    } elseif (isset($_POST['logo_upload'])) {
531
        $logoForm->addRule(
532
            'new_logo',
533
            get_lang('InvalidExtension').' ('.implode(',', $allowedFileTypes).')',
534
            'filetype',
535
            $allowedFileTypes
536
        );
537
        $logoForm->addRule(
538
            'new_logo',
539
            get_lang('ThisFieldIsRequired'),
540
            'required'
541
        );
542
543
        if ($logoForm->validate()) {
544
            $imageInfo = getimagesize($_FILES['new_logo']['tmp_name']);
545
            $width = $imageInfo[0];
546
            $height = $imageInfo[1];
547
            if ($width <= 250 && $height <= 70) {
548
                if (is_file($dir.$newLogoFileName)) {
549
                    unlink($dir.$newLogoFileName);
550
                }
551
552
                $status = move_uploaded_file(
553
                    $_FILES['new_logo']['tmp_name'],
554
                    $dir.$newLogoFileName
555
                );
556
557
                if ($status) {
558
                    echo Display::return_message(get_lang('NewLogoUpdated'));
559
                    echo '<script>'
560
                         .'$("#header-logo").attr("src","'.$url.$newLogoFileName.'");'
561
                         .'</script>';
562
                } else {
563
                    echo Display::return_message('Error - '.get_lang('UplNoFileUploaded'), 'error');
564
                }
565
            } else {
566
                Display::return_message('Error - '.get_lang('InvalidImageDimensions'), 'error');
567
            }
568
        }
569
    }
570
571
    if (isset($_POST['download'])) {
572
        generateCSSDownloadLink($selected);
573
    }
574
575
    $form_change = new FormValidator(
576
        'stylesheet_upload',
577
        'post',
578
        api_get_self().'?category=Stylesheets',
579
        null,
580
        ['id' => 'stylesheets_id']
581
    );
582
583
    $styles = $form_change->addElement(
584
        'selectTheme',
585
        'style',
586
        get_lang('NameStylesheet')
587
    );
588
    $styles->setSelected($currentStyle);
589
590
    if ($is_style_changeable) {
591
        $group = [
592
            $form_change->addButtonSave(get_lang('SaveSettings'), 'save', true),
593
            $form_change->addButtonPreview(get_lang('Preview'), 'preview', true),
594
            $form_change->addButtonDownload(get_lang('Download'), 'download', true),
595
        ];
596
597
        $form_change->addGroup($group);
598
599
        if ($show_upload_form) {
600
            echo Display::tabs(
601
                [get_lang('Update'), get_lang('UpdateLogo'), get_lang('UploadNewStylesheet')],
602
                [$form_change->returnForm(), $logoForm->returnForm(), $form->returnForm()]
603
            );
604
        } else {
605
            $form_change->display();
606
        }
607
608
        // Little hack to update the logo image in update form when submiting
609
        if (isset($_POST['logo_reset'])) {
610
            echo '<script>'
611
                    .'$("#header-logo-custom").attr("src","'.$url.$logoFileName.'");'
612
                .'</script>';
613
        } elseif (isset($_POST['logo_upload']) && is_file($dir.$newLogoFileName)) {
614
            echo '<script>'
615
                    .'$("#header-logo-custom").attr("src","'.$url.$newLogoFileName.'");'
616
                .'</script>';
617
        }
618
    } else {
619
        $form_change->freeze();
620
    }
621
}
622
623
/**
624
 * Creates the folder (if needed) and uploads the stylesheet in it.
625
 *
626
 * @param array $values  the values of the form
627
 * @param array $picture the values of the uploaded file
628
 *
629
 * @return bool
630
 *
631
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
632
 *
633
 * @version May 2008
634
 *
635
 * @since v1.8.5
636
 */
637
function uploadStylesheet($values, $picture)
638
{
639
    $result = false;
640
    // Valid name for the stylesheet folder.
641
    $style_name = api_preg_replace('/[^A-Za-z0-9]/', '', $values['name_stylesheet']);
642
    if (empty($style_name) || is_array($style_name)) {
643
        // The name of the uploaded stylesheet doesn't have the expected format
644
        return $result;
645
    }
646
    $cssToUpload = CSS_UPLOAD_PATH;
647
648
    // Check if a virtual instance vchamilo is used
649
    $virtualInstanceTheme = api_get_configuration_value('virtual_css_theme_folder');
650
    if (!empty($virtualInstanceTheme)) {
651
        $cssToUpload = $cssToUpload.$virtualInstanceTheme.'/';
652
    }
653
654
    // Create the folder if needed.
655
    if (!is_dir($cssToUpload.$style_name.'/')) {
656
        mkdir($cssToUpload.$style_name.'/', api_get_permissions_for_new_directories());
657
    }
658
659
    $info = pathinfo($picture['name']);
660
661
    if ($info['extension'] == 'zip') {
662
        // Try to open the file and extract it in the theme.
663
        $zip = new ZipArchive();
664
        if ($zip->open($picture['tmp_name'])) {
665
            // Make sure all files inside the zip are images or css.
666
            $num_files = $zip->numFiles;
667
            $valid = true;
668
            $single_directory = true;
669
            $invalid_files = [];
670
671
            $allowedFiles = getAllowedFileTypes();
672
673
            for ($i = 0; $i < $num_files; $i++) {
674
                $file = $zip->statIndex($i);
675
                if (substr($file['name'], -1) != '/') {
676
                    $path_parts = pathinfo($file['name']);
677
                    if (!in_array($path_parts['extension'], $allowedFiles)) {
678
                        $valid = false;
679
                        $invalid_files[] = $file['name'];
680
                    }
681
                }
682
683
                if (strpos($file['name'], '/') === false) {
684
                    $single_directory = false;
685
                }
686
            }
687
            if (!$valid) {
688
                $error_string = '<ul>';
689
                foreach ($invalid_files as $invalid_file) {
690
                    $error_string .= '<li>'.$invalid_file.'</li>';
691
                }
692
                $error_string .= '</ul>';
693
                echo Display::return_message(
694
                    get_lang('ErrorStylesheetFilesExtensionsInsideZip').$error_string,
695
                    'error',
696
                    false
697
                );
698
            } else {
699
                // If the zip does not contain a single directory, extract it.
700
                if (!$single_directory) {
701
                    // Extract zip file.
702
                    $zip->extractTo($cssToUpload.$style_name.'/');
703
                    $result = true;
704
                } else {
705
                    $extraction_path = $cssToUpload.$style_name.'/';
706
                    $mode = api_get_permissions_for_new_directories();
707
                    for ($i = 0; $i < $num_files; $i++) {
708
                        $entry = $zip->getNameIndex($i);
709
                        if (substr($entry, -1) == '/') {
710
                            continue;
711
                        }
712
713
                        $pos_slash = strpos($entry, '/');
714
                        $entry_without_first_dir = substr($entry, $pos_slash + 1);
715
                        // If there is still a slash, we need to make sure the directories are created.
716
                        if (strpos($entry_without_first_dir, '/') !== false) {
717
                            if (!is_dir($extraction_path.dirname($entry_without_first_dir))) {
718
                                // Create it.
719
                                @mkdir($extraction_path.dirname($entry_without_first_dir), $mode, true);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for mkdir(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

719
                                /** @scrutinizer ignore-unhandled */ @mkdir($extraction_path.dirname($entry_without_first_dir), $mode, true);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
720
                            }
721
                        }
722
723
                        $fp = $zip->getStream($entry);
724
                        $ofp = fopen($extraction_path.dirname($entry_without_first_dir).'/'.basename($entry), 'w');
725
726
                        while (!feof($fp)) {
727
                            fwrite($ofp, fread($fp, 8192));
728
                        }
729
730
                        fclose($fp);
731
                        fclose($ofp);
732
                    }
733
                    $result = true;
734
                }
735
            }
736
            $zip->close();
737
        } else {
738
            echo Display::return_message(get_lang('ErrorReadingZip').$info['extension'], 'error', false);
739
        }
740
    } else {
741
        // Simply move the file.
742
        move_uploaded_file($picture['tmp_name'], $cssToUpload.$style_name.'/'.$picture['name']);
743
        $result = true;
744
    }
745
746
    if ($result) {
747
        $fs = new Filesystem();
748
        $fs->mirror(
749
            CSS_UPLOAD_PATH,
750
            api_get_path(SYS_PATH).'web/css/themes/',
751
            null,
752
            ['override' => true]
753
        );
754
    }
755
756
    return $result;
757
}
758
759
/**
760
 * Creates the folder (if needed) and uploads the plugin in it. If the plugin
761
 * is already there and the folder is writeable, overwrite.
762
 *
763
 * @param array $values          the values of the form
764
 * @param array $file            the file passed to the upload form
765
 * @param array $officialPlugins A list of official plugins that cannot be uploaded
766
 *
767
 * @return bool
768
 */
769
function uploadPlugin($values, $file, $officialPlugins)
770
{
771
    $result = false;
772
    $pluginPath = api_get_path(SYS_PLUGIN_PATH);
773
    $info = pathinfo($file['name']);
774
    if ($info['extension'] == 'zip') {
775
        // Try to open the file and extract it in the theme.
776
        $zip = new ZipArchive();
777
        if ($zip->open($file['tmp_name'])) {
778
            // Make sure all files inside the zip are images or css.
779
            $num_files = $zip->numFiles;
780
            $valid = true;
781
            $single_directory = true;
782
            $invalid_files = [];
783
784
            $allowedFiles = getAllowedFileTypes();
785
            $allowedFiles[] = 'php';
786
            $allowedFiles[] = 'js';
787
            $pluginObject = new AppPlugin();
788
            $officialPlugins = $pluginObject->getOfficialPlugins();
789
790
            for ($i = 0; $i < $num_files; $i++) {
791
                $file = $zip->statIndex($i);
792
                if (substr($file['name'], -1) != '/') {
793
                    $path_parts = pathinfo($file['name']);
794
                    if (!in_array($path_parts['extension'], $allowedFiles)) {
795
                        $valid = false;
796
                        $invalid_files[] = $file['name'];
797
                    }
798
                }
799
800
                if (strpos($file['name'], '/') === false) {
801
                    $single_directory = false;
802
                }
803
            }
804
            if (!$valid) {
805
                $error_string = '<ul>';
806
                foreach ($invalid_files as $invalid_file) {
807
                    $error_string .= '<li>'.$invalid_file.'</li>';
808
                }
809
                $error_string .= '</ul>';
810
                echo Display::return_message(
811
                    get_lang('ErrorPluginFilesExtensionsInsideZip').$error_string,
812
                    'error',
813
                    false
814
                );
815
            } else {
816
                // Prevent overwriting an official plugin
817
818
                if (in_array($info['filename'], $officialPlugins)) {
819
                    echo Display::return_message(
820
                        get_lang('ErrorPluginOfficialCannotBeUploaded'),
821
                        'error',
822
                        false
823
                    );
824
                } else {
825
                    // If the zip does not contain a single directory, extract it.
826
                    if (!$single_directory) {
827
                        // Extract zip file.
828
                        $zip->extractTo($pluginPath.$info['filename'].'/');
829
                        $result = true;
830
                    } else {
831
                        $extraction_path = $pluginPath.$info['filename'].'/';
832
                        $mode = api_get_permissions_for_new_directories();
833
                        if (!is_dir($extraction_path)) {
834
                            @mkdir($extraction_path, $mode, true);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for mkdir(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

834
                            /** @scrutinizer ignore-unhandled */ @mkdir($extraction_path, $mode, true);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
835
                        }
836
837
                        for ($i = 0; $i < $num_files; $i++) {
838
                            $entry = $zip->getNameIndex($i);
839
                            if (substr($entry, -1) == '/') {
840
                                continue;
841
                            }
842
843
                            $pos_slash = strpos($entry, '/');
844
                            $entry_without_first_dir = substr($entry, $pos_slash + 1);
845
                            $shortPluginDir = dirname($entry_without_first_dir);
846
                            // If there is still a slash, we need to make sure the directories are created.
847
                            if (strpos($entry_without_first_dir, '/') !== false) {
848
                                if (!is_dir($extraction_path.$shortPluginDir)) {
849
                                    // Create it.
850
                                    @mkdir($extraction_path.$shortPluginDir, $mode, true);
851
                                }
852
                            }
853
854
                            $fp = $zip->getStream($entry);
855
                            $shortPluginDir = dirname($entry_without_first_dir).'/';
856
                            if ($shortPluginDir === './') {
857
                                $shortPluginDir = '';
858
                            }
859
                            $ofp = fopen($extraction_path.$shortPluginDir.basename($entry), 'w');
860
861
                            while (!feof($fp)) {
862
                                fwrite($ofp, fread($fp, 8192));
863
                            }
864
865
                            fclose($fp);
866
                            fclose($ofp);
867
                        }
868
                        $result = true;
869
                    }
870
                }
871
            }
872
            $zip->close();
873
        } else {
874
            echo Display::return_message(get_lang('ErrorReadingZip').$info['extension'], 'error', false);
875
        }
876
    } else {
877
        // Simply move the file.
878
        move_uploaded_file($file['tmp_name'], $pluginPath.'/'.$file['name']);
879
        $result = true;
880
    }
881
882
    return $result;
883
}
884
885
/**
886
 * Store plugin regions.
887
 */
888
function storeRegions()
889
{
890
    $plugin_obj = new AppPlugin();
891
892
    // Get a list of all current 'Plugins' settings
893
    $installed_plugins = $plugin_obj->getInstalledPlugins();
894
    $shortlist_installed = [];
895
    if (!empty($installed_plugins)) {
896
        foreach ($installed_plugins as $plugin) {
897
            if (isset($plugin['subkey'])) {
898
                $shortlist_installed[] = $plugin['subkey'];
899
            }
900
        }
901
    }
902
903
    $plugin_list = $plugin_obj->read_plugins_from_path();
904
905
    foreach ($plugin_list as $plugin) {
906
        if (isset($_POST['plugin_'.$plugin])) {
907
            $areas_to_installed = $_POST['plugin_'.$plugin];
908
            if (!empty($areas_to_installed)) {
909
                $plugin_obj->remove_all_regions($plugin);
910
                foreach ($areas_to_installed as $region) {
911
                    if (!empty($region) && $region != '-1') {
912
                        $plugin_obj->add_to_region($plugin, $region);
913
                    }
914
                }
915
            }
916
        }
917
    }
918
}
919
920
/**
921
 * This function allows easy activating and inactivating of plugins.
922
 *
923
 * @author Patrick Cool <[email protected]>, Ghent University
924
 */
925
function storePlugins()
926
{
927
    $appPlugin = new AppPlugin();
928
    // Get a list of all current 'Plugins' settings
929
    $plugin_list = $appPlugin->read_plugins_from_path();
930
    $installed_plugins = [];
931
932
    foreach ($plugin_list as $plugin) {
933
        if (isset($_POST['plugin_'.$plugin])) {
934
            $appPlugin->install($plugin);
935
            $installed_plugins[] = $plugin;
936
        }
937
    }
938
939
    if (!empty($installed_plugins)) {
940
        $remove_plugins = array_diff($plugin_list, $installed_plugins);
941
    } else {
942
        $remove_plugins = $plugin_list;
943
    }
944
945
    foreach ($remove_plugins as $plugin) {
946
        $appPlugin->uninstall($plugin);
947
    }
948
}
949
950
/**
951
 * This function allows the platform admin to choose which should be the default stylesheet.
952
 *
953
 * @author Patrick Cool <[email protected]>, Ghent University
954
 */
955
function storeStylesheets()
956
{
957
    // Insert the stylesheet.
958
    if (isStyle($_POST['style'])) {
959
        api_set_setting(
960
            'stylesheets',
961
            $_POST['style'],
962
            null,
963
            'stylesheets',
964
            api_get_current_access_url_id()
965
        );
966
    }
967
968
    return true;
969
}
970
971
/**
972
 * This function checks if the given style is a recognize style that exists in the css directory as
973
 * a standalone directory.
974
 *
975
 * @param string $style
976
 *
977
 * @return bool True if this style is recognized, false otherwise
978
 */
979
function isStyle($style)
980
{
981
    $themeList = api_get_themes();
982
983
    return in_array($style, array_keys($themeList));
984
}
985
986
/**
987
 * Search options
988
 * TODO: support for multiple site. aka $_configuration['access_url'] == 1.
989
 *
990
 * @author Marco Villegas <[email protected]>
991
 */
992
function handleSearch()
993
{
994
    global $SettingsStored, $_configuration;
995
996
    require_once api_get_path(LIBRARY_PATH).'specific_fields_manager.lib.php';
997
    $search_enabled = api_get_setting('search_enabled');
998
999
    $form = new FormValidator(
1000
        'search-options',
1001
        'post',
1002
        api_get_self().'?category=Search'
1003
    );
1004
    $values = api_get_settings_options('search_enabled');
1005
    $form->addElement('header', null, get_lang('SearchEnabledTitle'));
1006
1007
    $group = formGenerateElementsGroup($form, $values, 'search_enabled');
1008
1009
    // SearchEnabledComment
1010
    $form->addGroup(
1011
        $group,
1012
        'search_enabled',
1013
        [get_lang('SearchEnabledTitle'), get_lang('SearchEnabledComment')],
1014
        null,
1015
        false
1016
    );
1017
1018
    $search_enabled = api_get_setting('search_enabled');
1019
1020
    if ($form->validate()) {
1021
        $formValues = $form->exportValues();
1022
        setConfigurationSettingsInDatabase($formValues, $_configuration['access_url']);
1023
        $search_enabled = $formValues['search_enabled'];
1024
        echo Display::return_message($SettingsStored, 'confirm');
1025
    }
1026
    $specific_fields = get_specific_field_list();
1027
1028
    if ($search_enabled == 'true') {
1029
        $values = api_get_settings_options('search_show_unlinked_results');
1030
        $group = formGenerateElementsGroup(
1031
            $form,
1032
            $values,
1033
            'search_show_unlinked_results'
1034
        );
1035
        $form->addGroup(
1036
            $group,
1037
            'search_show_unlinked_results',
1038
            [
1039
                get_lang('SearchShowUnlinkedResultsTitle'),
1040
                get_lang('SearchShowUnlinkedResultsComment'),
1041
            ],
1042
            null,
1043
            false
1044
        );
1045
        $default_values['search_show_unlinked_results'] = api_get_setting('search_show_unlinked_results');
0 ignored issues
show
Comprehensibility Best Practice introduced by
$default_values was never initialized. Although not strictly required by PHP, it is generally a good practice to add $default_values = array(); before regardless.
Loading history...
1046
1047
        $sf_values = [];
1048
        foreach ($specific_fields as $sf) {
1049
            $sf_values[$sf['code']] = $sf['name'];
1050
        }
1051
        $url = Display::div(
1052
            Display::url(
1053
                get_lang('AddSpecificSearchField'),
1054
                'specific_fields.php'
1055
            ),
1056
            ['class' => 'sectioncomment']
1057
        );
1058
        if (empty($sf_values)) {
1059
            $form->addElement('label', [get_lang('SearchPrefilterPrefix'), $url]);
1060
        } else {
1061
            $form->addElement(
1062
                'select',
1063
                'search_prefilter_prefix',
1064
                [get_lang('SearchPrefilterPrefix'), $url],
1065
                $sf_values,
1066
                ''
1067
            );
1068
            $default_values['search_prefilter_prefix'] = api_get_setting('search_prefilter_prefix');
1069
        }
1070
    }
1071
1072
    $default_values['search_enabled'] = $search_enabled;
1073
1074
    $form->addButtonSave(get_lang('Save'));
1075
    $form->setDefaults($default_values);
1076
1077
    echo '<div id="search-options-form">';
1078
    $form->display();
1079
    echo '</div>';
1080
1081
    if ($search_enabled == 'true') {
1082
        $xapianPath = api_get_path(SYS_UPLOAD_PATH).'plugins/xapian/searchdb';
1083
1084
        /*
1085
        @todo Test the Xapian connection
1086
        if (extension_loaded('xapian')) {
1087
            require_once 'xapian.php';
1088
            try {
1089
                $db = new XapianDatabase($xapianPath.'/');
1090
            } catch (Exception $e) {
1091
                var_dump($e->getMessage());
1092
            }
1093
1094
            require_once api_get_path(LIBRARY_PATH) . 'search/ChamiloIndexer.class.php';
1095
            require_once api_get_path(LIBRARY_PATH) . 'search/IndexableChunk.class.php';
1096
            require_once api_get_path(LIBRARY_PATH) . 'specific_fields_manager.lib.php';
1097
1098
            $indexable = new IndexableChunk();
1099
            $indexable->addValue("content", 'Test');
1100
1101
            $di = new ChamiloIndexer();
1102
            $di->connectDb(NULL, NULL, 'english');
1103
            $di->addChunk($indexable);
1104
            $did = $di->index();
1105
        }
1106
        */
1107
1108
        $xapianLoaded = Display::return_icon('bullet_green.png', get_lang('Ok'));
1109
        $dir_exists = Display::return_icon('bullet_green.png', get_lang('Ok'));
1110
        $dir_is_writable = Display::return_icon('bullet_green.png', get_lang('Ok'));
1111
        $specific_fields_exists = Display::return_icon('bullet_green.png', get_lang('Ok'));
1112
1113
        //Testing specific fields
1114
        if (empty($specific_fields)) {
1115
            $specific_fields_exists = Display::return_icon(
1116
                'bullet_red.png',
1117
                get_lang('AddSpecificSearchField')
1118
            );
1119
        }
1120
        //Testing xapian extension
1121
        if (!extension_loaded('xapian')) {
1122
            $xapianLoaded = Display::return_icon('bullet_red.png', get_lang('Error'));
1123
        }
1124
        //Testing xapian searchdb path
1125
        if (!is_dir($xapianPath)) {
1126
            $dir_exists = Display::return_icon('bullet_red.png', get_lang('Error'));
1127
        }
1128
        //Testing xapian searchdb path is writable
1129
        if (!is_writable($xapianPath)) {
1130
            $dir_is_writable = Display::return_icon('bullet_red.png', get_lang('Error'));
1131
        }
1132
1133
        $data = [];
1134
        $data[] = [get_lang('XapianModuleInstalled'), $xapianLoaded];
1135
        $data[] = [get_lang('DirectoryExists').' - '.$xapianPath, $dir_exists];
1136
        $data[] = [get_lang('IsWritable').' - '.$xapianPath, $dir_is_writable];
1137
        $data[] = [get_lang('SpecificSearchFieldsAvailable'), $specific_fields_exists];
1138
1139
        showSearchSettingsTable($data);
1140
        showSearchToolsStatusTable();
1141
    }
1142
}
1143
1144
/**
1145
 * Wrapper for the templates.
1146
 *
1147
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
1148
 * @author Julio Montoya.
1149
 *
1150
 * @version August 2008
1151
 *
1152
 * @since v1.8.6
1153
 */
1154
function handleTemplates()
1155
{
1156
    /* Drive-by fix to avoid undefined var warnings, without repeating
1157
     * isset() combos all over the place. */
1158
    $action = isset($_GET['action']) ? $_GET['action'] : "invalid";
1159
1160
    if ($action != 'add') {
1161
        echo '<div class="actions" style="margin-left: 1px;">';
1162
        echo '<a href="settings.php?category=Templates&action=add">'.
1163
                Display::return_icon('new_template.png', get_lang('AddTemplate'), '', ICON_SIZE_MEDIUM).'</a>';
1164
        echo '</div>';
1165
    }
1166
1167
    if ($action == 'add' || ($action == 'edit' && is_numeric($_GET['id']))) {
1168
        addEditTemplate();
1169
1170
        // Add event to the system log.
1171
        $user_id = api_get_user_id();
1172
        $category = $_GET['category'];
1173
        Event::addEvent(
1174
            LOG_CONFIGURATION_SETTINGS_CHANGE,
1175
            LOG_CONFIGURATION_SETTINGS_CATEGORY,
1176
            $category,
1177
            api_get_utc_datetime(),
1178
            $user_id
1179
        );
1180
    } else {
1181
        if ($action == 'delete' && is_numeric($_GET['id'])) {
1182
            deleteTemplate($_GET['id']);
1183
1184
            // Add event to the system log
1185
            $user_id = api_get_user_id();
1186
            $category = $_GET['category'];
1187
            Event::addEvent(
1188
                LOG_CONFIGURATION_SETTINGS_CHANGE,
1189
                LOG_CONFIGURATION_SETTINGS_CATEGORY,
1190
                $category,
1191
                api_get_utc_datetime(),
1192
                $user_id
1193
            );
1194
        }
1195
        displayTemplates();
1196
    }
1197
}
1198
1199
/**
1200
 * Display a sortable table with all the templates that the platform administrator has defined.
1201
 *
1202
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
1203
 *
1204
 * @version August 2008
1205
 *
1206
 * @since v1.8.6
1207
 */
1208
function displayTemplates()
1209
{
1210
    $table = new SortableTable(
1211
        'templates',
1212
        'getNumberOfTemplates',
1213
        'getTemplateData',
1214
        1
1215
    );
1216
    $table->set_additional_parameters(
1217
        ['category' => Security::remove_XSS($_GET['category'])]
1218
    );
1219
    $table->set_header(0, get_lang('Image'), true, ['style' => 'width: 101px;']);
1220
    $table->set_header(1, get_lang('Title'));
1221
    $table->set_header(2, get_lang('Actions'), false, ['style' => 'width:50px;']);
1222
    $table->set_column_filter(2, 'actionsFilter');
1223
    $table->set_column_filter(0, 'searchImageFilter');
1224
    $table->display();
1225
}
1226
1227
/**
1228
 * Gets the number of templates that are defined by the platform admin.
1229
 *
1230
 * @return int
1231
 *
1232
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
1233
 *
1234
 * @version August 2008
1235
 *
1236
 * @since v1.8.6
1237
 */
1238
function getNumberOfTemplates()
1239
{
1240
    // Database table definition.
1241
    $table = Database::get_main_table('system_template');
1242
1243
    // The sql statement.
1244
    $sql = "SELECT COUNT(id) AS total FROM $table";
1245
    $result = Database::query($sql);
1246
    $row = Database::fetch_array($result);
1247
1248
    // Returning the number of templates.
1249
    return $row['total'];
1250
}
1251
1252
/**
1253
 * Gets all the template data for the sortable table.
1254
 *
1255
 * @param int    $from            the start of the limit statement
1256
 * @param int    $number_of_items the number of elements that have to be retrieved from the database
1257
 * @param int    $column          the column that is
1258
 * @param string $direction       the sorting direction (ASC or DESC)
1259
 *
1260
 * @return array
1261
 *
1262
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
1263
 *
1264
 * @version August 2008
1265
 *
1266
 * @since v1.8.6
1267
 */
1268
function getTemplateData($from, $number_of_items, $column, $direction)
1269
{
1270
    // Database table definition.
1271
    $table_system_template = Database::get_main_table('system_template');
1272
1273
    // The sql statement.
1274
    $sql = "SELECT image as col0, title as col1, id as col2 FROM $table_system_template";
1275
    $sql .= " ORDER BY col$column $direction ";
1276
    $sql .= " LIMIT $from,$number_of_items";
1277
    $result = Database::query($sql);
1278
    $return = [];
1279
    while ($row = Database::fetch_array($result)) {
1280
        $row['1'] = get_lang($row['1']);
1281
        $return[] = $row;
1282
    }
1283
    // Returning all the information for the sortable table.
1284
    return $return;
1285
}
1286
1287
/**
1288
 * display the edit and delete icons in the sortable table.
1289
 *
1290
 * @param int $id the id of the template
1291
 *
1292
 * @return string code for the link to edit and delete the template
1293
 *
1294
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
1295
 *
1296
 * @version August 2008
1297
 *
1298
 * @since v1.8.6
1299
 */
1300
function actionsFilter($id)
1301
{
1302
    $return = '<a href="settings.php?category=Templates&action=edit&id='.Security::remove_XSS($id).'">'.Display::return_icon('edit.png', get_lang('Edit'), '', ICON_SIZE_SMALL).'</a>';
1303
    $return .= '<a href="settings.php?category=Templates&action=delete&id='.Security::remove_XSS($id).'" onClick="javascript:if(!confirm('."'".get_lang('ConfirmYourChoice')."'".')) return false;">'.Display::return_icon('delete.png', get_lang('Delete'), '', ICON_SIZE_SMALL).'</a>';
1304
1305
    return $return;
1306
}
1307
1308
/**
1309
 * Display the image of the template in the sortable table.
1310
 *
1311
 * @param string $image the image
1312
 *
1313
 * @return string code for the image
1314
 *
1315
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
1316
 *
1317
 * @version August 2008
1318
 *
1319
 * @since v1.8.6
1320
 */
1321
function searchImageFilter($image)
1322
{
1323
    if (!empty($image)) {
1324
        return '<img src="'.api_get_path(WEB_APP_PATH).'home/default_platform_document/template_thumb/'.$image.'" alt="'.get_lang('TemplatePreview').'"/>';
1325
    } else {
1326
        return '<img src="'.api_get_path(WEB_APP_PATH).'home/default_platform_document/template_thumb/noimage.gif" alt="'.get_lang('NoTemplatePreview').'"/>';
1327
    }
1328
}
1329
1330
/**
1331
 * Add (or edit) a template. This function displays the form and also takes
1332
 * care of uploading the image and storing the information in the database.
1333
 *
1334
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
1335
 *
1336
 * @version August 2008
1337
 *
1338
 * @since v1.8.6
1339
 */
1340
function addEditTemplate()
1341
{
1342
    $em = Database::getManager();
1343
    // Initialize the object.
1344
    $id = isset($_GET['id']) ? (int) $_GET['id'] : 0;
1345
1346
    /** @var SystemTemplate $template */
1347
    $template = $id ? $em->find('ChamiloCoreBundle:SystemTemplate', $id) : new SystemTemplate();
1348
1349
    $form = new FormValidator(
1350
        'template',
1351
        'post',
1352
        'settings.php?category=Templates&action='.Security::remove_XSS($_GET['action']).'&id='.$id
1353
    );
1354
1355
    // Setting the form elements: the header.
1356
    if ($_GET['action'] == 'add') {
1357
        $title = get_lang('AddTemplate');
1358
    } else {
1359
        $title = get_lang('EditTemplate');
1360
    }
1361
    $form->addElement('header', '', $title);
1362
1363
    // Setting the form elements: the title of the template.
1364
    $form->addText('title', get_lang('Title'), false);
1365
    $form->addText('comment', get_lang('Description'), false);
1366
1367
    // Setting the form elements: the content of the template (wysiwyg editor).
1368
    $form->addHtmlEditor(
1369
        'template_text',
1370
        get_lang('Text'),
1371
        true,
1372
        true,
1373
        ['ToolbarSet' => 'Documents', 'Width' => '100%', 'Height' => '400']
1374
    );
1375
1376
    // Setting the form elements: the form to upload an image to be used with the template.
1377
    if (empty($template->getImage())) {
1378
        $form->addElement('file', 'template_image', get_lang('Image'), '');
1379
    }
1380
1381
    // Setting the form elements: a little bit information about the template image.
1382
    $form->addElement('static', 'file_comment', '', get_lang('TemplateImageComment100x70'));
1383
1384
    // Getting all the information of the template when editing a template.
1385
    if ($_GET['action'] == 'edit') {
1386
        $defaults['template_id'] = $id;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$defaults was never initialized. Although not strictly required by PHP, it is generally a good practice to add $defaults = array(); before regardless.
Loading history...
1387
        $defaults['template_text'] = $template->getContent();
1388
        // Forcing get_lang().
1389
        $defaults['title'] = $template->getTitle();
1390
        $defaults['comment'] = $template->getComment();
1391
1392
        // Adding an extra field: a hidden field with the id of the template we are editing.
1393
        $form->addElement('hidden', 'template_id');
1394
1395
        // Adding an extra field: a preview of the image that is currently used.
1396
1397
        if (!empty($template->getImage())) {
1398
            $form->addElement(
1399
                'static',
1400
                'template_image_preview',
1401
                '',
1402
                '<img src="'.api_get_path(WEB_APP_PATH)
1403
                    .'home/default_platform_document/template_thumb/'.$template->getImage()
1404
                    .'" alt="'.get_lang('TemplatePreview')
1405
                    .'"/>'
1406
            );
1407
            $form->addCheckBox('delete_image', null, get_lang('DeletePicture'));
1408
        } else {
1409
            $form->addElement(
1410
                'static',
1411
                'template_image_preview',
1412
                '',
1413
                '<img src="'.api_get_path(WEB_APP_PATH).'home/default_platform_document/template_thumb/noimage.gif" alt="'.get_lang('NoTemplatePreview').'"/>'
1414
            );
1415
        }
1416
1417
        // Setting the information of the template that we are editing.
1418
        $form->setDefaults($defaults);
1419
    }
1420
    // Setting the form elements: the submit button.
1421
    $form->addButtonSave(get_lang('Ok'), 'submit');
1422
1423
    // Setting the rules: the required fields.
1424
    if (empty($template->getImage())) {
1425
        $form->addRule(
1426
            'template_image',
1427
            get_lang('ThisFieldIsRequired'),
1428
            'required'
1429
        );
1430
        $form->addRule('title', get_lang('ThisFieldIsRequired'), 'required');
1431
    }
1432
1433
    // if the form validates (complies to all rules) we save the information,
1434
    // else we display the form again (with error message if needed)
1435
    if ($form->validate()) {
1436
        $check = Security::check_token('post');
1437
1438
        if ($check) {
1439
            // Exporting the values.
1440
            $values = $form->exportValues();
1441
            $isDelete = null;
1442
            if (isset($values['delete_image'])) {
1443
                $isDelete = $values['delete_image'];
1444
            }
1445
1446
            // Upload the file.
1447
            if (!empty($_FILES['template_image']['name'])) {
1448
                $upload_ok = process_uploaded_file($_FILES['template_image']);
1449
1450
                if ($upload_ok) {
1451
                    // Try to add an extension to the file if it hasn't one.
1452
                    $new_file_name = add_ext_on_mime(stripslashes($_FILES['template_image']['name']), $_FILES['template_image']['type']);
1453
1454
                    // The upload directory.
1455
                    $upload_dir = api_get_path(SYS_APP_PATH).'home/default_platform_document/template_thumb/';
1456
1457
                    // Create the directory if it does not exist.
1458
                    if (!is_dir($upload_dir)) {
1459
                        mkdir($upload_dir, api_get_permissions_for_new_directories());
1460
                    }
1461
1462
                    // Resize the preview image to max default and upload.
1463
                    $temp = new Image($_FILES['template_image']['tmp_name']);
1464
                    $picture_info = $temp->get_image_info();
1465
1466
                    $max_width_for_picture = 100;
1467
                    if ($picture_info['width'] > $max_width_for_picture) {
1468
                        $temp->resize($max_width_for_picture);
1469
                    }
1470
                    $temp->send_image($upload_dir.$new_file_name);
1471
                }
1472
            }
1473
1474
            // Store the information in the database (as insert or as update).
1475
            //$bootstrap = api_get_css(api_get_path(WEB_PUBLIC_PATH).'assets/bootstrap/dist/css/bootstrap.min.css');
1476
            $viewport = '<meta name="viewport" content="width=device-width, initial-scale=1.0">';
1477
1478
            if ($_GET['action'] == 'add') {
1479
                $templateContent = '<head>'.$viewport.'<title>'.$values['title'].'</title></head>'
1480
                    .$values['template_text'];
1481
                $template
1482
                    ->setTitle($values['title'])
1483
                    ->setComment(Security::remove_XSS($values['comment']))
1484
                    ->setContent(Security::remove_XSS($templateContent, COURSEMANAGERLOWSECURITY))
1485
                    ->setImage($new_file_name);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $new_file_name does not seem to be defined for all execution paths leading up to this point.
Loading history...
1486
                $em->persist($template);
1487
                $em->flush();
1488
1489
                // Display a feedback message.
1490
                echo Display::return_message(
1491
                    get_lang('TemplateAdded'),
1492
                    'confirm'
1493
                );
1494
                echo '<a href="settings.php?category=Templates&action=add">'.
1495
                    Display::return_icon('new_template.png', get_lang('AddTemplate'), '', ICON_SIZE_MEDIUM).
1496
                    '</a>';
1497
            } else {
1498
                $templateContent = $values['template_text'];
1499
                $template
1500
                    ->setTitle($values['title'])
1501
                    ->setComment(Security::remove_XSS($values['comment']))
1502
                    ->setContent(Security::remove_XSS($templateContent, COURSEMANAGERLOWSECURITY));
1503
1504
                if ($isDelete) {
1505
                    $filePath = api_get_path(SYS_APP_PATH).'home/default_platform_document/template_thumb/'.$template->getImage();
1506
                    if (file_exists($filePath)) {
1507
                        unlink($filePath);
1508
                    }
1509
                    $template->setImage(null);
1510
                }
1511
1512
                if (!empty($new_file_name)) {
1513
                    $template->setImage($new_file_name);
1514
                }
1515
1516
                $em->persist($template);
1517
                $em->flush();
1518
1519
                // Display a feedback message.
1520
                echo Display::return_message(get_lang('TemplateEdited'), 'confirm');
1521
            }
1522
        }
1523
        Security::clear_token();
1524
        displayTemplates();
1525
    } else {
1526
        $token = Security::get_token();
1527
        $form->addElement('hidden', 'sec_token');
1528
        $form->setConstants(['sec_token' => $token]);
1529
        // Display the form.
1530
        $form->display();
1531
    }
1532
}
1533
1534
/**
1535
 * Delete a template.
1536
 *
1537
 * @param int $id the id of the template that has to be deleted
1538
 *
1539
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
1540
 *
1541
 * @version August 2008
1542
 *
1543
 * @since v1.8.6
1544
 */
1545
function deleteTemplate($id)
1546
{
1547
    $id = intval($id);
1548
    // First we remove the image.
1549
    $table = Database::get_main_table('system_template');
1550
    $sql = "SELECT * FROM $table WHERE id = $id";
1551
    $result = Database::query($sql);
1552
    $row = Database::fetch_array($result);
1553
    if (!empty($row['image'])) {
1554
        @unlink(api_get_path(SYS_APP_PATH).'home/default_platform_document/template_thumb/'.$row['image']);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for unlink(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

1554
        /** @scrutinizer ignore-unhandled */ @unlink(api_get_path(SYS_APP_PATH).'home/default_platform_document/template_thumb/'.$row['image']);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
1555
    }
1556
1557
    // Now we remove it from the database.
1558
    $sql = "DELETE FROM $table WHERE id = $id";
1559
    Database::query($sql);
1560
1561
    // Display a feedback message.
1562
    echo Display::return_message(get_lang('TemplateDeleted'), 'confirm');
1563
}
1564
1565
/**
1566
 * Returns the list of timezone identifiers used to populate the select
1567
 * This function is called through a call_user_func() in the generate_settings_form function.
1568
 *
1569
 * @return array List of timezone identifiers
1570
 *
1571
 * @author Guillaume Viguier <[email protected]>
1572
 *
1573
 * @since Chamilo 1.8.7
1574
 */
1575
function select_timezone_value()
1576
{
1577
    return api_get_timezones();
1578
}
1579
1580
/**
1581
 * Returns an array containing the list of options used to populate the gradebook_number_decimals variable
1582
 * This function is called through a call_user_func() in the generate_settings_form function.
1583
 *
1584
 * @return array List of gradebook_number_decimals options
1585
 *
1586
 * @author Guillaume Viguier <[email protected]>
1587
 */
1588
function select_gradebook_number_decimals()
1589
{
1590
    return ['0', '1', '2'];
1591
}
1592
1593
/**
1594
 * Get the options for a select element to select gradebook default grade model.
1595
 *
1596
 * @return array
1597
 */
1598
function select_gradebook_default_grade_model_id()
1599
{
1600
    $grade_model = new GradeModel();
1601
    $models = $grade_model->get_all();
1602
    $options = [];
1603
    $options[-1] = get_lang('None');
1604
1605
    if (!empty($models)) {
1606
        foreach ($models as $model) {
1607
            $options[$model['id']] = $model['name'];
1608
        }
1609
    }
1610
1611
    return $options;
1612
}
1613
1614
/**
1615
 * @param array $settings
1616
 * @param array $settings_by_access_list
1617
 *
1618
 * @throws \Doctrine\ORM\ORMException
1619
 * @throws \Doctrine\ORM\OptimisticLockException
1620
 * @throws \Doctrine\ORM\TransactionRequiredException
1621
 *
1622
 * @return FormValidator
1623
 */
1624
function generateSettingsForm($settings, $settings_by_access_list)
1625
{
1626
    global $_configuration, $settings_to_avoid, $convert_byte_to_mega_list;
1627
    $em = Database::getManager();
1628
    $table_settings_current = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
1629
1630
    $form = new FormValidator(
1631
        'settings',
1632
        'post',
1633
        'settings.php?category='.Security::remove_XSS($_GET['category'])
1634
    );
1635
1636
    $form->addElement(
1637
        'hidden',
1638
        'search_field',
1639
        (!empty($_GET['search_field']) ? Security::remove_XSS($_GET['search_field']) : null)
1640
    );
1641
1642
    $url_id = api_get_current_access_url_id();
1643
    /*
1644
    if (!empty($_configuration['multiple_access_urls']) && api_is_global_platform_admin() && $url_id == 1) {
1645
        $group = array();
1646
        $group[] = $form->createElement('button', 'mark_all', get_lang('MarkAll'));
1647
        $group[] = $form->createElement('button', 'unmark_all', get_lang('UnmarkAll'));
1648
        $form->addGroup($group, 'buttons_in_action_right');
1649
    }*/
1650
1651
    $default_values = [];
1652
    $url_info = api_get_access_url($url_id);
1653
    $i = 0;
1654
    $addedSettings = [];
1655
    foreach ($settings as $row) {
1656
        if (in_array($row['variable'], array_keys($settings_to_avoid))) {
1657
            continue;
1658
        }
1659
1660
        if (in_array($row['variable'], $addedSettings)) {
1661
            continue;
1662
        }
1663
1664
        $addedSettings[] = $row['variable'];
1665
1666
        if (!empty($_configuration['multiple_access_urls'])) {
1667
            if (api_is_global_platform_admin()) {
1668
                if ($row['access_url_locked'] == 0) {
1669
                    if ($url_id == 1) {
1670
                        if ($row['access_url_changeable'] == '1') {
1671
                            $form->addElement(
1672
                                'html',
1673
                                '<div class="pull-right"><a class="share_this_setting" data_status = "0"  data_to_send = "'.$row['variable'].'" href="javascript:void(0);">'.
1674
                                Display::return_icon('shared_setting.png', get_lang('ChangeSharedSetting'), null, ICON_SIZE_MEDIUM).'</a></div>'
1675
                            );
1676
                        } else {
1677
                            $form->addElement(
1678
                                'html',
1679
                                '<div class="pull-right"><a class="share_this_setting" data_status = "1" data_to_send = "'.$row['variable'].'" href="javascript:void(0);">'.
1680
                                Display::return_icon('shared_setting_na.png', get_lang('ChangeSharedSetting'), null, ICON_SIZE_MEDIUM).'</a></div>'
1681
                            );
1682
                        }
1683
                    } else {
1684
                        if ($row['access_url_changeable'] == '1') {
1685
                            $form->addElement(
1686
                                'html',
1687
                                '<div class="pull-right">'.
1688
                                Display::return_icon('shared_setting.png', get_lang('ChangeSharedSetting'), null, ICON_SIZE_MEDIUM).'</div>'
1689
                            );
1690
                        } else {
1691
                            $form->addElement(
1692
                                'html',
1693
                                '<div class="pull-right">'.
1694
                                Display::return_icon('shared_setting_na.png', get_lang('ChangeSharedSetting'), null, ICON_SIZE_MEDIUM).'</div>'
1695
                            );
1696
                        }
1697
                    }
1698
                }
1699
            }
1700
        }
1701
1702
        $hideme = [];
1703
        $hide_element = false;
1704
1705
        if ($_configuration['access_url'] != 1) {
1706
            if ($row['access_url_changeable'] == 0) {
1707
                // We hide the element in other cases (checkbox, radiobutton) we 'freeze' the element.
1708
                $hide_element = true;
1709
                $hideme = ['disabled'];
1710
            } elseif ($url_info['active'] == 1) {
1711
                // We show the elements.
1712
                if (empty($row['variable'])) {
1713
                    $row['variable'] = 0;
1714
                }
1715
                if (empty($row['subkey'])) {
1716
                    $row['subkey'] = 0;
1717
                }
1718
                if (empty($row['category'])) {
1719
                    $row['category'] = 0;
1720
                }
1721
                if (isset($settings_by_access_list[$row['variable']]) &&
1722
                    isset($settings_by_access_list[$row['variable']][$row['subkey']]) &&
1723
                    is_array($settings_by_access_list[$row['variable']][$row['subkey']][$row['category']])
1724
                ) {
1725
                    // We are sure that the other site have a selected value.
1726
                    if ($settings_by_access_list[$row['variable']][$row['subkey']][$row['category']]['selected_value'] != '') {
1727
                        $row['selected_value'] = $settings_by_access_list[$row['variable']][$row['subkey']][$row['category']]['selected_value'];
1728
                    }
1729
                }
1730
                // There is no else{} statement because we load the default $row['selected_value'] of the main Chamilo site.
1731
            }
1732
        }
1733
1734
        switch ($row['type']) {
1735
            case 'textfield':
1736
                if (in_array($row['variable'], $convert_byte_to_mega_list)) {
1737
                    $form->addElement(
1738
                        'text',
1739
                        $row['variable'],
1740
                        [
1741
                            get_lang($row['title']),
1742
                            get_lang($row['comment']),
1743
                            get_lang('MB'),
1744
                        ],
1745
                        ['maxlength' => '8', 'aria-label' => get_lang($row['title'])]
1746
                    );
1747
                    $form->applyFilter($row['variable'], 'html_filter');
1748
                    $default_values[$row['variable']] = round($row['selected_value'] / 1024 / 1024, 1);
1749
                } elseif ($row['variable'] == 'account_valid_duration') {
1750
                    $form->addElement(
1751
                        'text',
1752
                        $row['variable'],
1753
                        [
1754
                            get_lang($row['title']),
1755
                            get_lang($row['comment']),
1756
                        ],
1757
                        ['maxlength' => '5', 'aria-label' => get_lang($row['title'])]
1758
                    );
1759
                    $form->applyFilter($row['variable'], 'html_filter');
1760
1761
                    // For platform character set selection:
1762
                    // Conversion of the textfield to a select box with valid values.
1763
                    $default_values[$row['variable']] = $row['selected_value'];
1764
                } elseif ($row['variable'] == 'platform_charset') {
1765
                    break;
1766
                } else {
1767
                    $hideme['class'] = 'col-md-4';
1768
                    $hideme['aria-label'] = get_lang($row['title']);
1769
                    $form->addElement(
1770
                        'text',
1771
                        $row['variable'],
1772
                        [
1773
                            get_lang($row['title']),
1774
                            get_lang($row['comment']),
1775
                        ],
1776
                        $hideme
1777
                    );
1778
                    $form->applyFilter($row['variable'], 'html_filter');
1779
                    $default_values[$row['variable']] = $row['selected_value'];
1780
                }
1781
                break;
1782
            case 'textarea':
1783
                if ($row['variable'] == 'header_extra_content') {
1784
                    $file = api_get_home_path().'header_extra_content.txt';
1785
                    $value = '';
1786
                    if (file_exists($file)) {
1787
                        $value = file_get_contents($file);
1788
                    }
1789
                    $form->addElement(
1790
                        'textarea',
1791
                        $row['variable'],
1792
                        [get_lang($row['title']), get_lang($row['comment'])],
1793
                        ['rows' => '10', 'id' => $row['variable']],
1794
                        $hideme
1795
                    );
1796
                    $default_values[$row['variable']] = $value;
1797
                } elseif ($row['variable'] == 'footer_extra_content') {
1798
                    $file = api_get_home_path().'footer_extra_content.txt';
1799
                    $value = '';
1800
                    if (file_exists($file)) {
1801
                        $value = file_get_contents($file);
1802
                    }
1803
                    $form->addElement(
1804
                        'textarea',
1805
                        $row['variable'],
1806
                        [get_lang($row['title']), get_lang($row['comment'])],
1807
                        ['rows' => '10', 'id' => $row['variable']],
1808
                        $hideme
1809
                    );
1810
                    $default_values[$row['variable']] = $value;
1811
                } else {
1812
                    $form->addElement(
1813
                        'textarea',
1814
                        $row['variable'],
1815
                        [get_lang($row['title']),
1816
                        get_lang($row['comment']), ],
1817
                        ['rows' => '10', 'id' => $row['variable']],
1818
                        $hideme
1819
                    );
1820
                    $default_values[$row['variable']] = $row['selected_value'];
1821
                }
1822
                break;
1823
            case 'radio':
1824
                $values = api_get_settings_options($row['variable']);
1825
                $group = [];
1826
                if (is_array($values)) {
1827
                    foreach ($values as $key => $value) {
1828
                        $element = &$form->createElement(
1829
                            'radio',
1830
                            $row['variable'],
1831
                            '',
1832
                            get_lang($value['display_text']),
1833
                            $value['value']
1834
                        );
1835
                        if ($hide_element) {
1836
                            $element->freeze();
1837
                        }
1838
                        $group[] = $element;
1839
                    }
1840
                }
1841
                $form->addGroup(
1842
                    $group,
1843
                    $row['variable'],
1844
                    [get_lang($row['title']), get_lang($row['comment'])],
1845
                    null,
1846
                    false
1847
                );
1848
                $default_values[$row['variable']] = $row['selected_value'];
1849
                break;
1850
            case 'checkbox':
1851
                // 1. We collect all the options of this variable.
1852
                $sql = "SELECT * FROM $table_settings_current
1853
                        WHERE variable='".$row['variable']."' AND access_url =  1";
1854
1855
                $result = Database::query($sql);
1856
                $group = [];
1857
                while ($rowkeys = Database::fetch_array($result)) {
1858
                    // Profile tab option should be hidden when the social tool is enabled.
1859
                    if (api_get_setting('allow_social_tool') == 'true') {
1860
                        if ($rowkeys['variable'] === 'show_tabs' && $rowkeys['subkey'] === 'my_profile') {
1861
                            continue;
1862
                        }
1863
                    }
1864
1865
                    // Hiding the gradebook option.
1866
                    if ($rowkeys['variable'] === 'show_tabs' && $rowkeys['subkey'] === 'my_gradebook') {
1867
                        continue;
1868
                    }
1869
1870
                    $element = &$form->createElement(
1871
                        'checkbox',
1872
                        $rowkeys['subkey'],
1873
                        '',
1874
                        get_lang($rowkeys['subkeytext'])
1875
                    );
1876
1877
                    if ($row['access_url_changeable'] == 1) {
1878
                        // 2. We look into the DB if there is a setting for a specific access_url.
1879
                        $access_url = $_configuration['access_url'];
1880
                        if (empty($access_url)) {
1881
                            $access_url = 1;
1882
                        }
1883
                        $sql = "SELECT selected_value FROM $table_settings_current
1884
                                WHERE
1885
                                    variable='".$rowkeys['variable']."' AND
1886
                                    subkey='".$rowkeys['subkey']."' AND
1887
                                    subkeytext='".$rowkeys['subkeytext']."' AND
1888
                                    access_url =  $access_url";
1889
                        $result_access = Database::query($sql);
1890
                        $row_access = Database::fetch_array($result_access);
1891
                        if ($row_access['selected_value'] === 'true' && !$form->isSubmitted()) {
1892
                            $element->setChecked(true);
1893
                        }
1894
                    } else {
1895
                        if ($rowkeys['selected_value'] === 'true' && !$form->isSubmitted()) {
1896
                            $element->setChecked(true);
1897
                        }
1898
                    }
1899
                    if ($hide_element) {
1900
                        $element->freeze();
1901
                    }
1902
                    $group[] = $element;
1903
                }
1904
                $form->addGroup(
1905
                    $group,
1906
                    $row['variable'],
1907
                    [get_lang($row['title']), get_lang($row['comment'])],
1908
                    null
1909
                );
1910
                break;
1911
            case 'link':
1912
                $form->addElement(
1913
                    'static',
1914
                    null,
1915
                    [get_lang($row['title']), get_lang($row['comment'])],
1916
                    get_lang('CurrentValue').' : '.$row['selected_value'],
1917
                    $hideme
1918
                );
1919
                break;
1920
            case 'select':
1921
                /*
1922
                * To populate the list of options, the select type dynamically calls a function that must be called select_ + the name of the variable being displayed.
1923
                * The functions being called must be added to the file settings.lib.php.
1924
                */
1925
                $form->addElement(
1926
                    'select',
1927
                    $row['variable'],
1928
                    [get_lang($row['title']), get_lang($row['comment'])],
1929
                    call_user_func('select_'.$row['variable']),
1930
                    $hideme
1931
                );
1932
                $default_values[$row['variable']] = $row['selected_value'];
1933
                break;
1934
            case 'custom':
1935
                break;
1936
            case 'select_course':
1937
                $courseSelectOptions = [];
1938
1939
                if (!empty($row['selected_value'])) {
1940
                    $course = $em->find('ChamiloCoreBundle:Course', $row['selected_value']);
1941
1942
                    $courseSelectOptions[$course->getId()] = $course->getTitle();
1943
                }
1944
1945
                $form->addElement(
1946
                    'select_ajax',
1947
                    $row['variable'],
1948
                    [get_lang($row['title']), get_lang($row['comment'])],
1949
                    $courseSelectOptions,
1950
                    ['url' => api_get_path(WEB_AJAX_PATH).'course.ajax.php?a=search_course']
1951
                );
1952
                $default_values[$row['variable']] = $row['selected_value'];
1953
                break;
1954
        }
1955
1956
        switch ($row['variable']) {
1957
            case 'pdf_export_watermark_enable':
1958
                $url = PDF::get_watermark(null);
1959
1960
                if ($url != false) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $url of type string to the boolean false. If you are specifically checking for a non-empty string, consider using the more explicit !== '' instead.
Loading history...
1961
                    $delete_url = '<a href="?delete_watermark">'.get_lang('DelImage').' '.Display::return_icon('delete.png', get_lang('DelImage')).'</a>';
1962
                    $form->addElement('html', '<div style="max-height:100px; max-width:100px; margin-left:162px; margin-bottom:10px; clear:both;"><img src="'.$url.'" style="margin-bottom:10px;" />'.$delete_url.'</div>');
1963
                }
1964
1965
                $form->addElement('file', 'pdf_export_watermark_path', get_lang('AddWaterMark'));
1966
                $allowed_picture_types = ['jpg', 'jpeg', 'png', 'gif'];
1967
                $form->addRule(
1968
                    'pdf_export_watermark_path',
1969
                    get_lang('OnlyImagesAllowed').' ('.implode(',', $allowed_picture_types).')',
1970
                    'filetype',
1971
                    $allowed_picture_types
1972
                );
1973
1974
                break;
1975
            case 'timezone_value':
1976
                $timezone = $row['selected_value'];
1977
                if (empty($timezone)) {
1978
                    $timezone = api_get_timezone();
1979
                }
1980
                $form->addLabel('', sprintf(get_lang('LocalTimeUsingPortalTimezoneXIsY'), $timezone, api_get_local_time()));
1981
                break;
1982
        }
1983
    } // end for
1984
1985
    if (!empty($settings)) {
1986
        $form->setDefaults($default_values);
1987
    }
1988
    $form->addHtml('<div class="bottom_actions">');
1989
    $form->addButtonSave(get_lang('SaveSettings'));
1990
    $form->addHtml('</div>');
1991
1992
    return $form;
1993
}
1994
1995
/**
1996
 * Searches a platform setting in all categories except from the Plugins category.
1997
 *
1998
 * @param string $search
1999
 *
2000
 * @return array
2001
 */
2002
function searchSetting($search)
2003
{
2004
    if (empty($search)) {
2005
        return [];
2006
    }
2007
    $table_settings_current = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2008
    $sql = "SELECT * FROM $table_settings_current
2009
            WHERE category <> 'Plugins' ORDER BY id ASC ";
2010
    $result = Database::store_result(Database::query($sql), 'ASSOC');
2011
    $settings = [];
2012
2013
    $search = api_strtolower($search);
2014
2015
    if (!empty($result)) {
2016
        foreach ($result as $setting) {
2017
            $found = false;
2018
2019
            $title = api_strtolower(get_lang($setting['title']));
2020
            // try the title
2021
            if (strpos($title, $search) === false) {
2022
                $comment = api_strtolower(get_lang($setting['comment']));
2023
                //Try the comment
2024
                if (strpos($comment, $search) === false) {
2025
                    //Try the variable name
2026
                    if (strpos($setting['variable'], $search) === false) {
2027
                        continue;
2028
                    } else {
2029
                        $found = true;
2030
                    }
2031
                } else {
2032
                    $found = true;
2033
                }
2034
            } else {
2035
                $found = true;
2036
            }
2037
            if ($found) {
2038
                $settings[] = $setting;
2039
            }
2040
        }
2041
    }
2042
2043
    return $settings;
2044
}
2045
/**
2046
 * Helper function to generates a form elements group.
2047
 *
2048
 * @param object $form   The form where the elements group has to be added
2049
 * @param array  $values Values to browse through
2050
 *
2051
 * @return array
2052
 */
2053
function formGenerateElementsGroup($form, $values = [], $elementName)
2054
{
2055
    $group = [];
2056
    if (is_array($values)) {
2057
        foreach ($values as $key => $value) {
2058
            $element = &$form->createElement('radio', $elementName, '', get_lang($value['display_text']), $value['value']);
2059
            $group[] = $element;
2060
        }
2061
    }
2062
2063
    return $group;
2064
}
2065
/**
2066
 * Helper function with allowed file types for CSS.
2067
 *
2068
 * @return array Array of file types (no indexes)
2069
 */
2070
function getAllowedFileTypes()
2071
{
2072
    $allowedFiles = [
2073
        'css',
2074
        'zip',
2075
        'jpeg',
2076
        'jpg',
2077
        'png',
2078
        'gif',
2079
        'ico',
2080
        'psd',
2081
        'xcf',
2082
        'svg',
2083
        'webp',
2084
        'woff',
2085
        'woff2',
2086
        'md',
2087
    ];
2088
2089
    return $allowedFiles;
2090
}
2091
/**
2092
 * Helper function to set settings in the database.
2093
 *
2094
 * @param array $parameters List of values
2095
 * @param int   $accessUrl  The current access URL
2096
 */
2097
function setConfigurationSettingsInDatabase($parameters, $accessUrl)
2098
{
2099
    api_set_settings_category('Search', 'false', $accessUrl);
2100
    // Save the settings.
2101
    foreach ($parameters as $key => $value) {
2102
        api_set_setting($key, $value, null, null);
2103
    }
2104
}
2105
2106
/**
2107
 * Helper function to show the status of the search settings table.
2108
 *
2109
 * @param array $data Data to show
2110
 */
2111
function showSearchSettingsTable($data)
2112
{
2113
    echo Display::tag('h3', get_lang('Settings'));
2114
    $table = new SortableTableFromArray($data);
2115
    $table->set_header(0, get_lang('Setting'), false);
2116
    $table->set_header(1, get_lang('Status'), false);
2117
    echo $table->display();
0 ignored issues
show
Bug introduced by
Are you sure the usage of $table->display() targeting SortableTable::display() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

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

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

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

Loading history...
2118
}
2119
/**
2120
 * Helper function to show status table for each command line tool installed.
2121
 */
2122
function showSearchToolsStatusTable()
2123
{
2124
    //@todo windows support
2125
    if (api_is_windows_os() == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

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

Loading history...
2126
        $list_of_programs = ['pdftotext', 'ps2pdf', 'catdoc', 'html2text', 'unrtf', 'catppt', 'xls2csv'];
2127
        foreach ($list_of_programs as $program) {
2128
            $output = [];
2129
            $ret_val = null;
2130
            exec("which $program", $output, $ret_val);
2131
2132
            if (!$output) {
2133
                $output[] = '';
2134
            }
2135
2136
            $icon = Display::return_icon('bullet_red.png', get_lang('NotInstalled'));
2137
            if (!empty($output[0])) {
2138
                $icon = Display::return_icon('bullet_green.png', get_lang('Installed'));
2139
            }
2140
            $data2[] = [$program, $output[0], $icon];
2141
        }
2142
        echo Display::tag('h3', get_lang('ProgramsNeededToConvertFiles'));
2143
        $table = new SortableTableFromArray($data2);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $data2 seems to be defined by a foreach iteration on line 2127. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
2144
        $table->set_header(0, get_lang('Program'), false);
2145
        $table->set_header(1, get_lang('Path'), false);
2146
        $table->set_header(2, get_lang('Status'), false);
2147
        echo $table->display();
0 ignored issues
show
Bug introduced by
Are you sure the usage of $table->display() targeting SortableTable::display() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

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

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

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

Loading history...
2148
    } else {
2149
        echo Display::return_message(
2150
            get_lang('YouAreUsingChamiloInAWindowsPlatformSadlyYouCantConvertDocumentsInOrderToSearchTheContentUsingThisTool'),
2151
            'warning'
2152
        );
2153
    }
2154
}
2155
/**
2156
 * Helper function to generate and show CSS Zip download message.
2157
 *
2158
 * @param string $style Style path
2159
 */
2160
function generateCSSDownloadLink($style)
2161
{
2162
    $arch = api_get_path(SYS_ARCHIVE_PATH).$style.'.zip';
2163
    $themeDir = Template::getThemeDir($style);
2164
    $dir = api_get_path(SYS_CSS_PATH).$themeDir;
2165
    $check = Security::check_abs_path(
2166
        $dir,
2167
        api_get_path(SYS_CSS_PATH).'themes'
2168
    );
2169
    if (is_dir($dir) && $check) {
2170
        $zip = new PclZip($arch);
2171
        // Remove path prefix except the style name and put file on disk
2172
        $zip->create($dir, PCLZIP_OPT_REMOVE_PATH, dirname($dir));
0 ignored issues
show
Bug introduced by
The constant PCLZIP_OPT_REMOVE_PATH was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2173
        $url = api_get_path(WEB_CODE_PATH).'course_info/download.php?archive_path=&archive='.str_replace(api_get_path(SYS_ARCHIVE_PATH), '', $arch);
2174
2175
        //@TODO: use more generic script to download.
2176
        $str = '<a class="btn btn-primary btn-large" href="'.$url.'">'.get_lang('ClickHereToDownloadTheFile').'</a>';
2177
        echo Display::return_message($str, 'normal', false);
2178
    } else {
2179
        echo Display::return_message(get_lang('FileNotFound'), 'warning');
2180
    }
2181
}
2182
2183
/**
2184
 * Helper function to tell if the style is changeable in the current URL.
2185
 *
2186
 * @return bool $changeable Whether the style can be changed in this URL or not
2187
 */
2188
function isStyleChangeable()
2189
{
2190
    $changeable = false;
2191
    $urlId = api_get_current_access_url_id();
2192
    if ($urlId) {
2193
        $style_info = api_get_settings('stylesheets', '', 1, 0);
2194
        $url_info = api_get_access_url($urlId);
2195
        if ($style_info[0]['access_url_changeable'] == 1 && $url_info['active'] == 1) {
2196
            $changeable = true;
2197
        }
2198
    } else {
2199
        $changeable = true;
2200
    }
2201
2202
    return $changeable;
2203
}
2204
2205
/**
2206
 * Get all settings of one category prepared for display in admin/settings.php.
2207
 *
2208
 * @param string $category
2209
 *
2210
 * @return array
2211
 */
2212
function getCategorySettings($category = '')
2213
{
2214
    $url_id = api_get_current_access_url_id();
2215
    $settings_by_access_list = [];
2216
2217
    if ($url_id == 1) {
2218
        $settings = api_get_settings($category, 'group', $url_id);
2219
    } else {
2220
        $url_info = api_get_access_url($url_id);
2221
        if ($url_info['active'] == 1) {
2222
            $categoryToSearch = $category;
2223
            if ($category == 'search_setting') {
2224
                $categoryToSearch = '';
2225
            }
2226
            // The default settings of Chamilo
2227
            $settings = api_get_settings($categoryToSearch, 'group', 1, 0);
2228
            // The settings that are changeable from a particular site.
2229
            $settings_by_access = api_get_settings($categoryToSearch, 'group', $url_id, 1);
2230
2231
            foreach ($settings_by_access as $row) {
2232
                if (empty($row['variable'])) {
2233
                    $row['variable'] = 0;
2234
                }
2235
                if (empty($row['subkey'])) {
2236
                    $row['subkey'] = 0;
2237
                }
2238
                if (empty($row['category'])) {
2239
                    $row['category'] = 0;
2240
                }
2241
2242
                // One more validation if is changeable.
2243
                if ($row['access_url_changeable'] == 1) {
2244
                    $settings_by_access_list[$row['variable']][$row['subkey']][$row['category']] = $row;
2245
                } else {
2246
                    $settings_by_access_list[$row['variable']][$row['subkey']][$row['category']] = [];
2247
                }
2248
            }
2249
        }
2250
    }
2251
2252
    if (isset($category) && $category == 'search_setting') {
2253
        if (!empty($_REQUEST['search_field'])) {
2254
            $settings = searchSetting($_REQUEST['search_field']);
2255
        }
2256
    }
2257
2258
    return [
2259
        'settings' => $settings,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $settings does not seem to be defined for all execution paths leading up to this point.
Loading history...
2260
        'settings_by_access_list' => $settings_by_access_list,
2261
    ];
2262
}
2263