Passed
Push — 1.11.x ( bce6cd...c146d9 )
by Angel Fernando Quiroz
12:25
created

main/admin/settings.lib.php (1 issue)

1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
use Chamilo\CoreBundle\Component\Utils\ChamiloApi;
6
use Chamilo\CoreBundle\Entity\SystemTemplate;
7
use ChamiloSession as Session;
8
use Symfony\Component\Filesystem\Filesystem;
9
10
/**
11
 * Library of the settings.php file.
12
 *
13
 * @author Julio Montoya <[email protected]>
14
 * @author Guillaume Viguier <[email protected]>
15
 *
16
 * @since Chamilo 1.8.7
17
 */
18
define('CSS_UPLOAD_PATH', api_get_path(SYS_APP_PATH).'Resources/public/css/themes/');
19
20
/**
21
 * This function allows easy activating and inactivating of regions.
22
 *
23
 * @author Julio Montoya <[email protected]> Beeznest 2012
24
 */
25
function handleRegions()
26
{
27
    if (isset($_POST['submit_plugins'])) {
28
        storeRegions();
29
        // Add event to the system log.
30
        $user_id = api_get_user_id();
31
        $category = $_GET['category'];
32
        Event::addEvent(
33
            LOG_CONFIGURATION_SETTINGS_CHANGE,
34
            LOG_CONFIGURATION_SETTINGS_CATEGORY,
35
            $category,
36
            api_get_utc_datetime(),
37
            $user_id
38
        );
39
        echo Display::return_message(get_lang('SettingsStored'), 'confirmation');
40
    }
41
42
    $plugin_obj = new AppPlugin();
43
    $installed_plugins = $plugin_obj->getInstalledPlugins();
44
45
    echo '<form name="plugins" method="post" action="'.api_get_self().'?category='.Security::remove_XSS($_GET['category']).'">';
46
    echo '<table class="table table-hover table-striped data_table">';
47
    echo '<tr>';
48
    echo '<th width="400px">';
49
    echo get_lang('Plugin');
50
    echo '</th><th>';
51
    echo get_lang('Regions');
52
    echo '</th>';
53
    echo '</th>';
54
    echo '</tr>';
55
56
    /* We display all the possible plugins and the checkboxes */
57
    $plugin_region_list = [];
58
    $my_plugin_list = $plugin_obj->get_plugin_regions();
59
    foreach ($my_plugin_list as $plugin_item) {
60
        $plugin_region_list[$plugin_item] = $plugin_item;
61
    }
62
63
    // Removing course tool
64
    unset($plugin_region_list['course_tool_plugin']);
65
66
    foreach ($installed_plugins as $pluginName) {
67
        $plugin_info_file = api_get_path(SYS_PLUGIN_PATH).$pluginName.'/plugin.php';
68
69
        if (file_exists($plugin_info_file)) {
70
            $plugin_info = [];
71
            require $plugin_info_file;
72
            if (isset($_GET['name']) && $_GET['name'] === $pluginName) {
73
                echo '<tr class="row_selected">';
74
            } else {
75
                echo '<tr>';
76
            }
77
            echo '<td>';
78
            echo '<h4>'.$plugin_info['title'].' <small>v'.$plugin_info['version'].'</small></h4>';
79
            echo '<p>'.$plugin_info['comment'].'</p>';
80
            echo '</td><td>';
81
            $selected_plugins = $plugin_obj->get_areas_by_plugin($pluginName);
82
            $region_list = [];
83
            $isAdminPlugin = isset($plugin_info['is_admin_plugin']) && $plugin_info['is_admin_plugin'];
84
            $isCoursePlugin = isset($plugin_info['is_course_plugin']) && $plugin_info['is_course_plugin'];
85
86
            if (!$isAdminPlugin && !$isCoursePlugin) {
87
                $region_list = $plugin_region_list;
88
            } else {
89
                if ($isAdminPlugin) {
90
                    $region_list['menu_administrator'] = 'menu_administrator';
91
                }
92
                if ($isCoursePlugin) {
93
                    $region_list['course_tool_plugin'] = 'course_tool_plugin';
94
                }
95
            }
96
97
            echo Display::select(
98
                'plugin_'.$pluginName.'[]',
99
                $region_list,
100
                $selected_plugins,
101
                ['multiple' => 'multiple', 'style' => 'width:500px'],
102
                true,
103
                get_lang('None')
104
            );
105
            echo '</td></tr>';
106
        }
107
    }
108
    echo '</table>';
109
    echo '<br />';
110
    echo '<button class="btn btn-success" type="submit" name="submit_plugins">'.get_lang('EnablePlugins').'</button></form>';
111
}
112
113
function handleExtensions()
114
{
115
    echo Display::page_subheader(get_lang('ConfigureExtensions'));
116
    echo '<a class="btn btn-success" href="configure_extensions.php?display=ppt2lp" role="button">'.get_lang('Ppt2lp').'</a>';
117
}
118
119
/**
120
 * Show form for plugin and validates inputs. Calls uploadPlugin() if everything OK.
121
 *
122
 * @throws Exception
123
 *
124
 * @return string|void The HTML form, or displays a message and returns nothing on error
125
 */
126
function handlePluginUpload()
127
{
128
    $allowPluginUpload = true == api_get_configuration_value('plugin_upload_enable');
129
    if (!$allowPluginUpload) {
130
        echo Display::return_message(
131
            get_lang('PluginUploadIsNotEnabled'),
132
            'error',
133
            false
134
        );
135
136
        return;
137
    }
138
    $pluginPath = api_get_path(SYS_PLUGIN_PATH);
139
    if (!is_writable($pluginPath)) {
140
        echo Display::return_message(
141
            $pluginPath.' '.get_lang('IsNotWritable'),
142
            'error',
143
            false
144
        );
145
146
        return;
147
    }
148
149
    echo Display::return_message(
150
        get_lang('PluginUploadPleaseRememberUploadingThirdPartyPluginsCanBeDangerous'),
151
        'warning',
152
        false
153
    );
154
    echo Display::return_message(
155
        get_lang('PluginUploadingTwiceWillReplacePreviousFiles'),
156
        'normal',
157
        false
158
    );
159
    $form = new FormValidator(
160
        'plugin_upload',
161
        'post',
162
        api_get_path(WEB_CODE_PATH).'admin/settings.php?category=Plugins#tabs-4'
163
    );
164
    $form->addElement(
165
        'file',
166
        'new_plugin',
167
        [get_lang('UploadNewPlugin'), '.zip']
168
    );
169
    // Only zip files are allowed
170
    $allowed_file_types[] = 'zip';
171
172
    $form->addRule(
173
        'new_plugin',
174
        get_lang('InvalidExtension').' ('.implode(',', $allowed_file_types).')',
175
        'filetype',
176
        $allowed_file_types
177
    );
178
    $form->addRule(
179
        'new_plugin',
180
        get_lang('ThisFieldIsRequired'),
181
        'required'
182
    );
183
    $form->addButtonUpload(get_lang('Upload'), 'plugin_upload');
184
    $form->protect();
185
186
    // Plugin upload.
187
    if ($form->validate()) {
188
        $fileElement = $form->getElement('new_plugin');
189
        $file = $fileElement->getValue();
190
        $result = uploadPlugin($file);
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['name'],
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
    echo $form->returnForm();
210
}
211
212
/**
213
 * This function allows easy activating and inactivating of plugins.
214
 *
215
 * @todo: a similar function needs to be written to activate or inactivate additional tools.
216
 *
217
 * @author Patrick Cool <[email protected]>, Ghent University
218
 * @author Julio Montoya <[email protected]> Beeznest 2012
219
 */
220
function handlePlugins()
221
{
222
    Session::erase('plugin_data');
223
    $plugin_obj = new AppPlugin();
224
    $token = Security::get_existing_token();
225
    if (isset($_POST['submit_plugins'])) {
226
        storePlugins();
227
        // Add event to the system log.
228
        $user_id = api_get_user_id();
229
        $installed = $plugin_obj->getInstalledPlugins();
230
        Event::addEvent(
231
            LOG_PLUGIN_CHANGE,
232
            LOG_PLUGIN_ENABLE,
233
            implode(',', $installed),
234
            api_get_utc_datetime(),
235
            $user_id
236
        );
237
        echo Display::return_message(get_lang('SettingsStored'), 'confirmation');
238
    }
239
240
    $all_plugins = $plugin_obj->read_plugins_from_path();
241
    $installed_plugins = $plugin_obj->getInstalledPlugins();
242
    $officialPlugins = $plugin_obj->getOfficialPlugins();
243
244
    // Plugins NOT installed
245
    echo Display::page_subheader(get_lang('Plugins'));
246
    echo '<form
247
        class="form-horizontal"
248
        name="plugins"
249
        method="post"
250
        action="'.api_get_self().'?category='.Security::remove_XSS($_GET['category']).'&sec_token='.$token.'"
251
    >';
252
    echo '<table class="table table-hover table-striped table-bordered">';
253
    echo '<tr>';
254
    echo '<th width="20px">';
255
    echo get_lang('Action');
256
    echo '</th><th>';
257
    echo get_lang('Description');
258
    echo '</th>';
259
    echo '</tr>';
260
261
    $installed = '';
262
    $notInstalled = '';
263
    $isMainPortal = true;
264
    if (api_is_multiple_url_enabled()) {
265
        $isMainPortal = 1 === api_get_current_access_url_id();
266
    }
267
268
    $unknownLabel = get_lang('Unknown');
269
    foreach ($all_plugins as $pluginName) {
270
        $plugin_info_file = api_get_path(SYS_PLUGIN_PATH).$pluginName.'/plugin.php';
271
        if (file_exists($plugin_info_file)) {
272
            $plugin_info = [
273
                'title' => $pluginName,
274
                'version' => '',
275
                'comment' => '',
276
                'author' => $unknownLabel,
277
            ];
278
            require $plugin_info_file;
279
280
            if (in_array($pluginName, $officialPlugins)) {
281
                $officialRibbon = '<div class="ribbon-diagonal ribbon-diagonal-top-right ribbon-diagonal-official">
282
                    <span>'.get_lang('PluginOfficial').'</span></div>';
283
            } else {
284
                $officialRibbon = '<div class="ribbon-diagonal ribbon-diagonal-top-right ribbon-diagonal-thirdparty">
285
                    <span>'.get_lang('PluginThirdParty').'</span></div>';
286
            }
287
            $pluginRow = '';
288
289
            $isInstalled = in_array($pluginName, $installed_plugins);
290
291
            if ($isInstalled) {
292
                $pluginRow .= '<tr class="row_selected">';
293
            } else {
294
                $pluginRow .= '<tr>';
295
            }
296
297
            $pluginRow .= '<td>';
298
299
            if ($isMainPortal) {
300
                if ($isInstalled) {
301
                    $pluginRow .= '<input type="checkbox" name="plugin_'.$pluginName.'[]" checked="checked">';
302
                } else {
303
                    $pluginRow .= '<input type="checkbox" name="plugin_'.$pluginName.'[]">';
304
                }
305
            } else {
306
                if ($isInstalled) {
307
                    $pluginRow .= Display::return_icon('check.png');
308
                } else {
309
                    $pluginRow .= Display::return_icon('checkbox_off.gif');
310
                }
311
            }
312
313
            $pluginRow .= '</td><td>';
314
            $pluginRow .= $officialRibbon;
315
            $pluginRow .= '<h4>'.$plugin_info['title'].' <small>v '.$plugin_info['version'].'</small></h4>';
316
            $pluginRow .= '<p>'.$plugin_info['comment'].'</p>';
317
            $pluginRow .= '<p>'.get_lang('Author').': '.$plugin_info['author'].'</p>';
318
319
            $pluginRow .= '<div class="btn-group">';
320
            if ($isInstalled) {
321
                $pluginRow .= Display::url(
322
                    '<em class="fa fa-cogs"></em> '.get_lang('Configure'),
323
                    'configure_plugin.php?name='.$pluginName,
324
                    ['class' => 'btn btn-default']
325
                );
326
                $pluginRow .= Display::url(
327
                    '<em class="fa fa-th-large"></em> '.get_lang('Regions'),
328
                    'settings.php?category=Regions&name='.$pluginName,
329
                    ['class' => 'btn btn-default']
330
                );
331
            }
332
333
            if (file_exists(api_get_path(SYS_PLUGIN_PATH).$pluginName.'/readme.txt')) {
334
                $pluginRow .= Display::url(
335
                    "<em class='fa fa-file-text-o'></em> readme.txt",
336
                    api_get_path(WEB_PLUGIN_PATH).$pluginName."/readme.txt",
337
                    [
338
                        'class' => 'btn btn-default ajax',
339
                        'data-title' => $plugin_info['title'],
340
                        'data-size' => 'lg',
341
                        '_target' => '_blank',
342
                    ]
343
                );
344
            }
345
346
            $readmeFile = api_get_path(SYS_PLUGIN_PATH).$pluginName.'/README.md';
347
            if (file_exists($readmeFile)) {
348
                $pluginRow .= Display::url(
349
                    "<em class='fa fa-file-text-o'></em> README.md",
350
                    api_get_path(WEB_AJAX_PATH).'plugin.ajax.php?a=md_to_html&plugin='.$pluginName,
351
                    [
352
                        'class' => 'btn btn-default ajax',
353
                        'data-title' => $plugin_info['title'],
354
                        'data-size' => 'lg',
355
                        '_target' => '_blank',
356
                    ]
357
                );
358
            }
359
360
            $pluginRow .= '</div>';
361
            $pluginRow .= '</td></tr>';
362
363
            if ($isInstalled) {
364
                $installed .= $pluginRow;
365
            } else {
366
                $notInstalled .= $pluginRow;
367
            }
368
        }
369
    }
370
371
    echo $installed;
372
    echo $notInstalled;
373
    echo '</table>';
374
375
    if ($isMainPortal) {
376
        echo '<div class="form-actions bottom_actions">';
377
        echo '<button class="btn btn-primary" type="submit" name="submit_plugins">';
378
        echo '<i class="fa fa-check" aria-hidden="true"></i> ';
379
        echo get_lang('EnablePlugins').'</button>';
380
        echo '</div>';
381
    }
382
383
    echo '</form>';
384
}
385
386
/**
387
 * This function allows the platform admin to choose the default stylesheet.
388
 *
389
 * @author Patrick Cool <[email protected]>, Ghent University
390
 * @author Julio Montoya <[email protected]>, Chamilo
391
 */
392
function handleStylesheets()
393
{
394
    $is_style_changeable = isStyleChangeable();
395
    $allowedFileTypes = ['png'];
396
397
    $form = new FormValidator(
398
        'stylesheet_upload',
399
        'post',
400
        api_get_path().'admin/settings.php?category=Stylesheets#tabs-3'
401
    );
402
    $form->protect();
403
    $form->addElement(
404
        'text',
405
        'name_stylesheet',
406
        get_lang('NameStylesheet'),
407
        ['size' => '40', 'maxlength' => '40']
408
    );
409
    $form->addRule(
410
        'name_stylesheet',
411
        get_lang('ThisFieldIsRequired'),
412
        'required'
413
    );
414
    $form->addElement(
415
        'file',
416
        'new_stylesheet',
417
        get_lang('UploadNewStylesheet')
418
    );
419
    $allowed_file_types = getAllowedFileTypes();
420
421
    $form->addRule(
422
        'new_stylesheet',
423
        get_lang('InvalidExtension').' ('.implode(',', $allowed_file_types).')',
424
        'filetype',
425
        $allowed_file_types
426
    );
427
    $form->addRule(
428
        'new_stylesheet',
429
        get_lang('ThisFieldIsRequired'),
430
        'required'
431
    );
432
    $form->addButtonUpload(get_lang('Upload'), 'stylesheet_upload');
433
434
    $show_upload_form = false;
435
    $urlId = api_get_current_access_url_id();
436
437
    if (!is_writable(CSS_UPLOAD_PATH)) {
438
        echo Display::return_message(
439
            CSS_UPLOAD_PATH.get_lang('IsNotWritable'),
440
            'error',
441
            false
442
        );
443
    } else {
444
        // Uploading a new stylesheet.
445
        if ($urlId == 1) {
446
            $show_upload_form = true;
447
        } else {
448
            if ($is_style_changeable) {
449
                $show_upload_form = true;
450
            }
451
        }
452
    }
453
454
    // Stylesheet upload.
455
    if (isset($_POST['stylesheet_upload'])) {
456
        if ($form->validate()) {
457
            $values = $form->exportValues();
458
            $picture_element = $form->getElement('new_stylesheet');
459
            $picture = $picture_element->getValue();
460
            $result = uploadStylesheet($values, $picture);
461
462
            // Add event to the system log.
463
            $user_id = api_get_user_id();
464
            $category = $_GET['category'];
465
            Event::addEvent(
466
                LOG_CONFIGURATION_SETTINGS_CHANGE,
467
                LOG_CONFIGURATION_SETTINGS_CATEGORY,
468
                $category,
469
                api_get_utc_datetime(),
470
                $user_id
471
            );
472
473
            if ($result) {
474
                echo Display::return_message(get_lang('StylesheetAdded'));
475
            }
476
        }
477
    }
478
479
    // Current style.
480
    $selected = $currentStyle = api_get_setting('stylesheets');
481
    $styleFromDatabase = api_get_settings_params_simple(
482
        ['variable = ? AND access_url = ?' => ['stylesheets', api_get_current_access_url_id()]]
483
    );
484
    if ($styleFromDatabase) {
485
        $selected = $currentStyle = $styleFromDatabase['selected_value'];
486
    }
487
488
    if (isset($_POST['preview'])) {
489
        $selected = $currentStyle = Security::remove_XSS($_POST['style']);
490
    }
491
492
    $themeDir = Template::getThemeDir($selected);
493
    $dir = api_get_path(SYS_PUBLIC_PATH).'css/'.$themeDir.'/images/';
494
    $url = api_get_path(WEB_CSS_PATH).'/'.$themeDir.'/images/';
495
    $logoFileName = 'header-logo.png';
496
    $newLogoFileName = 'header-logo-custom'.api_get_current_access_url_id().'.png';
497
    $webPlatformLogoPath = ChamiloApi::getPlatformLogoPath($selected);
498
499
    $logoForm = new FormValidator(
500
        'logo_upload',
501
        'post',
502
        'settings.php?category=Stylesheets#tabs-2'
503
    );
504
505
    $logoForm->addHtml(
506
        Display::return_message(
507
            sprintf(
508
                get_lang('TheLogoMustBeSizeXAndFormatY'),
509
                '250 x 70',
510
                'PNG'
511
            ),
512
            'info'
513
        )
514
    );
515
516
    if ($webPlatformLogoPath !== null) {
517
        $logoForm->addLabel(
518
            get_lang('CurrentLogo'),
519
            '<img id="header-logo-custom" src="'.$webPlatformLogoPath.'?'.time().'">'
520
        );
521
    }
522
    $logoForm->addFile('new_logo', get_lang('UpdateLogo'));
523
    if ($is_style_changeable) {
524
        $logoGroup = [
525
            $logoForm->addButtonUpload(get_lang('Upload'), 'logo_upload', true),
526
            $logoForm->addButtonCancel(get_lang('Reset'), 'logo_reset', true),
527
        ];
528
529
        $logoForm->addGroup($logoGroup);
530
    }
531
532
    if (isset($_POST['logo_reset'])) {
533
        if (is_file($dir.$newLogoFileName)) {
534
            unlink($dir.$newLogoFileName);
535
            echo Display::return_message(get_lang('ResetToTheOriginalLogo'));
536
            echo '<script>'
537
                .'$("#header-logo").attr("src","'.$url.$logoFileName.'");'
538
            .'</script>';
539
        }
540
    } elseif (isset($_POST['logo_upload'])) {
541
        $logoForm->addRule(
542
            'new_logo',
543
            get_lang('InvalidExtension').' ('.implode(',', $allowedFileTypes).')',
544
            'filetype',
545
            $allowedFileTypes
546
        );
547
        $logoForm->addRule(
548
            'new_logo',
549
            get_lang('ThisFieldIsRequired'),
550
            'required'
551
        );
552
553
        if ($logoForm->validate()) {
554
            $imageInfo = getimagesize($_FILES['new_logo']['tmp_name']);
555
            $width = $imageInfo[0];
556
            $height = $imageInfo[1];
557
            if ($width <= 250 && $height <= 70) {
558
                if (is_file($dir.$newLogoFileName)) {
559
                    unlink($dir.$newLogoFileName);
560
                }
561
562
                $status = move_uploaded_file(
563
                    $_FILES['new_logo']['tmp_name'],
564
                    $dir.$newLogoFileName
565
                );
566
567
                if ($status) {
568
                    echo Display::return_message(get_lang('NewLogoUpdated'));
569
                    echo '<script>'
570
                         .'$("#header-logo").attr("src","'.$url.$newLogoFileName.'");'
571
                         .'</script>';
572
                } else {
573
                    echo Display::return_message('Error - '.get_lang('UplNoFileUploaded'), 'error');
574
                }
575
            } else {
576
                Display::return_message('Error - '.get_lang('InvalidImageDimensions'), 'error');
577
            }
578
        }
579
    }
580
581
    if (isset($_POST['download'])) {
582
        generateCSSDownloadLink($selected);
583
    }
584
585
    $form_change = new FormValidator(
586
        'stylesheet_upload',
587
        'post',
588
        api_get_self().'?category=Stylesheets',
589
        null,
590
        ['id' => 'stylesheets_id']
591
    );
592
593
    $styles = $form_change->addElement(
594
        'selectTheme',
595
        'style',
596
        get_lang('NameStylesheet')
597
    );
598
    $styles->setSelected($currentStyle);
599
600
    if ($is_style_changeable) {
601
        $group = [
602
            $form_change->addButtonSave(get_lang('SaveSettings'), 'save', true),
603
            $form_change->addButtonPreview(get_lang('Preview'), 'preview', true),
604
            $form_change->addButtonDownload(get_lang('Download'), 'download', true),
605
        ];
606
607
        $form_change->addGroup($group);
608
609
        if ($show_upload_form) {
610
            echo Display::tabs(
611
                [get_lang('Update'), get_lang('UpdateLogo'), get_lang('UploadNewStylesheet')],
612
                [$form_change->returnForm(), $logoForm->returnForm(), $form->returnForm()]
613
            );
614
        } else {
615
            $form_change->display();
616
        }
617
618
        // Little hack to update the logo image in update form when submiting
619
        if (isset($_POST['logo_reset'])) {
620
            echo '<script>'
621
                    .'$("#header-logo-custom").attr("src","'.$url.$logoFileName.'");'
622
                .'</script>';
623
        } elseif (isset($_POST['logo_upload']) && is_file($dir.$newLogoFileName)) {
624
            echo '<script>'
625
                    .'$("#header-logo-custom").attr("src","'.$url.$newLogoFileName.'");'
626
                .'</script>';
627
        }
628
    } else {
629
        $form_change->freeze();
630
    }
631
}
632
633
/**
634
 * Creates the folder (if needed) and uploads the stylesheet in it.
635
 *
636
 * @param array $values  the values of the form
637
 * @param array $picture the values of the uploaded file
638
 *
639
 * @return bool
640
 *
641
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
642
 *
643
 * @version May 2008
644
 *
645
 * @since v1.8.5
646
 */
647
function uploadStylesheet($values, $picture)
648
{
649
    $result = false;
650
    // Valid name for the stylesheet folder.
651
    $style_name = api_preg_replace('/[^A-Za-z0-9]/', '', $values['name_stylesheet']);
652
    if (empty($style_name) || is_array($style_name)) {
653
        // The name of the uploaded stylesheet doesn't have the expected format
654
        return $result;
655
    }
656
    $cssToUpload = CSS_UPLOAD_PATH;
657
658
    // Check if a virtual instance vchamilo is used
659
    $virtualInstanceTheme = api_get_configuration_value('virtual_css_theme_folder');
660
    if (!empty($virtualInstanceTheme)) {
661
        $cssToUpload = $cssToUpload.$virtualInstanceTheme.'/';
662
    }
663
664
    // Create the folder if needed.
665
    if (!is_dir($cssToUpload.$style_name.'/')) {
666
        mkdir($cssToUpload.$style_name.'/', api_get_permissions_for_new_directories());
667
    }
668
669
    $info = pathinfo($picture['name']);
670
671
    if ($info['extension'] == 'zip') {
672
        // Try to open the file and extract it in the theme.
673
        $zip = new ZipArchive();
674
        if ($zip->open($picture['tmp_name'])) {
675
            // Make sure all files inside the zip are images or css.
676
            $num_files = $zip->numFiles;
677
            $valid = true;
678
            $single_directory = true;
679
            $invalid_files = [];
680
681
            $allowedFiles = getAllowedFileTypes();
682
683
            for ($i = 0; $i < $num_files; $i++) {
684
                $file = $zip->statIndex($i);
685
                if (substr($file['name'], -1) != '/') {
686
                    $path_parts = pathinfo($file['name']);
687
                    if (!in_array($path_parts['extension'], $allowedFiles)) {
688
                        $valid = false;
689
                        $invalid_files[] = $file['name'];
690
                    }
691
                }
692
693
                if (strpos($file['name'], '/') === false) {
694
                    $single_directory = false;
695
                }
696
            }
697
            if (!$valid) {
698
                $error_string = '<ul>';
699
                foreach ($invalid_files as $invalid_file) {
700
                    $error_string .= '<li>'.$invalid_file.'</li>';
701
                }
702
                $error_string .= '</ul>';
703
                echo Display::return_message(
704
                    get_lang('ErrorStylesheetFilesExtensionsInsideZip').$error_string,
705
                    'error',
706
                    false
707
                );
708
            } else {
709
                // If the zip does not contain a single directory, extract it.
710
                if (!$single_directory) {
711
                    // Extract zip file.
712
                    $zip->extractTo($cssToUpload.$style_name.'/');
713
                    $result = true;
714
                } else {
715
                    $extraction_path = $cssToUpload.$style_name.'/';
716
                    $mode = api_get_permissions_for_new_directories();
717
                    for ($i = 0; $i < $num_files; $i++) {
718
                        $entry = $zip->getNameIndex($i);
719
                        if (substr($entry, -1) == '/') {
720
                            continue;
721
                        }
722
723
                        $pos_slash = strpos($entry, '/');
724
                        $entry_without_first_dir = substr($entry, $pos_slash + 1);
725
                        // If there is still a slash, we need to make sure the directories are created.
726
                        if (strpos($entry_without_first_dir, '/') !== false) {
727
                            if (!is_dir($extraction_path.dirname($entry_without_first_dir))) {
728
                                // Create it.
729
                                @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

729
                                /** @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...
730
                            }
731
                        }
732
733
                        $fp = $zip->getStream($entry);
734
                        $ofp = fopen($extraction_path.dirname($entry_without_first_dir).'/'.basename($entry), 'w');
735
736
                        while (!feof($fp)) {
737
                            fwrite($ofp, fread($fp, 8192));
738
                        }
739
740
                        fclose($fp);
741
                        fclose($ofp);
742
                    }
743
                    $result = true;
744
                }
745
            }
746
            $zip->close();
747
        } else {
748
            echo Display::return_message(get_lang('ErrorReadingZip').$info['extension'], 'error', false);
749
        }
750
    } else {
751
        // Simply move the file.
752
        move_uploaded_file($picture['tmp_name'], $cssToUpload.$style_name.'/'.$picture['name']);
753
        $result = true;
754
    }
755
756
    if ($result) {
757
        $fs = new Filesystem();
758
        $fs->mirror(
759
            CSS_UPLOAD_PATH,
760
            api_get_path(SYS_PATH).'web/css/themes/',
761
            null,
762
            ['override' => true]
763
        );
764
    }
765
766
    return $result;
767
}
768
769
/**
770
 * Creates the folder (if needed) and uploads the plugin in it. If the plugin
771
 * is already there and the folder is writeable, overwrite.
772
 *
773
 * @param array $file the file passed to the upload form
774
 *
775
 * @return bool
776
 */
777
function uploadPlugin($file)
778
{
779
    $result = false;
780
    $pluginPath = api_get_path(SYS_PLUGIN_PATH);
781
    $info = pathinfo($file['name']);
782
    if ($info['extension'] == 'zip') {
783
        // Try to open the file and extract it in the theme.
784
        $zip = new ZipArchive();
785
        if ($zip->open($file['tmp_name'])) {
786
            // Make sure all files inside the zip are images or css.
787
            $num_files = $zip->numFiles;
788
            $valid = true;
789
            $single_directory = true;
790
            $invalid_files = [];
791
792
            $allowedFiles = getAllowedFileTypes();
793
            $allowedFiles[] = 'php';
794
            $allowedFiles[] = 'js';
795
            $allowedFiles[] = 'tpl';
796
            $pluginObject = new AppPlugin();
797
            $officialPlugins = $pluginObject->getOfficialPlugins();
798
799
            for ($i = 0; $i < $num_files; $i++) {
800
                $file = $zip->statIndex($i);
801
                if (substr($file['name'], -1) != '/') {
802
                    $path_parts = pathinfo($file['name']);
803
                    if (!in_array($path_parts['extension'], $allowedFiles)) {
804
                        $valid = false;
805
                        $invalid_files[] = $file['name'];
806
                    }
807
                }
808
809
                if (strpos($file['name'], '/') === false) {
810
                    $single_directory = false;
811
                }
812
            }
813
            if (!$valid) {
814
                $error_string = '<ul>';
815
                foreach ($invalid_files as $invalid_file) {
816
                    $error_string .= '<li>'.$invalid_file.'</li>';
817
                }
818
                $error_string .= '</ul>';
819
                echo Display::return_message(
820
                    get_lang('ErrorPluginFilesExtensionsInsideZip').$error_string,
821
                    'error',
822
                    false
823
                );
824
            } else {
825
                // Prevent overwriting an official plugin
826
827
                if (in_array($info['filename'], $officialPlugins)) {
828
                    echo Display::return_message(
829
                        get_lang('ErrorPluginOfficialCannotBeUploaded'),
830
                        'error',
831
                        false
832
                    );
833
                } else {
834
                    // If the zip does not contain a single directory, extract it.
835
                    if (!$single_directory) {
836
                        // Extract zip file.
837
                        $zip->extractTo($pluginPath.$info['filename'].'/');
838
                        $result = true;
839
                    } else {
840
                        $extraction_path = $pluginPath.$info['filename'].'/';
841
                        $mode = api_get_permissions_for_new_directories();
842
                        if (!is_dir($extraction_path)) {
843
                            @mkdir($extraction_path, $mode, true);
844
                        }
845
846
                        for ($i = 0; $i < $num_files; $i++) {
847
                            $entry = $zip->getNameIndex($i);
848
                            if (substr($entry, -1) == '/') {
849
                                continue;
850
                            }
851
852
                            $pos_slash = strpos($entry, '/');
853
                            $entry_without_first_dir = substr($entry, $pos_slash + 1);
854
                            $shortPluginDir = dirname($entry_without_first_dir);
855
                            // If there is still a slash, we need to make sure the directories are created.
856
                            if (strpos($entry_without_first_dir, '/') !== false) {
857
                                if (!is_dir($extraction_path.$shortPluginDir)) {
858
                                    // Create it.
859
                                    @mkdir($extraction_path.$shortPluginDir, $mode, true);
860
                                }
861
                            }
862
863
                            $fp = $zip->getStream($entry);
864
                            $shortPluginDir = dirname($entry_without_first_dir).'/';
865
                            if ($shortPluginDir === './') {
866
                                $shortPluginDir = '';
867
                            }
868
                            $ofp = fopen($extraction_path.$shortPluginDir.basename($entry), 'w');
869
870
                            while (!feof($fp)) {
871
                                fwrite($ofp, fread($fp, 8192));
872
                            }
873
874
                            fclose($fp);
875
                            fclose($ofp);
876
                        }
877
                        $result = true;
878
                    }
879
                }
880
            }
881
            $zip->close();
882
        } else {
883
            echo Display::return_message(get_lang('ErrorReadingZip').$info['extension'], 'error', false);
884
        }
885
    } else {
886
        // Simply move the file.
887
        move_uploaded_file($file['tmp_name'], $pluginPath.'/'.$file['name']);
888
        $result = true;
889
    }
890
891
    return $result;
892
}
893
894
/**
895
 * Store plugin regions.
896
 */
897
function storeRegions()
898
{
899
    $plugin_obj = new AppPlugin();
900
901
    // Get a list of all current 'Plugins' settings
902
    $installed_plugins = $plugin_obj->getInstalledPlugins();
903
    $shortlist_installed = [];
904
    if (!empty($installed_plugins)) {
905
        foreach ($installed_plugins as $plugin) {
906
            if (isset($plugin['subkey'])) {
907
                $shortlist_installed[] = $plugin['subkey'];
908
            }
909
        }
910
    }
911
912
    $plugin_list = $plugin_obj->read_plugins_from_path();
913
914
    foreach ($plugin_list as $plugin) {
915
        if (isset($_POST['plugin_'.$plugin])) {
916
            $areas_to_installed = $_POST['plugin_'.$plugin];
917
            if (!empty($areas_to_installed)) {
918
                $plugin_obj->remove_all_regions($plugin);
919
                foreach ($areas_to_installed as $region) {
920
                    if (!empty($region) && $region != '-1') {
921
                        $plugin_obj->add_to_region($plugin, $region);
922
                    }
923
                }
924
            }
925
        }
926
    }
927
}
928
929
/**
930
 * This function allows easy activating and inactivating of plugins.
931
 *
932
 * @author Patrick Cool <[email protected]>, Ghent University
933
 */
934
function storePlugins()
935
{
936
    $appPlugin = new AppPlugin();
937
    // Get a list of all current 'Plugins' settings
938
    $plugin_list = $appPlugin->read_plugins_from_path();
939
    $installed_plugins = [];
940
941
    foreach ($plugin_list as $plugin) {
942
        if (isset($_POST['plugin_'.$plugin])) {
943
            $appPlugin->install($plugin);
944
            $installed_plugins[] = $plugin;
945
        }
946
    }
947
948
    if (!empty($installed_plugins)) {
949
        $remove_plugins = array_diff($plugin_list, $installed_plugins);
950
    } else {
951
        $remove_plugins = $plugin_list;
952
    }
953
954
    foreach ($remove_plugins as $plugin) {
955
        $appPlugin->uninstall($plugin);
956
    }
957
}
958
959
/**
960
 * This function allows the platform admin to choose which should be the default stylesheet.
961
 *
962
 * @author Patrick Cool <[email protected]>, Ghent University
963
 */
964
function storeStylesheets()
965
{
966
    // Insert the stylesheet.
967
    if (isStyle($_POST['style'])) {
968
        api_set_setting(
969
            'stylesheets',
970
            $_POST['style'],
971
            null,
972
            'stylesheets',
973
            api_get_current_access_url_id()
974
        );
975
    }
976
977
    return true;
978
}
979
980
/**
981
 * This function checks if the given style is a recognize style that exists in the css directory as
982
 * a standalone directory.
983
 *
984
 * @param string $style
985
 *
986
 * @return bool True if this style is recognized, false otherwise
987
 */
988
function isStyle($style)
989
{
990
    $themeList = api_get_themes();
991
992
    return in_array($style, array_keys($themeList));
993
}
994
995
/**
996
 * Search options
997
 * TODO: support for multiple site. aka $_configuration['access_url'] == 1.
998
 *
999
 * @author Marco Villegas <[email protected]>
1000
 */
1001
function handleSearch()
1002
{
1003
    global $SettingsStored, $_configuration;
1004
1005
    require_once api_get_path(LIBRARY_PATH).'specific_fields_manager.lib.php';
1006
    $search_enabled = api_get_setting('search_enabled');
1007
1008
    $form = new FormValidator(
1009
        'search-options',
1010
        'post',
1011
        api_get_self().'?category=Search'
1012
    );
1013
    $values = api_get_settings_options('search_enabled');
1014
    $form->addElement('header', null, get_lang('SearchEnabledTitle'));
1015
1016
    $group = formGenerateElementsGroup($form, $values, 'search_enabled');
1017
1018
    // SearchEnabledComment
1019
    $form->addGroup(
1020
        $group,
1021
        'search_enabled',
1022
        [get_lang('SearchEnabledTitle'), get_lang('SearchEnabledComment')],
1023
        null,
1024
        false
1025
    );
1026
1027
    $search_enabled = api_get_setting('search_enabled');
1028
1029
    if ($form->validate()) {
1030
        $formValues = $form->exportValues();
1031
        setConfigurationSettingsInDatabase($formValues, $_configuration['access_url']);
1032
        $search_enabled = $formValues['search_enabled'];
1033
        echo Display::return_message($SettingsStored, 'confirm');
1034
    }
1035
    $specific_fields = get_specific_field_list();
1036
1037
    if ($search_enabled == 'true') {
1038
        $values = api_get_settings_options('search_show_unlinked_results');
1039
        $group = formGenerateElementsGroup(
1040
            $form,
1041
            $values,
1042
            'search_show_unlinked_results'
1043
        );
1044
        $form->addGroup(
1045
            $group,
1046
            'search_show_unlinked_results',
1047
            [
1048
                get_lang('SearchShowUnlinkedResultsTitle'),
1049
                get_lang('SearchShowUnlinkedResultsComment'),
1050
            ],
1051
            null,
1052
            false
1053
        );
1054
        $default_values['search_show_unlinked_results'] = api_get_setting('search_show_unlinked_results');
1055
1056
        $sf_values = [];
1057
        foreach ($specific_fields as $sf) {
1058
            $sf_values[$sf['code']] = $sf['name'];
1059
        }
1060
        $url = Display::div(
1061
            Display::url(
1062
                get_lang('AddSpecificSearchField'),
1063
                'specific_fields.php'
1064
            ),
1065
            ['class' => 'sectioncomment']
1066
        );
1067
        if (empty($sf_values)) {
1068
            $form->addElement('label', [get_lang('SearchPrefilterPrefix'), $url]);
1069
        } else {
1070
            $form->addElement(
1071
                'select',
1072
                'search_prefilter_prefix',
1073
                [get_lang('SearchPrefilterPrefix'), $url],
1074
                $sf_values,
1075
                ''
1076
            );
1077
            $default_values['search_prefilter_prefix'] = api_get_setting('search_prefilter_prefix');
1078
        }
1079
    }
1080
1081
    $default_values['search_enabled'] = $search_enabled;
1082
1083
    $form->addButtonSave(get_lang('Save'));
1084
    $form->setDefaults($default_values);
1085
1086
    echo '<div id="search-options-form">';
1087
    $form->display();
1088
    echo '</div>';
1089
1090
    if ($search_enabled == 'true') {
1091
        $xapianPath = api_get_path(SYS_UPLOAD_PATH).'plugins/xapian/searchdb';
1092
1093
        /*
1094
        @todo Test the Xapian connection
1095
        if (extension_loaded('xapian')) {
1096
            require_once 'xapian.php';
1097
            try {
1098
                $db = new XapianDatabase($xapianPath.'/');
1099
            } catch (Exception $e) {
1100
                var_dump($e->getMessage());
1101
            }
1102
1103
            require_once api_get_path(LIBRARY_PATH) . 'search/ChamiloIndexer.class.php';
1104
            require_once api_get_path(LIBRARY_PATH) . 'search/IndexableChunk.class.php';
1105
            require_once api_get_path(LIBRARY_PATH) . 'specific_fields_manager.lib.php';
1106
1107
            $indexable = new IndexableChunk();
1108
            $indexable->addValue("content", 'Test');
1109
1110
            $di = new ChamiloIndexer();
1111
            $di->connectDb(NULL, NULL, 'english');
1112
            $di->addChunk($indexable);
1113
            $did = $di->index();
1114
        }
1115
        */
1116
1117
        $xapianLoaded = Display::return_icon('bullet_green.png', get_lang('Ok'));
1118
        $dir_exists = Display::return_icon('bullet_green.png', get_lang('Ok'));
1119
        $dir_is_writable = Display::return_icon('bullet_green.png', get_lang('Ok'));
1120
        $specific_fields_exists = Display::return_icon('bullet_green.png', get_lang('Ok'));
1121
1122
        //Testing specific fields
1123
        if (empty($specific_fields)) {
1124
            $specific_fields_exists = Display::return_icon(
1125
                'bullet_red.png',
1126
                get_lang('AddSpecificSearchField')
1127
            );
1128
        }
1129
        //Testing xapian extension
1130
        if (!extension_loaded('xapian')) {
1131
            $xapianLoaded = Display::return_icon('bullet_red.png', get_lang('Error'));
1132
        }
1133
        //Testing xapian searchdb path
1134
        if (!is_dir($xapianPath)) {
1135
            $dir_exists = Display::return_icon('bullet_red.png', get_lang('Error'));
1136
        }
1137
        //Testing xapian searchdb path is writable
1138
        if (!is_writable($xapianPath)) {
1139
            $dir_is_writable = Display::return_icon('bullet_red.png', get_lang('Error'));
1140
        }
1141
1142
        $data = [];
1143
        $data[] = [get_lang('XapianModuleInstalled'), $xapianLoaded];
1144
        $data[] = [get_lang('DirectoryExists').' - '.$xapianPath, $dir_exists];
1145
        $data[] = [get_lang('IsWritable').' - '.$xapianPath, $dir_is_writable];
1146
        $data[] = [get_lang('SpecificSearchFieldsAvailable'), $specific_fields_exists];
1147
1148
        showSearchSettingsTable($data);
1149
        showSearchToolsStatusTable();
1150
    }
1151
}
1152
1153
/**
1154
 * Wrapper for the templates.
1155
 *
1156
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
1157
 * @author Julio Montoya.
1158
 *
1159
 * @version August 2008
1160
 *
1161
 * @since v1.8.6
1162
 */
1163
function handleTemplates()
1164
{
1165
    /* Drive-by fix to avoid undefined var warnings, without repeating
1166
     * isset() combos all over the place. */
1167
    $action = isset($_GET['action']) ? $_GET['action'] : "invalid";
1168
1169
    if ($action != 'add') {
1170
        echo '<div class="actions" style="margin-left: 1px;">';
1171
        echo '<a href="settings.php?category=Templates&action=add">'.
1172
                Display::return_icon('new_template.png', get_lang('AddTemplate'), '', ICON_SIZE_MEDIUM).'</a>';
1173
        echo '</div>';
1174
    }
1175
1176
    if ($action == 'add' || ($action == 'edit' && is_numeric($_GET['id']))) {
1177
        addEditTemplate();
1178
1179
        // Add event to the system log.
1180
        $user_id = api_get_user_id();
1181
        $category = $_GET['category'];
1182
        Event::addEvent(
1183
            LOG_CONFIGURATION_SETTINGS_CHANGE,
1184
            LOG_CONFIGURATION_SETTINGS_CATEGORY,
1185
            $category,
1186
            api_get_utc_datetime(),
1187
            $user_id
1188
        );
1189
    } else {
1190
        if ($action == 'delete' && is_numeric($_GET['id'])) {
1191
            deleteTemplate($_GET['id']);
1192
1193
            // Add event to the system log
1194
            $user_id = api_get_user_id();
1195
            $category = $_GET['category'];
1196
            Event::addEvent(
1197
                LOG_CONFIGURATION_SETTINGS_CHANGE,
1198
                LOG_CONFIGURATION_SETTINGS_CATEGORY,
1199
                $category,
1200
                api_get_utc_datetime(),
1201
                $user_id
1202
            );
1203
        }
1204
        displayTemplates();
1205
    }
1206
}
1207
1208
/**
1209
 * Display a sortable table with all the templates that the platform administrator has defined.
1210
 *
1211
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
1212
 *
1213
 * @version August 2008
1214
 *
1215
 * @since v1.8.6
1216
 */
1217
function displayTemplates()
1218
{
1219
    $table = new SortableTable(
1220
        'templates',
1221
        'getNumberOfTemplates',
1222
        'getTemplateData',
1223
        1
1224
    );
1225
    $table->set_additional_parameters(
1226
        ['category' => Security::remove_XSS($_GET['category'])]
1227
    );
1228
    $table->set_header(0, get_lang('Image'), true, ['style' => 'width: 101px;']);
1229
    $table->set_header(1, get_lang('Title'));
1230
    $table->set_header(2, get_lang('Actions'), false, ['style' => 'width:50px;']);
1231
    $table->set_column_filter(2, 'actionsFilter');
1232
    $table->set_column_filter(0, 'searchImageFilter');
1233
    $table->display();
1234
}
1235
1236
/**
1237
 * Gets the number of templates that are defined by the platform admin.
1238
 *
1239
 * @return int
1240
 *
1241
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
1242
 *
1243
 * @version August 2008
1244
 *
1245
 * @since v1.8.6
1246
 */
1247
function getNumberOfTemplates()
1248
{
1249
    // Database table definition.
1250
    $table = Database::get_main_table('system_template');
1251
1252
    // The sql statement.
1253
    $sql = "SELECT COUNT(id) AS total FROM $table";
1254
    $result = Database::query($sql);
1255
    $row = Database::fetch_array($result);
1256
1257
    // Returning the number of templates.
1258
    return $row['total'];
1259
}
1260
1261
/**
1262
 * Gets all the template data for the sortable table.
1263
 *
1264
 * @param int    $from            the start of the limit statement
1265
 * @param int    $number_of_items the number of elements that have to be retrieved from the database
1266
 * @param int    $column          the column that is
1267
 * @param string $direction       the sorting direction (ASC or DESC)
1268
 *
1269
 * @return array
1270
 *
1271
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
1272
 *
1273
 * @version August 2008
1274
 *
1275
 * @since v1.8.6
1276
 */
1277
function getTemplateData($from, $number_of_items, $column, $direction)
1278
{
1279
    // Database table definition.
1280
    $table_system_template = Database::get_main_table('system_template');
1281
1282
    $from = (int) $from;
1283
    $number_of_items = (int) $number_of_items;
1284
    $column = (int) $column;
1285
    $direction = !in_array(strtolower(trim($direction)), ['asc', 'desc']) ? 'asc' : $direction;
1286
1287
    // The sql statement.
1288
    $sql = "SELECT image as col0, title as col1, id as col2 FROM $table_system_template";
1289
    $sql .= " ORDER BY col$column $direction ";
1290
    $sql .= " LIMIT $from,$number_of_items";
1291
    $result = Database::query($sql);
1292
    $return = [];
1293
    while ($row = Database::fetch_array($result)) {
1294
        $row['1'] = get_lang($row['1']);
1295
        $return[] = $row;
1296
    }
1297
    // Returning all the information for the sortable table.
1298
    return $return;
1299
}
1300
1301
/**
1302
 * display the edit and delete icons in the sortable table.
1303
 *
1304
 * @param int $id the id of the template
1305
 *
1306
 * @return string code for the link to edit and delete the template
1307
 *
1308
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
1309
 *
1310
 * @version August 2008
1311
 *
1312
 * @since v1.8.6
1313
 */
1314
function actionsFilter($id)
1315
{
1316
    $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>';
1317
    $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>';
1318
1319
    return $return;
1320
}
1321
1322
/**
1323
 * Display the image of the template in the sortable table.
1324
 *
1325
 * @param string $image the image
1326
 *
1327
 * @return string code for the image
1328
 *
1329
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
1330
 *
1331
 * @version August 2008
1332
 *
1333
 * @since v1.8.6
1334
 */
1335
function searchImageFilter($image)
1336
{
1337
    if (!empty($image)) {
1338
        return '<img src="'.api_get_path(WEB_HOME_PATH).'default_platform_document/template_thumb/'.$image.'" alt="'.get_lang('TemplatePreview').'"/>';
1339
    } else {
1340
        return '<img src="'.api_get_path(WEB_HOME_PATH).'default_platform_document/template_thumb/noimage.gif" alt="'.get_lang('NoTemplatePreview').'"/>';
1341
    }
1342
}
1343
1344
/**
1345
 * Add (or edit) a template. This function displays the form and also takes
1346
 * care of uploading the image and storing the information in the database.
1347
 *
1348
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
1349
 *
1350
 * @version August 2008
1351
 *
1352
 * @since v1.8.6
1353
 */
1354
function addEditTemplate()
1355
{
1356
    $em = Database::getManager();
1357
    // Initialize the object.
1358
    $id = isset($_GET['id']) ? (int) $_GET['id'] : 0;
1359
1360
    /** @var SystemTemplate $template */
1361
    $template = $id ? $em->find('ChamiloCoreBundle:SystemTemplate', $id) : new SystemTemplate();
1362
1363
    $form = new FormValidator(
1364
        'template',
1365
        'post',
1366
        'settings.php?category=Templates&action='.Security::remove_XSS($_GET['action']).'&id='.$id
1367
    );
1368
1369
    // Setting the form elements: the header.
1370
    if ($_GET['action'] == 'add') {
1371
        $title = get_lang('AddTemplate');
1372
    } else {
1373
        $title = get_lang('EditTemplate');
1374
    }
1375
    $form->addElement('header', '', $title);
1376
1377
    // Setting the form elements: the title of the template.
1378
    $form->addText('title', get_lang('Title'), false);
1379
    $form->addText('comment', get_lang('Description'), false);
1380
1381
    // Setting the form elements: the content of the template (wysiwyg editor).
1382
    $form->addHtmlEditor(
1383
        'template_text',
1384
        get_lang('Text'),
1385
        true,
1386
        true,
1387
        ['ToolbarSet' => 'Documents', 'Width' => '100%', 'Height' => '400']
1388
    );
1389
1390
    // Setting the form elements: the form to upload an image to be used with the template.
1391
    if (empty($template->getImage())) {
1392
        $form->addElement('file', 'template_image', get_lang('Image'), '');
1393
    }
1394
1395
    // Setting the form elements: a little bit information about the template image.
1396
    $form->addElement('static', 'file_comment', '', get_lang('TemplateImageComment100x70'));
1397
1398
    // Getting all the information of the template when editing a template.
1399
    if ($_GET['action'] === 'edit') {
1400
        $defaults['template_id'] = $id;
1401
        $defaults['template_text'] = $template->getContent();
1402
        // Forcing get_lang().
1403
        $defaults['title'] = $template->getTitle();
1404
        $defaults['comment'] = $template->getComment();
1405
1406
        // Adding an extra field: a hidden field with the id of the template we are editing.
1407
        $form->addElement('hidden', 'template_id');
1408
1409
        // Adding an extra field: a preview of the image that is currently used.
1410
        if (!empty($template->getImage())) {
1411
            $form->addElement(
1412
                'static',
1413
                'template_image_preview',
1414
                '',
1415
                '<img src="'.api_get_path(WEB_HOME_PATH).
1416
                'default_platform_document/template_thumb/'.$template->getImage()
1417
                    .'" alt="'.get_lang('TemplatePreview')
1418
                    .'"/>'
1419
            );
1420
            $form->addCheckBox('delete_image', null, get_lang('DeletePicture'));
1421
        } else {
1422
            $form->addElement(
1423
                'static',
1424
                'template_image_preview',
1425
                '',
1426
                '<img src="'.api_get_path(WEB_HOME_PATH).'default_platform_document/template_thumb/noimage.gif" alt="'.get_lang('NoTemplatePreview').'"/>'
1427
            );
1428
        }
1429
1430
        // Setting the information of the template that we are editing.
1431
        $form->setDefaults($defaults);
1432
    }
1433
    // Setting the form elements: the submit button.
1434
    $form->addButtonSave(get_lang('Ok'), 'submit');
1435
1436
    // Setting the rules: the required fields.
1437
    if (empty($template->getImage())) {
1438
        $form->addRule(
1439
            'template_image',
1440
            get_lang('ThisFieldIsRequired'),
1441
            'required'
1442
        );
1443
        $form->addRule('title', get_lang('ThisFieldIsRequired'), 'required');
1444
    }
1445
1446
    // if the form validates (complies to all rules) we save the information,
1447
    // else we display the form again (with error message if needed)
1448
    if ($form->validate()) {
1449
        $check = Security::check_token('post');
1450
1451
        if ($check) {
1452
            // Exporting the values.
1453
            $values = $form->exportValues();
1454
            $isDelete = null;
1455
            if (isset($values['delete_image'])) {
1456
                $isDelete = $values['delete_image'];
1457
            }
1458
1459
            // Upload the file.
1460
            if (!empty($_FILES['template_image']['name'])) {
1461
                $upload_ok = process_uploaded_file($_FILES['template_image']);
1462
1463
                if ($upload_ok) {
1464
                    // Try to add an extension to the file if it hasn't one.
1465
                    $new_file_name = add_ext_on_mime(
1466
                        stripslashes($_FILES['template_image']['name']),
1467
                        $_FILES['template_image']['type']
1468
                    );
1469
1470
                    // The upload directory.
1471
                    $upload_dir = api_get_path(SYS_HOME_PATH).'default_platform_document/template_thumb/';
1472
1473
                    // Create the directory if it does not exist.
1474
                    if (!is_dir($upload_dir)) {
1475
                        mkdir($upload_dir, api_get_permissions_for_new_directories());
1476
                    }
1477
1478
                    // Resize the preview image to max default and upload.
1479
                    $temp = new Image($_FILES['template_image']['tmp_name']);
1480
                    $picture_info = $temp->get_image_info();
1481
1482
                    $max_width_for_picture = 100;
1483
                    if ($picture_info['width'] > $max_width_for_picture) {
1484
                        $temp->resize($max_width_for_picture);
1485
                    }
1486
                    $temp->send_image($upload_dir.$new_file_name);
1487
                }
1488
            }
1489
1490
            // Store the information in the database (as insert or as update).
1491
            //$bootstrap = api_get_css(api_get_path(WEB_PUBLIC_PATH).'assets/bootstrap/dist/css/bootstrap.min.css');
1492
            $viewport = '<meta name="viewport" content="width=device-width, initial-scale=1.0">';
1493
1494
            if ($_GET['action'] == 'add') {
1495
                $templateContent = '<head>'.$viewport.'<title>'.$values['title'].'</title></head>'
1496
                    .$values['template_text'];
1497
                $template
1498
                    ->setTitle($values['title'])
1499
                    ->setComment(Security::remove_XSS($values['comment']))
1500
                    ->setContent(Security::remove_XSS($templateContent, COURSEMANAGERLOWSECURITY))
1501
                    ->setImage($new_file_name);
1502
                $em->persist($template);
1503
                $em->flush();
1504
1505
                // Display a feedback message.
1506
                echo Display::return_message(
1507
                    get_lang('TemplateAdded'),
1508
                    'confirm'
1509
                );
1510
                echo '<a href="settings.php?category=Templates&action=add">'.
1511
                    Display::return_icon('new_template.png', get_lang('AddTemplate'), '', ICON_SIZE_MEDIUM).
1512
                    '</a>';
1513
            } else {
1514
                $templateContent = $values['template_text'];
1515
                $template
1516
                    ->setTitle($values['title'])
1517
                    ->setComment(Security::remove_XSS($values['comment']))
1518
                    ->setContent(Security::remove_XSS($templateContent, COURSEMANAGERLOWSECURITY));
1519
1520
                if ($isDelete) {
1521
                    $filePath = api_get_path(SYS_HOME_PATH).'default_platform_document/template_thumb/'.$template->getImage();
1522
                    if (file_exists($filePath)) {
1523
                        unlink($filePath);
1524
                    }
1525
                    $template->setImage(null);
1526
                }
1527
1528
                if (!empty($new_file_name)) {
1529
                    $template->setImage($new_file_name);
1530
                }
1531
1532
                $em->persist($template);
1533
                $em->flush();
1534
1535
                // Display a feedback message.
1536
                echo Display::return_message(get_lang('TemplateEdited'), 'confirm');
1537
            }
1538
        }
1539
        Security::clear_token();
1540
        displayTemplates();
1541
    } else {
1542
        $token = Security::get_token();
1543
        $form->addElement('hidden', 'sec_token');
1544
        $form->setConstants(['sec_token' => $token]);
1545
        // Display the form.
1546
        $form->display();
1547
    }
1548
}
1549
1550
/**
1551
 * Delete a template.
1552
 *
1553
 * @param int $id the id of the template that has to be deleted
1554
 *
1555
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
1556
 *
1557
 * @version August 2008
1558
 *
1559
 * @since v1.8.6
1560
 */
1561
function deleteTemplate($id)
1562
{
1563
    $id = intval($id);
1564
    // First we remove the image.
1565
    $table = Database::get_main_table('system_template');
1566
    $sql = "SELECT * FROM $table WHERE id = $id";
1567
    $result = Database::query($sql);
1568
    $row = Database::fetch_array($result);
1569
    if (!empty($row['image'])) {
1570
        @unlink(api_get_path(SYS_HOME_PATH).'default_platform_document/template_thumb/'.$row['image']);
1571
    }
1572
1573
    // Now we remove it from the database.
1574
    $sql = "DELETE FROM $table WHERE id = $id";
1575
    Database::query($sql);
1576
1577
    // Display a feedback message.
1578
    echo Display::return_message(get_lang('TemplateDeleted'), 'confirm');
1579
}
1580
1581
/**
1582
 * Returns the list of timezone identifiers used to populate the select
1583
 * This function is called through a call_user_func() in the generate_settings_form function.
1584
 *
1585
 * @return array List of timezone identifiers
1586
 *
1587
 * @author Guillaume Viguier <[email protected]>
1588
 *
1589
 * @since Chamilo 1.8.7
1590
 */
1591
function select_timezone_value()
1592
{
1593
    return api_get_timezones();
1594
}
1595
1596
/**
1597
 * Returns an array containing the list of options used to populate the gradebook_number_decimals variable
1598
 * This function is called through a call_user_func() in the generate_settings_form function.
1599
 *
1600
 * @return array List of gradebook_number_decimals options
1601
 *
1602
 * @author Guillaume Viguier <[email protected]>
1603
 */
1604
function select_gradebook_number_decimals()
1605
{
1606
    return ['0', '1', '2'];
1607
}
1608
1609
/**
1610
 * Get the options for a select element to select gradebook default grade model.
1611
 *
1612
 * @return array
1613
 */
1614
function select_gradebook_default_grade_model_id()
1615
{
1616
    $grade_model = new GradeModel();
1617
    $models = $grade_model->get_all();
1618
    $options = [];
1619
    $options[-1] = get_lang('None');
1620
1621
    if (!empty($models)) {
1622
        foreach ($models as $model) {
1623
            $options[$model['id']] = $model['name'];
1624
        }
1625
    }
1626
1627
    return $options;
1628
}
1629
1630
/**
1631
 * @param array $settings
1632
 * @param array $settings_by_access_list
1633
 *
1634
 * @return FormValidator
1635
 */
1636
function generateSettingsForm($settings, $settings_by_access_list)
1637
{
1638
    global $_configuration, $settings_to_avoid, $convert_byte_to_mega_list;
1639
    $table_settings_current = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
1640
1641
    $form = new FormValidator(
1642
        'settings',
1643
        'post',
1644
        api_get_path(WEB_CODE_PATH).'admin/settings.php?category='.Security::remove_XSS($_GET['category'])
1645
    );
1646
    $form->protect();
1647
1648
    $form->addElement(
1649
        'hidden',
1650
        'search_field',
1651
        (!empty($_GET['search_field']) ? Security::remove_XSS($_GET['search_field']) : null)
1652
    );
1653
1654
    $url_id = api_get_current_access_url_id();
1655
    /*
1656
    if (!empty($_configuration['multiple_access_urls']) && api_is_global_platform_admin() && $url_id == 1) {
1657
        $group = array();
1658
        $group[] = $form->createElement('button', 'mark_all', get_lang('MarkAll'));
1659
        $group[] = $form->createElement('button', 'unmark_all', get_lang('UnmarkAll'));
1660
        $form->addGroup($group, 'buttons_in_action_right');
1661
    }*/
1662
1663
    $default_values = [];
1664
    $url_info = api_get_access_url($url_id);
1665
    $i = 0;
1666
    $addedSettings = [];
1667
    foreach ($settings as $row) {
1668
        if (in_array($row['variable'], array_keys($settings_to_avoid))) {
1669
            continue;
1670
        }
1671
1672
        if (in_array($row['variable'], $addedSettings)) {
1673
            continue;
1674
        }
1675
1676
        $addedSettings[] = $row['variable'];
1677
1678
        if (!empty($_configuration['multiple_access_urls'])) {
1679
            if (api_is_global_platform_admin()) {
1680
                if ($row['access_url_locked'] == 0) {
1681
                    if ($url_id == 1) {
1682
                        if ($row['access_url_changeable'] == '1') {
1683
                            $form->addElement(
1684
                                'html',
1685
                                '<div class="pull-right"><a class="share_this_setting" data_status = "0"  data_to_send = "'.$row['variable'].'" href="javascript:void(0);">'.
1686
                                Display::return_icon('shared_setting.png', get_lang('ChangeSharedSetting'), null, ICON_SIZE_MEDIUM).'</a></div>'
1687
                            );
1688
                        } else {
1689
                            $form->addElement(
1690
                                'html',
1691
                                '<div class="pull-right"><a class="share_this_setting" data_status = "1" data_to_send = "'.$row['variable'].'" href="javascript:void(0);">'.
1692
                                Display::return_icon('shared_setting_na.png', get_lang('ChangeSharedSetting'), null, ICON_SIZE_MEDIUM).'</a></div>'
1693
                            );
1694
                        }
1695
                    } else {
1696
                        if ($row['access_url_changeable'] == '1') {
1697
                            $form->addElement(
1698
                                'html',
1699
                                '<div class="pull-right">'.
1700
                                Display::return_icon('shared_setting.png', get_lang('ChangeSharedSetting'), null, ICON_SIZE_MEDIUM).'</div>'
1701
                            );
1702
                        } else {
1703
                            $form->addElement(
1704
                                'html',
1705
                                '<div class="pull-right">'.
1706
                                Display::return_icon('shared_setting_na.png', get_lang('ChangeSharedSetting'), null, ICON_SIZE_MEDIUM).'</div>'
1707
                            );
1708
                        }
1709
                    }
1710
                }
1711
            }
1712
        }
1713
1714
        $hideme = [];
1715
        $hide_element = false;
1716
1717
        if ($_configuration['access_url'] != 1) {
1718
            if ($row['access_url_changeable'] == 0) {
1719
                // We hide the element in other cases (checkbox, radiobutton) we 'freeze' the element.
1720
                $hide_element = true;
1721
                $hideme = ['disabled'];
1722
            } elseif ($url_info['active'] == 1) {
1723
                // We show the elements.
1724
                if (empty($row['variable'])) {
1725
                    $row['variable'] = 0;
1726
                }
1727
                if (empty($row['subkey'])) {
1728
                    $row['subkey'] = 0;
1729
                }
1730
                if (empty($row['category'])) {
1731
                    $row['category'] = 0;
1732
                }
1733
                if (isset($settings_by_access_list[$row['variable']]) &&
1734
                    isset($settings_by_access_list[$row['variable']][$row['subkey']]) &&
1735
                    is_array($settings_by_access_list[$row['variable']][$row['subkey']][$row['category']])
1736
                ) {
1737
                    // We are sure that the other site have a selected value.
1738
                    if ($settings_by_access_list[$row['variable']][$row['subkey']][$row['category']]['selected_value'] != '') {
1739
                        $row['selected_value'] = $settings_by_access_list[$row['variable']][$row['subkey']][$row['category']]['selected_value'];
1740
                    }
1741
                }
1742
                // There is no else{} statement because we load the default $row['selected_value'] of the main Chamilo site.
1743
            }
1744
        }
1745
1746
        switch ($row['type']) {
1747
            case 'textfield':
1748
                if (in_array($row['variable'], $convert_byte_to_mega_list)) {
1749
                    $form->addElement(
1750
                        'text',
1751
                        $row['variable'],
1752
                        [
1753
                            get_lang($row['title']),
1754
                            get_lang($row['comment']),
1755
                            get_lang('MB'),
1756
                        ],
1757
                        ['maxlength' => '8', 'aria-label' => get_lang($row['title'])]
1758
                    );
1759
                    $form->applyFilter($row['variable'], 'html_filter');
1760
                    $default_values[$row['variable']] = round($row['selected_value'] / 1024 / 1024, 1);
1761
                } elseif ($row['variable'] == 'account_valid_duration') {
1762
                    $form->addElement(
1763
                        'text',
1764
                        $row['variable'],
1765
                        [
1766
                            get_lang($row['title']),
1767
                            get_lang($row['comment']),
1768
                        ],
1769
                        ['maxlength' => '5', 'aria-label' => get_lang($row['title'])]
1770
                    );
1771
                    $form->applyFilter($row['variable'], 'html_filter');
1772
1773
                    // For platform character set selection:
1774
                    // Conversion of the textfield to a select box with valid values.
1775
                    $default_values[$row['variable']] = $row['selected_value'];
1776
                } elseif ($row['variable'] == 'platform_charset') {
1777
                    break;
1778
                } else {
1779
                    $hideme['class'] = 'col-md-4';
1780
                    $hideme['aria-label'] = get_lang($row['title']);
1781
                    $form->addElement(
1782
                        'text',
1783
                        $row['variable'],
1784
                        [
1785
                            get_lang($row['title']),
1786
                            get_lang($row['comment']),
1787
                        ],
1788
                        $hideme
1789
                    );
1790
                    $form->applyFilter($row['variable'], 'html_filter');
1791
                    $default_values[$row['variable']] = $row['selected_value'];
1792
                }
1793
                break;
1794
            case 'textarea':
1795
                if ($row['variable'] == 'header_extra_content') {
1796
                    $file = api_get_home_path().'header_extra_content.txt';
1797
                    $value = '';
1798
                    if (file_exists($file)) {
1799
                        $value = file_get_contents($file);
1800
                    }
1801
                    $form->addElement(
1802
                        'textarea',
1803
                        $row['variable'],
1804
                        [get_lang($row['title']), get_lang($row['comment'])],
1805
                        ['rows' => '10', 'id' => $row['variable']],
1806
                        $hideme
1807
                    );
1808
                    $default_values[$row['variable']] = $value;
1809
                } elseif ($row['variable'] == 'footer_extra_content') {
1810
                    $file = api_get_home_path().'footer_extra_content.txt';
1811
                    $value = '';
1812
                    if (file_exists($file)) {
1813
                        $value = file_get_contents($file);
1814
                    }
1815
                    $form->addElement(
1816
                        'textarea',
1817
                        $row['variable'],
1818
                        [get_lang($row['title']), get_lang($row['comment'])],
1819
                        ['rows' => '10', 'id' => $row['variable']],
1820
                        $hideme
1821
                    );
1822
                    $default_values[$row['variable']] = $value;
1823
                } else {
1824
                    $form->addElement(
1825
                        'textarea',
1826
                        $row['variable'],
1827
                        [get_lang($row['title']),
1828
                        get_lang($row['comment']), ],
1829
                        ['rows' => '10', 'id' => $row['variable']],
1830
                        $hideme
1831
                    );
1832
                    $default_values[$row['variable']] = $row['selected_value'];
1833
                }
1834
                break;
1835
            case 'radio':
1836
                $values = api_get_settings_options($row['variable']);
1837
                $group = [];
1838
                if (is_array($values)) {
1839
                    foreach ($values as $key => $value) {
1840
                        $element = &$form->createElement(
1841
                            'radio',
1842
                            $row['variable'],
1843
                            '',
1844
                            get_lang($value['display_text']),
1845
                            $value['value']
1846
                        );
1847
                        if ($hide_element) {
1848
                            $element->freeze();
1849
                        }
1850
                        $group[] = $element;
1851
                    }
1852
                }
1853
                $form->addGroup(
1854
                    $group,
1855
                    $row['variable'],
1856
                    [get_lang($row['title']), get_lang($row['comment'])],
1857
                    null,
1858
                    false
1859
                );
1860
                $default_values[$row['variable']] = $row['selected_value'];
1861
                break;
1862
            case 'checkbox':
1863
                // 1. We collect all the options of this variable.
1864
                $sql = "SELECT * FROM $table_settings_current
1865
                        WHERE variable='".$row['variable']."' AND access_url =  1";
1866
1867
                $result = Database::query($sql);
1868
                $group = [];
1869
                while ($rowkeys = Database::fetch_array($result)) {
1870
                    // Profile tab option should be hidden when the social tool is enabled.
1871
                    if (api_get_setting('allow_social_tool') == 'true') {
1872
                        if ($rowkeys['variable'] === 'show_tabs' && $rowkeys['subkey'] === 'my_profile') {
1873
                            continue;
1874
                        }
1875
                    }
1876
1877
                    // Hiding the gradebook option.
1878
                    if ($rowkeys['variable'] === 'show_tabs' && $rowkeys['subkey'] === 'my_gradebook') {
1879
                        continue;
1880
                    }
1881
1882
                    $element = &$form->createElement(
1883
                        'checkbox',
1884
                        $rowkeys['subkey'],
1885
                        '',
1886
                        get_lang($rowkeys['subkeytext'])
1887
                    );
1888
1889
                    if ($row['access_url_changeable'] == 1) {
1890
                        // 2. We look into the DB if there is a setting for a specific access_url.
1891
                        $access_url = $_configuration['access_url'];
1892
                        if (empty($access_url)) {
1893
                            $access_url = 1;
1894
                        }
1895
                        $sql = "SELECT selected_value FROM $table_settings_current
1896
                                WHERE
1897
                                    variable='".$rowkeys['variable']."' AND
1898
                                    subkey='".$rowkeys['subkey']."' AND
1899
                                    subkeytext='".$rowkeys['subkeytext']."' AND
1900
                                    access_url =  $access_url";
1901
                        $result_access = Database::query($sql);
1902
                        $row_access = Database::fetch_array($result_access);
1903
                        if ($row_access['selected_value'] === 'true' && !$form->isSubmitted()) {
1904
                            $element->setChecked(true);
1905
                        }
1906
                    } else {
1907
                        if ($rowkeys['selected_value'] === 'true' && !$form->isSubmitted()) {
1908
                            $element->setChecked(true);
1909
                        }
1910
                    }
1911
                    if ($hide_element) {
1912
                        $element->freeze();
1913
                    }
1914
                    $group[] = $element;
1915
                }
1916
                $form->addGroup(
1917
                    $group,
1918
                    $row['variable'],
1919
                    [get_lang($row['title']), get_lang($row['comment'])],
1920
                    null
1921
                );
1922
                break;
1923
            case 'link':
1924
                $form->addElement(
1925
                    'static',
1926
                    null,
1927
                    [get_lang($row['title']), get_lang($row['comment'])],
1928
                    get_lang('CurrentValue').' : '.$row['selected_value'],
1929
                    $hideme
1930
                );
1931
                break;
1932
            case 'select':
1933
                /*
1934
                * To populate the list of options, the select type dynamically calls a
1935
                * function that must be called select_ + the name of the variable being displayed.
1936
                * The functions being called must be added to the file settings.lib.php.
1937
                */
1938
                $form->addElement(
1939
                    'select',
1940
                    $row['variable'],
1941
                    [get_lang($row['title']), get_lang($row['comment'])],
1942
                    call_user_func('select_'.$row['variable']),
1943
                    $hideme
1944
                );
1945
                $default_values[$row['variable']] = $row['selected_value'];
1946
                break;
1947
            case 'custom':
1948
                break;
1949
            case 'select_course':
1950
                $courseSelectOptions = [];
1951
                if (!empty($row['selected_value'])) {
1952
                    $course = api_get_course_entity($row['selected_value']);
1953
                    if ($course) {
1954
                        $courseSelectOptions[$course->getId()] = $course->getTitle();
1955
                    }
1956
                }
1957
1958
                $form->addElement(
1959
                    'select_ajax',
1960
                    $row['variable'],
1961
                    [get_lang($row['title']), get_lang($row['comment'])],
1962
                    $courseSelectOptions,
1963
                    ['url' => api_get_path(WEB_AJAX_PATH).'course.ajax.php?a=search_course']
1964
                );
1965
                $default_values[$row['variable']] = $row['selected_value'];
1966
                break;
1967
        }
1968
1969
        switch ($row['variable']) {
1970
            case 'upload_extensions_replace_by':
1971
                $default_values[$row['variable']] = api_replace_dangerous_char(
1972
                    str_replace('.', '', $default_values[$row['variable']])
1973
                );
1974
                break;
1975
            case 'pdf_export_watermark_enable':
1976
                $url = PDF::get_watermark(null);
1977
1978
                if ($url != false) {
1979
                    $delete_url = '<a href="?delete_watermark">'.get_lang('DelImage').' '.Display::return_icon('delete.png', get_lang('DelImage')).'</a>';
1980
                    $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>');
1981
                }
1982
1983
                $form->addElement('file', 'pdf_export_watermark_path', get_lang('AddWaterMark'));
1984
                $allowed_picture_types = ['jpg', 'jpeg', 'png', 'gif'];
1985
                $form->addRule(
1986
                    'pdf_export_watermark_path',
1987
                    get_lang('OnlyImagesAllowed').' ('.implode(',', $allowed_picture_types).')',
1988
                    'filetype',
1989
                    $allowed_picture_types
1990
                );
1991
1992
                break;
1993
            case 'timezone_value':
1994
                $timezone = $row['selected_value'];
1995
                if (empty($timezone)) {
1996
                    $timezone = api_get_timezone();
1997
                }
1998
                $form->addLabel('', sprintf(get_lang('LocalTimeUsingPortalTimezoneXIsY'), $timezone, api_get_local_time()));
1999
                break;
2000
        }
2001
    } // end for
2002
2003
    if (!empty($settings)) {
2004
        $form->setDefaults($default_values);
2005
    }
2006
    $form->addHtml('<div class="bottom_actions">');
2007
    $form->addButtonSave(get_lang('SaveSettings'));
2008
    $form->addHtml('</div>');
2009
2010
    return $form;
2011
}
2012
2013
/**
2014
 * Searches a platform setting in all categories except from the Plugins category.
2015
 *
2016
 * @param string $search
2017
 *
2018
 * @return array
2019
 */
2020
function searchSetting($search)
2021
{
2022
    if (empty($search)) {
2023
        return [];
2024
    }
2025
    $table_settings_current = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2026
    $sql = "SELECT * FROM $table_settings_current
2027
            WHERE category <> 'Plugins' ORDER BY id ASC ";
2028
    $result = Database::store_result(Database::query($sql), 'ASSOC');
2029
    $settings = [];
2030
2031
    $search = api_strtolower($search);
2032
2033
    if (!empty($result)) {
2034
        foreach ($result as $setting) {
2035
            $found = false;
2036
2037
            $title = api_strtolower(get_lang($setting['title']));
2038
            // try the title
2039
            if (strpos($title, $search) === false) {
2040
                $comment = api_strtolower(get_lang($setting['comment']));
2041
                //Try the comment
2042
                if (strpos($comment, $search) === false) {
2043
                    //Try the variable name
2044
                    if (strpos($setting['variable'], $search) === false) {
2045
                        continue;
2046
                    } else {
2047
                        $found = true;
2048
                    }
2049
                } else {
2050
                    $found = true;
2051
                }
2052
            } else {
2053
                $found = true;
2054
            }
2055
            if ($found) {
2056
                $settings[] = $setting;
2057
            }
2058
        }
2059
    }
2060
2061
    return $settings;
2062
}
2063
/**
2064
 * Helper function to generates a form elements group.
2065
 *
2066
 * @param object $form   The form where the elements group has to be added
2067
 * @param array  $values Values to browse through
2068
 *
2069
 * @return array
2070
 */
2071
function formGenerateElementsGroup($form, $values, $elementName)
2072
{
2073
    $group = [];
2074
    if (is_array($values)) {
2075
        foreach ($values as $key => $value) {
2076
            $element = &$form->createElement('radio', $elementName, '', get_lang($value['display_text']), $value['value']);
2077
            $group[] = $element;
2078
        }
2079
    }
2080
2081
    return $group;
2082
}
2083
/**
2084
 * Helper function with allowed file types for CSS.
2085
 *
2086
 * @return array Array of file types (no indexes)
2087
 */
2088
function getAllowedFileTypes()
2089
{
2090
    $allowedFiles = [
2091
        'css',
2092
        'zip',
2093
        'jpeg',
2094
        'jpg',
2095
        'png',
2096
        'gif',
2097
        'ico',
2098
        'psd',
2099
        'xcf',
2100
        'svg',
2101
        'webp',
2102
        'woff',
2103
        'woff2',
2104
        'md',
2105
        'html',
2106
        'xml',
2107
        'markdown',
2108
        'txt',
2109
    ];
2110
2111
    return $allowedFiles;
2112
}
2113
/**
2114
 * Helper function to set settings in the database.
2115
 *
2116
 * @param array $parameters List of values
2117
 * @param int   $accessUrl  The current access URL
2118
 */
2119
function setConfigurationSettingsInDatabase($parameters, $accessUrl)
2120
{
2121
    api_set_settings_category('Search', 'false', $accessUrl);
2122
    // Save the settings.
2123
    foreach ($parameters as $key => $value) {
2124
        api_set_setting($key, $value, null, null);
2125
    }
2126
}
2127
2128
/**
2129
 * Helper function to show the status of the search settings table.
2130
 *
2131
 * @param array $data Data to show
2132
 */
2133
function showSearchSettingsTable($data)
2134
{
2135
    echo Display::tag('h3', get_lang('Settings'));
2136
    $table = new SortableTableFromArray($data);
2137
    $table->set_header(0, get_lang('Setting'), false);
2138
    $table->set_header(1, get_lang('Status'), false);
2139
    echo $table->display();
2140
}
2141
/**
2142
 * Helper function to show status table for each command line tool installed.
2143
 */
2144
function showSearchToolsStatusTable()
2145
{
2146
    //@todo windows support
2147
    if (api_is_windows_os() == false) {
2148
        $list_of_programs = ['pdftotext', 'ps2pdf', 'catdoc', 'html2text', 'unrtf', 'catppt', 'xls2csv'];
2149
        foreach ($list_of_programs as $program) {
2150
            $output = [];
2151
            $ret_val = null;
2152
            exec("which $program", $output, $ret_val);
2153
2154
            if (!$output) {
2155
                $output[] = '';
2156
            }
2157
2158
            $icon = Display::return_icon('bullet_red.png', get_lang('NotInstalled'));
2159
            if (!empty($output[0])) {
2160
                $icon = Display::return_icon('bullet_green.png', get_lang('Installed'));
2161
            }
2162
            $data2[] = [$program, $output[0], $icon];
2163
        }
2164
        echo Display::tag('h3', get_lang('ProgramsNeededToConvertFiles'));
2165
        $table = new SortableTableFromArray($data2);
2166
        $table->set_header(0, get_lang('Program'), false);
2167
        $table->set_header(1, get_lang('Path'), false);
2168
        $table->set_header(2, get_lang('Status'), false);
2169
        echo $table->display();
2170
    } else {
2171
        echo Display::return_message(
2172
            get_lang('YouAreUsingChamiloInAWindowsPlatformSadlyYouCantConvertDocumentsInOrderToSearchTheContentUsingThisTool'),
2173
            'warning'
2174
        );
2175
    }
2176
}
2177
/**
2178
 * Helper function to generate and show CSS Zip download message.
2179
 *
2180
 * @param string $style Style path
2181
 */
2182
function generateCSSDownloadLink($style)
2183
{
2184
    $arch = api_get_path(SYS_ARCHIVE_PATH).$style.'.zip';
2185
    $themeDir = Template::getThemeDir($style);
2186
    $dir = api_get_path(SYS_CSS_PATH).$themeDir;
2187
    $check = Security::check_abs_path(
2188
        $dir,
2189
        api_get_path(SYS_CSS_PATH).'themes'
2190
    );
2191
    if (is_dir($dir) && $check) {
2192
        $zip = new PclZip($arch);
2193
        // Remove path prefix except the style name and put file on disk
2194
        $zip->create($dir, PCLZIP_OPT_REMOVE_PATH, dirname($dir));
2195
        $url = api_get_path(WEB_CODE_PATH).'course_info/download.php?archive_path=&archive='.str_replace(api_get_path(SYS_ARCHIVE_PATH), '', $arch);
2196
2197
        //@TODO: use more generic script to download.
2198
        $str = '<a class="btn btn-primary btn-large" href="'.$url.'">'.get_lang('ClickHereToDownloadTheFile').'</a>';
2199
        echo Display::return_message($str, 'normal', false);
2200
    } else {
2201
        echo Display::return_message(get_lang('FileNotFound'), 'warning');
2202
    }
2203
}
2204
2205
/**
2206
 * Helper function to tell if the style is changeable in the current URL.
2207
 *
2208
 * @return bool $changeable Whether the style can be changed in this URL or not
2209
 */
2210
function isStyleChangeable()
2211
{
2212
    $changeable = false;
2213
    $urlId = api_get_current_access_url_id();
2214
    if ($urlId) {
2215
        $style_info = api_get_settings('stylesheets', '', 1, 0);
2216
        $url_info = api_get_access_url($urlId);
2217
        if ($style_info[0]['access_url_changeable'] == 1 && $url_info['active'] == 1) {
2218
            $changeable = true;
2219
        }
2220
    } else {
2221
        $changeable = true;
2222
    }
2223
2224
    return $changeable;
2225
}
2226
2227
/**
2228
 * Get all settings of one category prepared for display in admin/settings.php.
2229
 *
2230
 * @param string $category
2231
 *
2232
 * @return array
2233
 */
2234
function getCategorySettings($category = '')
2235
{
2236
    $url_id = api_get_current_access_url_id();
2237
    $settings_by_access_list = [];
2238
2239
    if ($url_id == 1) {
2240
        $settings = api_get_settings($category, 'group', $url_id);
2241
    } else {
2242
        $url_info = api_get_access_url($url_id);
2243
        if ($url_info['active'] == 1) {
2244
            $categoryToSearch = $category;
2245
            if ($category == 'search_setting') {
2246
                $categoryToSearch = '';
2247
            }
2248
            // The default settings of Chamilo
2249
            $settings = api_get_settings($categoryToSearch, 'group', 1, 0);
2250
            // The settings that are changeable from a particular site.
2251
            $settings_by_access = api_get_settings($categoryToSearch, 'group', $url_id, 1);
2252
2253
            foreach ($settings_by_access as $row) {
2254
                if (empty($row['variable'])) {
2255
                    $row['variable'] = 0;
2256
                }
2257
                if (empty($row['subkey'])) {
2258
                    $row['subkey'] = 0;
2259
                }
2260
                if (empty($row['category'])) {
2261
                    $row['category'] = 0;
2262
                }
2263
2264
                // One more validation if is changeable.
2265
                if ($row['access_url_changeable'] == 1) {
2266
                    $settings_by_access_list[$row['variable']][$row['subkey']][$row['category']] = $row;
2267
                } else {
2268
                    $settings_by_access_list[$row['variable']][$row['subkey']][$row['category']] = [];
2269
                }
2270
            }
2271
        }
2272
    }
2273
2274
    if (isset($category) && $category == 'search_setting') {
2275
        if (!empty($_REQUEST['search_field'])) {
2276
            $settings = searchSetting($_REQUEST['search_field']);
2277
        }
2278
    }
2279
2280
    return [
2281
        'settings' => $settings,
2282
        'settings_by_access_list' => $settings_by_access_list,
2283
    ];
2284
}
2285