Issues (2029)

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
        api_flush_settings_cache(api_get_current_access_url_id());
40
        echo Display::return_message(get_lang('SettingsStored'), 'confirmation');
41
    }
42
43
    $plugin_obj = new AppPlugin();
44
    $installed_plugins = $plugin_obj->getInstalledPlugins();
45
46
    echo '<form name="plugins" method="post" action="'.api_get_self().'?category='.Security::remove_XSS($_GET['category']).'">';
47
    echo '<table class="table table-hover table-striped data_table">';
48
    echo '<tr>';
49
    echo '<th width="400px">';
50
    echo get_lang('Plugin');
51
    echo '</th><th>';
52
    echo get_lang('Regions');
53
    echo '</th>';
54
    echo '</th>';
55
    echo '</tr>';
56
57
    /* We display all the possible plugins and the checkboxes */
58
    $plugin_region_list = [];
59
    $my_plugin_list = $plugin_obj->get_plugin_regions();
60
    foreach ($my_plugin_list as $plugin_item) {
61
        $plugin_region_list[$plugin_item] = $plugin_item;
62
    }
63
64
    // Removing course tool
65
    unset($plugin_region_list['course_tool_plugin']);
66
67
    foreach ($installed_plugins as $pluginName) {
68
        $plugin_info_file = api_get_path(SYS_PLUGIN_PATH).$pluginName.'/plugin.php';
69
70
        if (file_exists($plugin_info_file)) {
71
            $plugin_info = [];
72
            require $plugin_info_file;
73
            if (isset($_GET['name']) && $_GET['name'] === $pluginName) {
74
                echo '<tr class="row_selected">';
75
            } else {
76
                echo '<tr>';
77
            }
78
            echo '<td>';
79
            echo '<h4>'.$plugin_info['title'].' <small>v'.$plugin_info['version'].'</small></h4>';
80
            echo '<p>'.$plugin_info['comment'].'</p>';
81
            echo '</td><td>';
82
            $selected_plugins = $plugin_obj->get_areas_by_plugin($pluginName);
83
            $region_list = [];
84
            $isAdminPlugin = isset($plugin_info['is_admin_plugin']) && $plugin_info['is_admin_plugin'];
85
            $isCoursePlugin = isset($plugin_info['is_course_plugin']) && $plugin_info['is_course_plugin'];
86
87
            if (!$isAdminPlugin && !$isCoursePlugin) {
88
                $region_list = $plugin_region_list;
89
            } else {
90
                if ($isAdminPlugin) {
91
                    $region_list['menu_administrator'] = 'menu_administrator';
92
                }
93
                if ($isCoursePlugin) {
94
                    $region_list['course_tool_plugin'] = 'course_tool_plugin';
95
                }
96
            }
97
98
            echo Display::select(
99
                'plugin_'.$pluginName.'[]',
100
                $region_list,
101
                $selected_plugins,
102
                ['multiple' => 'multiple', 'style' => 'width:500px'],
103
                true,
104
                get_lang('None')
105
            );
106
            echo '</td></tr>';
107
        }
108
    }
109
    echo '</table>';
110
    echo '<br />';
111
    echo '<button class="btn btn-success" type="submit" name="submit_plugins">'.get_lang('EnablePlugins').'</button></form>';
112
}
113
114
function handleExtensions()
115
{
116
    echo Display::page_subheader(get_lang('ConfigureExtensions'));
117
    echo '<a class="btn btn-success" href="configure_extensions.php?display=ppt2lp" role="button">'.get_lang('Ppt2lp').'</a>';
118
}
119
120
/**
121
 * Show form for plugin and validates inputs. Calls uploadPlugin() if everything OK.
122
 *
123
 * @throws Exception
124
 *
125
 * @return string|void The HTML form, or displays a message and returns nothing on error
126
 */
127
function handlePluginUpload()
128
{
129
    $allowPluginUpload = true == api_get_configuration_value('plugin_upload_enable');
130
    if (!$allowPluginUpload) {
131
        echo Display::return_message(
132
            get_lang('PluginUploadIsNotEnabled'),
133
            'error',
134
            false
135
        );
136
137
        return;
138
    }
139
    $pluginPath = api_get_path(SYS_PLUGIN_PATH);
140
    if (!is_writable($pluginPath)) {
141
        echo Display::return_message(
142
            $pluginPath.' '.get_lang('IsNotWritable'),
143
            'error',
144
            false
145
        );
146
147
        return;
148
    }
149
150
    echo Display::return_message(
151
        get_lang('PluginUploadPleaseRememberUploadingThirdPartyPluginsCanBeDangerous'),
152
        'warning',
153
        false
154
    );
155
    echo Display::return_message(
156
        get_lang('PluginUploadingTwiceWillReplacePreviousFiles'),
157
        'normal',
158
        false
159
    );
160
    $form = new FormValidator(
161
        'plugin_upload',
162
        'post',
163
        api_get_path(WEB_CODE_PATH).'admin/settings.php?category=Plugins#tabs-4'
164
    );
165
    $form->addElement(
166
        'file',
167
        'new_plugin',
168
        [get_lang('UploadNewPlugin'), '.zip']
169
    );
170
    // Only zip files are allowed
171
    $allowed_file_types[] = 'zip';
172
173
    $form->addRule(
174
        'new_plugin',
175
        get_lang('InvalidExtension').' ('.implode(',', $allowed_file_types).')',
176
        'filetype',
177
        $allowed_file_types
178
    );
179
    $form->addRule(
180
        'new_plugin',
181
        get_lang('ThisFieldIsRequired'),
182
        'required'
183
    );
184
    $form->addButtonUpload(get_lang('Upload'), 'plugin_upload');
185
    $form->protect();
186
187
    // Plugin upload.
188
    if ($form->validate()) {
189
        $fileElement = $form->getElement('new_plugin');
190
        $file = $fileElement->getValue();
191
        $result = uploadPlugin($file);
192
193
        // Add event to the system log.
194
        $user_id = api_get_user_id();
195
        $category = $_GET['category'];
196
        Event::addEvent(
197
            LOG_PLUGIN_CHANGE,
198
            LOG_PLUGIN_UPLOAD,
199
            $file['name'],
200
            api_get_utc_datetime(),
201
            $user_id
202
        );
203
204
        if ($result) {
205
            Display::addFlash(Display::return_message(get_lang('PluginUploaded'), 'success', false));
206
            header('Location: ?category=Plugins#');
207
            exit;
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_existing_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
    AppPlugin::cleanEntitiesInBundle();
242
243
    $all_plugins = $plugin_obj->read_plugins_from_path();
244
    $installed_plugins = $plugin_obj->getInstalledPlugins();
245
    $officialPlugins = $plugin_obj->getOfficialPlugins();
246
247
    // Plugins NOT installed
248
    echo Display::page_subheader(get_lang('Plugins'));
249
    echo '<form
250
        class="form-horizontal"
251
        name="plugins"
252
        method="post"
253
        action="'.api_get_self().'?category='.Security::remove_XSS($_GET['category']).'&sec_token='.$token.'"
254
    >';
255
    echo '<table class="table table-hover table-striped table-bordered">';
256
    echo '<tr>';
257
    echo '<th width="20px">';
258
    echo get_lang('Installed');
259
    echo '</th><th>';
260
    echo get_lang('Description');
261
    echo '</th>';
262
    echo '</tr>';
263
264
    $installed = '';
265
    $notInstalled = '';
266
    $isMainPortal = true;
267
    if (api_is_multiple_url_enabled()) {
268
        $isMainPortal = 1 === api_get_current_access_url_id();
269
    }
270
271
    $unknownLabel = get_lang('Unknown');
272
    foreach ($all_plugins as $pluginName) {
273
        if (in_array($pluginName, ['jcapture'])) {
274
            continue;
275
        }
276
277
        $plugin_info_file = api_get_path(SYS_PLUGIN_PATH).$pluginName.'/plugin.php';
278
        if (file_exists($plugin_info_file)) {
279
            $plugin_info = [
280
                'title' => $pluginName,
281
                'version' => '',
282
                'comment' => '',
283
                'author' => $unknownLabel,
284
            ];
285
            require $plugin_info_file;
286
287
            if (in_array($pluginName, $officialPlugins)) {
288
                $officialRibbon = '<div class="ribbon-diagonal ribbon-diagonal-top-right ribbon-diagonal-official">
289
                    <span>'.get_lang('PluginOfficial').'</span></div>';
290
            } else {
291
                $officialRibbon = '<div class="ribbon-diagonal ribbon-diagonal-top-right ribbon-diagonal-thirdparty">
292
                    <span>'.get_lang('PluginThirdParty').'</span></div>';
293
            }
294
            $pluginRow = '';
295
296
            $isInstalled = in_array($pluginName, $installed_plugins);
297
298
            if ($isInstalled) {
299
                $pluginRow .= '<tr class="row_selected">';
300
            } else {
301
                $pluginRow .= '<tr>';
302
            }
303
304
            $pluginRow .= '<td>';
305
306
            if ($isMainPortal) {
307
                if ($isInstalled) {
308
                    $pluginRow .= '<input type="checkbox" name="plugin_'.$pluginName.'[]" checked="checked">';
309
                } else {
310
                    $pluginRow .= '<input type="checkbox" name="plugin_'.$pluginName.'[]">';
311
                }
312
            } else {
313
                if ($isInstalled) {
314
                    $pluginRow .= Display::return_icon('check.png');
315
                } else {
316
                    $pluginRow .= Display::return_icon('checkbox_off.gif');
317
                }
318
            }
319
320
            $pluginRow .= '</td><td>';
321
            $pluginRow .= $officialRibbon;
322
            $pluginRow .= '<h4>'.$plugin_info['title'].' <small>v '.$plugin_info['version'].'</small></h4>';
323
            $pluginRow .= '<p>'.$plugin_info['comment'].'</p>';
324
            $pluginRow .= '<p>'.get_lang('Author').': '.$plugin_info['author'].'</p>';
325
326
            $pluginRow .= '<div class="btn-group">';
327
            if ($isInstalled) {
328
                $pluginRow .= Display::url(
329
                    '<em class="fa fa-cogs"></em> '.get_lang('Configure'),
330
                    'configure_plugin.php?name='.$pluginName,
331
                    ['class' => 'btn btn-default']
332
                );
333
                $pluginRow .= Display::url(
334
                    '<em class="fa fa-th-large"></em> '.get_lang('Regions'),
335
                    'settings.php?category=Regions&name='.$pluginName,
336
                    ['class' => 'btn btn-default']
337
                );
338
            }
339
340
            if (file_exists(api_get_path(SYS_PLUGIN_PATH).$pluginName.'/readme.txt')) {
341
                $pluginRow .= Display::url(
342
                    "<em class='fa fa-file-text-o'></em> readme.txt",
343
                    api_get_path(WEB_PLUGIN_PATH).$pluginName."/readme.txt",
344
                    [
345
                        'class' => 'btn btn-default ajax',
346
                        'data-title' => $plugin_info['title'],
347
                        'data-size' => 'lg',
348
                        '_target' => '_blank',
349
                    ]
350
                );
351
            }
352
353
            $readmeFile = api_get_path(SYS_PLUGIN_PATH).$pluginName.'/README.md';
354
            if (file_exists($readmeFile)) {
355
                $pluginRow .= Display::url(
356
                    "<em class='fa fa-file-text-o'></em> README.md",
357
                    api_get_path(WEB_AJAX_PATH).'plugin.ajax.php?a=md_to_html&plugin='.$pluginName,
358
                    [
359
                        'class' => 'btn btn-default ajax',
360
                        'data-title' => $plugin_info['title'],
361
                        'data-size' => 'lg',
362
                        '_target' => '_blank',
363
                    ]
364
                );
365
            }
366
367
            $pluginRow .= '</div>';
368
            $pluginRow .= '</td></tr>';
369
370
            if ($isInstalled) {
371
                $installed .= $pluginRow;
372
            } else {
373
                $notInstalled .= $pluginRow;
374
            }
375
        }
376
    }
377
378
    echo $installed;
379
    echo $notInstalled;
380
    echo '</table>';
381
382
    if ($isMainPortal) {
383
        echo '<div class="form-actions bottom_actions">';
384
        echo '<button class="btn btn-primary" type="submit" name="submit_plugins">';
385
        echo '<i class="fa fa-check" aria-hidden="true"></i> ';
386
        echo get_lang('EnablePlugins').'</button>';
387
        echo '</div>';
388
    }
389
390
    echo '</form>';
391
}
392
393
/**
394
 * This function allows the platform admin to choose the default stylesheet.
395
 *
396
 * @author Patrick Cool <[email protected]>, Ghent University
397
 * @author Julio Montoya <[email protected]>, Chamilo
398
 */
399
function handleStylesheets()
400
{
401
    $is_style_changeable = isStyleChangeable();
402
    $allowedFileTypes = ['png'];
403
404
    $form = new FormValidator(
405
        'stylesheet_upload',
406
        'post',
407
        api_get_path(WEB_CODE_PATH).'admin/settings.php?category=Stylesheets#tabs-3'
408
    );
409
    $form->protect();
410
    $form->addElement(
411
        'text',
412
        'name_stylesheet',
413
        get_lang('NameStylesheet'),
414
        ['size' => '40', 'maxlength' => '40']
415
    );
416
    $form->addRule(
417
        'name_stylesheet',
418
        get_lang('ThisFieldIsRequired'),
419
        'required'
420
    );
421
    $form->addElement(
422
        'file',
423
        'new_stylesheet',
424
        get_lang('UploadNewStylesheet')
425
    );
426
    $allowed_file_types = getAllowedFileTypes();
427
428
    $form->addRule(
429
        'new_stylesheet',
430
        get_lang('InvalidExtension').' ('.implode(',', $allowed_file_types).')',
431
        'filetype',
432
        $allowed_file_types
433
    );
434
    $form->addRule(
435
        'new_stylesheet',
436
        get_lang('ThisFieldIsRequired'),
437
        'required'
438
    );
439
    $form->addButtonUpload(get_lang('Upload'), 'stylesheet_upload');
440
441
    $show_upload_form = false;
442
    $urlId = api_get_current_access_url_id();
443
444
    if (!is_writable(CSS_UPLOAD_PATH)) {
445
        echo Display::return_message(
446
            CSS_UPLOAD_PATH.get_lang('IsNotWritable'),
447
            'error',
448
            false
449
        );
450
    } else {
451
        // Uploading a new stylesheet.
452
        if ($urlId == 1) {
453
            $show_upload_form = true;
454
        } else {
455
            if ($is_style_changeable) {
456
                $show_upload_form = true;
457
            }
458
        }
459
    }
460
461
    // Stylesheet upload.
462
    if (isset($_POST['stylesheet_upload'])) {
463
        if ($form->validate()) {
464
            $values = $form->exportValues();
465
            $picture_element = $form->getElement('new_stylesheet');
466
            $picture = $picture_element->getValue();
467
            $result = uploadStylesheet($values, $picture);
468
469
            // Add event to the system log.
470
            $user_id = api_get_user_id();
471
            $category = $_GET['category'];
472
            Event::addEvent(
473
                LOG_CONFIGURATION_SETTINGS_CHANGE,
474
                LOG_CONFIGURATION_SETTINGS_CATEGORY,
475
                $category,
476
                api_get_utc_datetime(),
477
                $user_id
478
            );
479
480
            if ($result) {
481
                echo Display::return_message(get_lang('StylesheetAdded'));
482
            }
483
        }
484
    }
485
486
    // Current style.
487
    $selected = $currentStyle = api_get_setting('stylesheets');
488
    $styleFromDatabase = api_get_settings_params_simple(
489
        ['variable = ? AND access_url = ?' => ['stylesheets', api_get_current_access_url_id()]]
490
    );
491
    if ($styleFromDatabase) {
492
        $selected = $currentStyle = $styleFromDatabase['selected_value'];
493
    }
494
495
    if (isset($_POST['preview'])) {
496
        $selected = $currentStyle = Security::remove_XSS($_POST['style']);
497
    }
498
499
    $themeDir = Template::getThemeDir($selected);
500
    $dir = api_get_path(SYS_PUBLIC_PATH).'css/'.$themeDir.'/images/';
501
    $url = api_get_path(WEB_CSS_PATH).'/'.$themeDir.'/images/';
502
    $logoFileName = 'header-logo.png';
503
    $newLogoFileName = 'header-logo-custom'.api_get_current_access_url_id().'.png';
504
    $webPlatformLogoPath = ChamiloApi::getPlatformLogoPath($selected);
505
506
    $logoForm = new FormValidator(
507
        'logo_upload',
508
        'post',
509
        'settings.php?category=Stylesheets#tabs-2'
510
    );
511
512
    $logoForm->addHtml(
513
        Display::return_message(
514
            sprintf(
515
                get_lang('TheLogoMustBeSizeXAndFormatY'),
516
                '250 x 70',
517
                'PNG'
518
            ),
519
            'info'
520
        )
521
    );
522
523
    if ($webPlatformLogoPath !== null) {
524
        $logoForm->addLabel(
525
            get_lang('CurrentLogo'),
526
            '<img id="header-logo-custom" src="'.$webPlatformLogoPath.'?'.time().'">'
527
        );
528
    }
529
    $logoForm->addFile('new_logo', get_lang('UpdateLogo'));
530
    if ($is_style_changeable) {
531
        $logoGroup = [
532
            $logoForm->addButtonUpload(get_lang('Upload'), 'logo_upload', true),
533
            $logoForm->addButtonCancel(get_lang('Reset'), 'logo_reset', true),
534
        ];
535
536
        $logoForm->addGroup($logoGroup);
537
    }
538
539
    if (isset($_POST['logo_reset'])) {
540
        if (is_file($dir.$newLogoFileName)) {
541
            unlink($dir.$newLogoFileName);
542
            echo Display::return_message(get_lang('ResetToTheOriginalLogo'));
543
            echo '<script>'
544
                .'$("#header-logo").attr("src","'.$url.$logoFileName.'");'
545
            .'</script>';
546
        }
547
    } elseif (isset($_POST['logo_upload'])) {
548
        $logoForm->addRule(
549
            'new_logo',
550
            get_lang('InvalidExtension').' ('.implode(',', $allowedFileTypes).')',
551
            'filetype',
552
            $allowedFileTypes
553
        );
554
        $logoForm->addRule(
555
            'new_logo',
556
            get_lang('ThisFieldIsRequired'),
557
            'required'
558
        );
559
560
        if ($logoForm->validate()) {
561
            $imageInfo = getimagesize($_FILES['new_logo']['tmp_name']);
562
            $width = $imageInfo[0];
563
            $height = $imageInfo[1];
564
            if ($width <= 250 && $height <= 70) {
565
                if (is_file($dir.$newLogoFileName)) {
566
                    unlink($dir.$newLogoFileName);
567
                }
568
569
                $status = move_uploaded_file(
570
                    $_FILES['new_logo']['tmp_name'],
571
                    $dir.$newLogoFileName
572
                );
573
574
                if ($status) {
575
                    echo Display::return_message(get_lang('NewLogoUpdated'));
576
                    echo '<script>'
577
                         .'$("#header-logo").attr("src","'.$url.$newLogoFileName.'");'
578
                         .'</script>';
579
                } else {
580
                    echo Display::return_message('Error - '.get_lang('UplNoFileUploaded'), 'error');
581
                }
582
            } else {
583
                echo Display::return_message('Error - '.get_lang('InvalidImageDimensions'), 'error');
584
            }
585
        }
586
    }
587
588
    if (isset($_POST['download'])) {
589
        generateCSSDownloadLink($selected);
590
    }
591
592
    $form_change = new FormValidator(
593
        'stylesheet_upload',
594
        'post',
595
        api_get_self().'?category=Stylesheets',
596
        null,
597
        ['id' => 'stylesheets_id']
598
    );
599
600
    $styles = $form_change->addElement(
601
        'selectTheme',
602
        'style',
603
        get_lang('NameStylesheet')
604
    );
605
    $styles->setSelected($currentStyle);
606
607
    if ($is_style_changeable) {
608
        $group = [
609
            $form_change->addButtonSave(get_lang('SaveSettings'), 'save', true),
610
            $form_change->addButtonPreview(get_lang('Preview'), 'preview', true),
611
            $form_change->addButtonDownload(get_lang('Download'), 'download', true),
612
        ];
613
614
        $form_change->addGroup($group);
615
616
        if ($show_upload_form) {
617
            echo Display::tabs(
618
                [get_lang('Update'), get_lang('UpdateLogo'), get_lang('UploadNewStylesheet')],
619
                [$form_change->returnForm(), $logoForm->returnForm(), $form->returnForm()]
620
            );
621
        } else {
622
            $form_change->display();
623
        }
624
625
        // Little hack to update the logo image in update form when submiting
626
        if (isset($_POST['logo_reset'])) {
627
            echo '<script>'
628
                    .'$("#header-logo-custom").attr("src","'.$url.$logoFileName.'");'
629
                .'</script>';
630
        } elseif (isset($_POST['logo_upload']) && is_file($dir.$newLogoFileName)) {
631
            echo '<script>'
632
                    .'$("#header-logo-custom").attr("src","'.$url.$newLogoFileName.'");'
633
                .'</script>';
634
        }
635
    } else {
636
        $form_change->freeze();
637
    }
638
}
639
640
/**
641
 * Creates the folder (if needed) and uploads the stylesheet in it.
642
 *
643
 * @param array $values  the values of the form
644
 * @param array $picture the values of the uploaded file
645
 *
646
 * @return bool
647
 *
648
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
649
 *
650
 * @version May 2008
651
 *
652
 * @since v1.8.5
653
 */
654
function uploadStylesheet($values, $picture)
655
{
656
    $result = false;
657
    // Valid name for the stylesheet folder.
658
    $style_name = api_preg_replace('/[^A-Za-z0-9]/', '', $values['name_stylesheet']);
659
    if (empty($style_name) || is_array($style_name)) {
660
        // The name of the uploaded stylesheet doesn't have the expected format
661
        return $result;
662
    }
663
    $cssToUpload = CSS_UPLOAD_PATH;
664
665
    // Check if a virtual instance vchamilo is used
666
    $virtualInstanceTheme = api_get_configuration_value('virtual_css_theme_folder');
667
    if (!empty($virtualInstanceTheme)) {
668
        $cssToUpload = $cssToUpload.$virtualInstanceTheme.'/';
669
    }
670
671
    // Create the folder if needed.
672
    if (!is_dir($cssToUpload.$style_name.'/')) {
673
        mkdir($cssToUpload.$style_name.'/', api_get_permissions_for_new_directories());
674
    }
675
676
    $info = pathinfo($picture['name']);
677
678
    if ($info['extension'] == 'zip') {
679
        // Try to open the file and extract it in the theme.
680
        $zip = new ZipArchive();
681
        if ($zip->open($picture['tmp_name'])) {
682
            // Make sure all files inside the zip are images or css.
683
            $num_files = $zip->numFiles;
684
            $valid = true;
685
            $single_directory = true;
686
            $invalid_files = [];
687
688
            $allowedFiles = getAllowedFileTypes();
689
690
            for ($i = 0; $i < $num_files; $i++) {
691
                $file = $zip->statIndex($i);
692
                if (substr($file['name'], -1) != '/') {
693
                    $path_parts = pathinfo($file['name']);
694
                    if (!in_array($path_parts['extension'], $allowedFiles)) {
695
                        $valid = false;
696
                        $invalid_files[] = $file['name'];
697
                    }
698
                }
699
700
                if (strpos($file['name'], '/') === false) {
701
                    $single_directory = false;
702
                }
703
            }
704
            if (!$valid) {
705
                $error_string = '<ul>';
706
                foreach ($invalid_files as $invalid_file) {
707
                    $error_string .= '<li>'.$invalid_file.'</li>';
708
                }
709
                $error_string .= '</ul>';
710
                echo Display::return_message(
711
                    get_lang('ErrorStylesheetFilesExtensionsInsideZip').$error_string,
712
                    'error',
713
                    false
714
                );
715
            } else {
716
                // If the zip does not contain a single directory, extract it.
717
                if (!$single_directory) {
718
                    // Extract zip file.
719
                    $zip->extractTo($cssToUpload.$style_name.'/');
720
                    $result = true;
721
                } else {
722
                    $extraction_path = $cssToUpload.$style_name.'/';
723
                    $mode = api_get_permissions_for_new_directories();
724
                    for ($i = 0; $i < $num_files; $i++) {
725
                        $entry = $zip->getNameIndex($i);
726
                        if (substr($entry, -1) == '/') {
727
                            continue;
728
                        }
729
730
                        $pos_slash = strpos($entry, '/');
731
                        $entry_without_first_dir = substr($entry, $pos_slash + 1);
732
                        // If there is still a slash, we need to make sure the directories are created.
733
                        if (strpos($entry_without_first_dir, '/') !== false) {
734
                            if (!is_dir($extraction_path.dirname($entry_without_first_dir))) {
735
                                // Create it.
736
                                @mkdir($extraction_path.dirname($entry_without_first_dir), $mode, true);
737
                            }
738
                        }
739
740
                        $fp = $zip->getStream($entry);
741
                        $ofp = fopen($extraction_path.dirname($entry_without_first_dir).'/'.basename($entry), 'w');
742
743
                        while (!feof($fp)) {
744
                            fwrite($ofp, fread($fp, 8192));
745
                        }
746
747
                        fclose($fp);
748
                        fclose($ofp);
749
                    }
750
                    $result = true;
751
                }
752
            }
753
            $zip->close();
754
        } else {
755
            echo Display::return_message(get_lang('ErrorReadingZip').$info['extension'], 'error', false);
756
        }
757
    } else {
758
        // Simply move the file.
759
        move_uploaded_file($picture['tmp_name'], $cssToUpload.$style_name.'/'.$picture['name']);
760
        $result = true;
761
    }
762
763
    if ($result) {
764
        $fs = new Filesystem();
765
        $fs->mirror(
766
            CSS_UPLOAD_PATH,
767
            api_get_path(SYS_PATH).'web/css/themes/',
768
            null,
769
            ['override' => true]
770
        );
771
    }
772
773
    return $result;
774
}
775
776
/**
777
 * Creates the folder (if needed) and uploads the plugin in it. If the plugin
778
 * is already there and the folder is writeable, overwrite.
779
 *
780
 * @param array $file the file passed to the upload form
781
 *
782
 * @return bool
783
 */
784
function uploadPlugin($file)
785
{
786
    $result = false;
787
    $pluginPath = api_get_path(SYS_PLUGIN_PATH);
788
    $info = pathinfo($file['name']);
789
    if ($info['extension'] == 'zip') {
790
        // Try to open the file and extract it in the theme.
791
        $zip = new ZipArchive();
792
        if ($zip->open($file['tmp_name'])) {
793
            // Make sure all files inside the zip are images or css.
794
            $num_files = $zip->numFiles;
795
            $valid = true;
796
            $single_directory = true;
797
            $invalid_files = [];
798
799
            $allowedFiles = getAllowedFileTypes();
800
            $allowedFiles[] = 'php';
801
            $allowedFiles[] = 'js';
802
            $allowedFiles[] = 'tpl';
803
            $pluginObject = new AppPlugin();
804
            $officialPlugins = $pluginObject->getOfficialPlugins();
805
806
            for ($i = 0; $i < $num_files; $i++) {
807
                $file = $zip->statIndex($i);
808
                if (substr($file['name'], -1) != '/') {
809
                    $path_parts = pathinfo($file['name']);
810
                    if (!in_array($path_parts['extension'], $allowedFiles)) {
811
                        $valid = false;
812
                        $invalid_files[] = $file['name'];
813
                    }
814
                }
815
816
                if (strpos($file['name'], '/') === false) {
817
                    $single_directory = false;
818
                }
819
            }
820
            if (!$valid) {
821
                $error_string = '<ul>';
822
                foreach ($invalid_files as $invalid_file) {
823
                    $error_string .= '<li>'.$invalid_file.'</li>';
824
                }
825
                $error_string .= '</ul>';
826
                echo Display::return_message(
827
                    get_lang('ErrorPluginFilesExtensionsInsideZip').$error_string,
828
                    'error',
829
                    false
830
                );
831
            } else {
832
                // Prevent overwriting an official plugin
833
834
                if (in_array($info['filename'], $officialPlugins)) {
835
                    echo Display::return_message(
836
                        get_lang('ErrorPluginOfficialCannotBeUploaded'),
837
                        'error',
838
                        false
839
                    );
840
                } else {
841
                    // If the zip does not contain a single directory, extract it.
842
                    if (!$single_directory) {
843
                        // Extract zip file.
844
                        $zip->extractTo($pluginPath.$info['filename'].'/');
845
                        $result = true;
846
                    } else {
847
                        $extraction_path = $pluginPath.$info['filename'].'/';
848
                        $mode = api_get_permissions_for_new_directories();
849
                        if (!is_dir($extraction_path)) {
850
                            @mkdir($extraction_path, $mode, true);
851
                        }
852
853
                        for ($i = 0; $i < $num_files; $i++) {
854
                            $entry = $zip->getNameIndex($i);
855
                            if (substr($entry, -1) == '/') {
856
                                continue;
857
                            }
858
859
                            $pos_slash = strpos($entry, '/');
860
                            $entry_without_first_dir = substr($entry, $pos_slash + 1);
861
                            $shortPluginDir = dirname($entry_without_first_dir);
862
                            // If there is still a slash, we need to make sure the directories are created.
863
                            if (strpos($entry_without_first_dir, '/') !== false) {
864
                                if (!is_dir($extraction_path.$shortPluginDir)) {
865
                                    // Create it.
866
                                    @mkdir($extraction_path.$shortPluginDir, $mode, true);
867
                                }
868
                            }
869
870
                            $fp = $zip->getStream($entry);
871
                            $shortPluginDir = dirname($entry_without_first_dir).'/';
872
                            if ($shortPluginDir === './') {
873
                                $shortPluginDir = '';
874
                            }
875
                            $ofp = fopen($extraction_path.$shortPluginDir.basename($entry), 'w');
876
877
                            while (!feof($fp)) {
878
                                fwrite($ofp, fread($fp, 8192));
879
                            }
880
881
                            fclose($fp);
882
                            fclose($ofp);
883
                        }
884
                        $result = true;
885
                    }
886
                }
887
            }
888
            $zip->close();
889
        } else {
890
            echo Display::return_message(get_lang('ErrorReadingZip').$info['extension'], 'error', false);
891
        }
892
    } else {
893
        // Simply move the file.
894
        move_uploaded_file($file['tmp_name'], $pluginPath.'/'.$file['name']);
895
        $result = true;
896
    }
897
898
    return $result;
899
}
900
901
/**
902
 * Store plugin regions.
903
 */
904
function storeRegions()
905
{
906
    $plugin_obj = new AppPlugin();
907
908
    // Get a list of all current 'Plugins' settings
909
    $installed_plugins = $plugin_obj->getInstalledPlugins();
910
    $shortlist_installed = [];
911
    if (!empty($installed_plugins)) {
912
        foreach ($installed_plugins as $plugin) {
913
            if (isset($plugin['subkey'])) {
914
                $shortlist_installed[] = $plugin['subkey'];
915
            }
916
        }
917
    }
918
919
    $plugin_list = $plugin_obj->read_plugins_from_path();
920
921
    foreach ($plugin_list as $plugin) {
922
        if (isset($_POST['plugin_'.$plugin])) {
923
            $areas_to_installed = $_POST['plugin_'.$plugin];
924
            if (!empty($areas_to_installed)) {
925
                $plugin_obj->remove_all_regions($plugin);
926
                foreach ($areas_to_installed as $region) {
927
                    if (!empty($region) && $region != '-1') {
928
                        $plugin_obj->add_to_region($plugin, $region);
929
                    }
930
                }
931
            }
932
        }
933
    }
934
}
935
936
/**
937
 * This function allows easy activating and inactivating of plugins.
938
 *
939
 * @author Patrick Cool <[email protected]>, Ghent University
940
 */
941
function storePlugins()
942
{
943
    $appPlugin = new AppPlugin();
944
    // Get a list of all current 'Plugins' settings
945
    $plugin_list = $appPlugin->read_plugins_from_path();
946
    $installed_plugins = [];
947
948
    foreach ($plugin_list as $plugin) {
949
        if (isset($_POST['plugin_'.$plugin])) {
950
            $appPlugin->install($plugin);
951
            $installed_plugins[] = $plugin;
952
        }
953
    }
954
955
    if (!empty($installed_plugins)) {
956
        $remove_plugins = array_diff($plugin_list, $installed_plugins);
957
    } else {
958
        $remove_plugins = $plugin_list;
959
    }
960
961
    foreach ($remove_plugins as $plugin) {
962
        $appPlugin->uninstall($plugin);
963
    }
964
}
965
966
/**
967
 * This function allows the platform admin to choose which should be the default stylesheet.
968
 *
969
 * @author Patrick Cool <[email protected]>, Ghent University
970
 */
971
function storeStylesheets()
972
{
973
    // Insert the stylesheet.
974
    if (isStyle($_POST['style'])) {
975
        api_set_setting(
976
            'stylesheets',
977
            $_POST['style'],
978
            null,
979
            'stylesheets',
980
            api_get_current_access_url_id()
981
        );
982
    }
983
984
    return true;
985
}
986
987
/**
988
 * This function checks if the given style is a recognize style that exists in the css directory as
989
 * a standalone directory.
990
 *
991
 * @param string $style
992
 *
993
 * @return bool True if this style is recognized, false otherwise
994
 */
995
function isStyle($style)
996
{
997
    $themeList = api_get_themes();
998
999
    return in_array($style, array_keys($themeList));
1000
}
1001
1002
/**
1003
 * Search options
1004
 * TODO: support for multiple site. aka $_configuration['access_url'] == 1.
1005
 *
1006
 * @author Marco Villegas <[email protected]>
1007
 */
1008
function handleSearch()
1009
{
1010
    global $SettingsStored, $_configuration;
1011
1012
    require_once api_get_path(LIBRARY_PATH).'specific_fields_manager.lib.php';
1013
    $search_enabled = api_get_setting('search_enabled');
1014
1015
    $form = new FormValidator(
1016
        'search-options',
1017
        'post',
1018
        api_get_self().'?category=Search'
1019
    );
1020
    $values = api_get_settings_options('search_enabled');
1021
    $form->addElement('header', null, get_lang('SearchEnabledTitle'));
1022
1023
    $group = formGenerateElementsGroup($form, $values, 'search_enabled');
1024
1025
    // SearchEnabledComment
1026
    $form->addGroup(
1027
        $group,
1028
        'search_enabled',
1029
        [get_lang('SearchEnabledTitle'), get_lang('SearchEnabledComment')],
1030
        null,
1031
        false
1032
    );
1033
1034
    $search_enabled = api_get_setting('search_enabled');
1035
1036
    if ($form->validate()) {
1037
        $formValues = $form->exportValues();
1038
        setConfigurationSettingsInDatabase($formValues, $_configuration['access_url']);
1039
        $search_enabled = $formValues['search_enabled'];
1040
        echo Display::return_message($SettingsStored, 'confirm');
1041
    }
1042
    $specific_fields = get_specific_field_list();
1043
1044
    if ($search_enabled == 'true') {
1045
        $values = api_get_settings_options('search_show_unlinked_results');
1046
        $group = formGenerateElementsGroup(
1047
            $form,
1048
            $values,
1049
            'search_show_unlinked_results'
1050
        );
1051
        $form->addGroup(
1052
            $group,
1053
            'search_show_unlinked_results',
1054
            [
1055
                get_lang('SearchShowUnlinkedResultsTitle'),
1056
                get_lang('SearchShowUnlinkedResultsComment'),
1057
            ],
1058
            null,
1059
            false
1060
        );
1061
        $default_values['search_show_unlinked_results'] = api_get_setting('search_show_unlinked_results');
1062
1063
        $sf_values = [];
1064
        foreach ($specific_fields as $sf) {
1065
            $sf_values[$sf['code']] = $sf['name'];
1066
        }
1067
        $url = Display::div(
1068
            Display::url(
1069
                get_lang('AddSpecificSearchField'),
1070
                'specific_fields.php'
1071
            ),
1072
            ['class' => 'sectioncomment']
1073
        );
1074
        if (empty($sf_values)) {
1075
            $form->addElement('label', [get_lang('SearchPrefilterPrefix'), $url]);
1076
        } else {
1077
            $form->addElement(
1078
                'select',
1079
                'search_prefilter_prefix',
1080
                [get_lang('SearchPrefilterPrefix'), $url],
1081
                $sf_values,
1082
                ''
1083
            );
1084
            $default_values['search_prefilter_prefix'] = api_get_setting('search_prefilter_prefix');
1085
        }
1086
    }
1087
1088
    $default_values['search_enabled'] = $search_enabled;
1089
1090
    $form->addButtonSave(get_lang('Save'));
1091
    $form->setDefaults($default_values);
1092
1093
    echo '<div id="search-options-form">';
1094
    $form->display();
1095
    echo '</div>';
1096
1097
    if ($search_enabled == 'true') {
1098
        $xapianPath = api_get_path(SYS_UPLOAD_PATH).'plugins/xapian/searchdb';
1099
1100
        /*
1101
        @todo Test the Xapian connection
1102
        if (extension_loaded('xapian')) {
1103
            require_once 'xapian.php';
1104
            try {
1105
                $db = new XapianDatabase($xapianPath.'/');
1106
            } catch (Exception $e) {
1107
                var_dump($e->getMessage());
1108
            }
1109
1110
            require_once api_get_path(LIBRARY_PATH) . 'search/ChamiloIndexer.class.php';
1111
            require_once api_get_path(LIBRARY_PATH) . 'search/IndexableChunk.class.php';
1112
            require_once api_get_path(LIBRARY_PATH) . 'specific_fields_manager.lib.php';
1113
1114
            $indexable = new IndexableChunk();
1115
            $indexable->addValue("content", 'Test');
1116
1117
            $di = new ChamiloIndexer();
1118
            $di->connectDb(NULL, NULL, 'english');
1119
            $di->addChunk($indexable);
1120
            $did = $di->index();
1121
        }
1122
        */
1123
1124
        $xapianLoaded = Display::return_icon('bullet_green.png', get_lang('Ok'));
1125
        $dir_exists = Display::return_icon('bullet_green.png', get_lang('Ok'));
1126
        $dir_is_writable = Display::return_icon('bullet_green.png', get_lang('Ok'));
1127
        $specific_fields_exists = Display::return_icon('bullet_green.png', get_lang('Ok'));
1128
1129
        //Testing specific fields
1130
        if (empty($specific_fields)) {
1131
            $specific_fields_exists = Display::return_icon(
1132
                'bullet_red.png',
1133
                get_lang('AddSpecificSearchField')
1134
            );
1135
        }
1136
        //Testing xapian extension
1137
        if (!extension_loaded('xapian')) {
1138
            $xapianLoaded = Display::return_icon('bullet_red.png', get_lang('Error'));
1139
        }
1140
        //Testing xapian searchdb path
1141
        if (!is_dir($xapianPath)) {
1142
            $dir_exists = Display::return_icon('bullet_red.png', get_lang('Error'));
1143
        }
1144
        //Testing xapian searchdb path is writable
1145
        if (!is_writable($xapianPath)) {
1146
            $dir_is_writable = Display::return_icon('bullet_red.png', get_lang('Error'));
1147
        }
1148
1149
        $data = [];
1150
        $data[] = [get_lang('XapianModuleInstalled'), $xapianLoaded];
1151
        $data[] = [get_lang('DirectoryExists').' - '.$xapianPath, $dir_exists];
1152
        $data[] = [get_lang('IsWritable').' - '.$xapianPath, $dir_is_writable];
1153
        $data[] = [get_lang('SpecificSearchFieldsAvailable'), $specific_fields_exists];
1154
1155
        showSearchSettingsTable($data);
1156
        showSearchToolsStatusTable();
1157
    }
1158
}
1159
1160
/**
1161
 * Wrapper for the templates.
1162
 *
1163
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
1164
 * @author Julio Montoya.
1165
 *
1166
 * @version August 2008
1167
 *
1168
 * @since v1.8.6
1169
 */
1170
function handleTemplates()
1171
{
1172
    /* Drive-by fix to avoid undefined var warnings, without repeating
1173
     * isset() combos all over the place. */
1174
    $action = isset($_GET['action']) ? $_GET['action'] : "invalid";
1175
1176
    if ($action != 'add') {
1177
        echo '<div class="actions" style="margin-left: 1px;">';
1178
        echo '<a href="settings.php?category=Templates&action=add">'.
1179
                Display::return_icon('new_template.png', get_lang('AddTemplate'), '', ICON_SIZE_MEDIUM).'</a>';
1180
        echo '</div>';
1181
    }
1182
1183
    if ($action == 'add' || ($action == 'edit' && is_numeric($_GET['id']))) {
1184
        addEditTemplate();
1185
1186
        // Add event to the system log.
1187
        $user_id = api_get_user_id();
1188
        $category = $_GET['category'];
1189
        Event::addEvent(
1190
            LOG_CONFIGURATION_SETTINGS_CHANGE,
1191
            LOG_CONFIGURATION_SETTINGS_CATEGORY,
1192
            $category,
1193
            api_get_utc_datetime(),
1194
            $user_id
1195
        );
1196
    } else {
1197
        if ($action == 'delete' && is_numeric($_GET['id'])) {
1198
            deleteTemplate($_GET['id']);
1199
1200
            // Add event to the system log
1201
            $user_id = api_get_user_id();
1202
            $category = $_GET['category'];
1203
            Event::addEvent(
1204
                LOG_CONFIGURATION_SETTINGS_CHANGE,
1205
                LOG_CONFIGURATION_SETTINGS_CATEGORY,
1206
                $category,
1207
                api_get_utc_datetime(),
1208
                $user_id
1209
            );
1210
        }
1211
        displayTemplates();
1212
    }
1213
}
1214
1215
/**
1216
 * Display a sortable table with all the templates that the platform administrator has defined.
1217
 *
1218
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
1219
 *
1220
 * @version August 2008
1221
 *
1222
 * @since v1.8.6
1223
 */
1224
function displayTemplates()
1225
{
1226
    $table = new SortableTable(
1227
        'templates',
1228
        'getNumberOfTemplates',
1229
        'getTemplateData',
1230
        1
1231
    );
1232
    $table->set_additional_parameters(
1233
        ['category' => Security::remove_XSS($_GET['category'])]
1234
    );
1235
    $table->set_header(0, get_lang('Image'), true, ['style' => 'width: 101px;']);
1236
    $table->set_header(1, get_lang('Title'));
1237
    if (true === api_get_configuration_value('template_activate_language_filter')) {
1238
        $table->set_header(2, get_lang('Language'));
1239
        $table->set_header(3, get_lang('Actions'), false, ['style' => 'width:50px;']);
1240
        $table->set_column_filter(3, 'actionsFilter');
1241
    } else {
1242
        $table->set_header(2, get_lang('Actions'), false, ['style' => 'width:50px;']);
1243
        $table->set_column_filter(2, 'actionsFilter');
1244
    }
1245
    $table->set_column_filter(0, 'searchImageFilter');
1246
    $table->display();
1247
}
1248
1249
/**
1250
 * Gets the number of templates that are defined by the platform admin.
1251
 *
1252
 * @return int
1253
 *
1254
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
1255
 *
1256
 * @version August 2008
1257
 *
1258
 * @since v1.8.6
1259
 */
1260
function getNumberOfTemplates()
1261
{
1262
    // Database table definition.
1263
    $table = Database::get_main_table('system_template');
1264
1265
    // The sql statement.
1266
    $sql = "SELECT COUNT(id) AS total FROM $table";
1267
    $result = Database::query($sql);
1268
    $row = Database::fetch_array($result);
1269
1270
    // Returning the number of templates.
1271
    return $row['total'];
1272
}
1273
1274
/**
1275
 * Gets all the template data for the sortable table.
1276
 *
1277
 * @param int    $from            the start of the limit statement
1278
 * @param int    $number_of_items the number of elements that have to be retrieved from the database
1279
 * @param int    $column          the column that is
1280
 * @param string $direction       the sorting direction (ASC or DESC)
1281
 *
1282
 * @return array
1283
 *
1284
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
1285
 *
1286
 * @version August 2008
1287
 *
1288
 * @since v1.8.6
1289
 */
1290
function getTemplateData($from, $number_of_items, $column, $direction)
1291
{
1292
    // Database table definition.
1293
    $table_system_template = Database::get_main_table('system_template');
1294
1295
    $from = (int) $from;
1296
    $number_of_items = (int) $number_of_items;
1297
    $column = (int) $column;
1298
    $direction = !in_array(strtolower(trim($direction)), ['asc', 'desc']) ? 'asc' : $direction;
1299
1300
    // The sql statement.
1301
    if (true === api_get_configuration_value('template_activate_language_filter')) {
1302
        $sql = "SELECT image as col0, title as col1, language as col2, id as col3 FROM $table_system_template";
1303
    } else {
1304
        $sql = "SELECT image as col0, title as col1, id as col2 FROM $table_system_template";
1305
    }
1306
    $sql .= " ORDER BY col$column $direction ";
1307
    $sql .= " LIMIT $from,$number_of_items";
1308
    $result = Database::query($sql);
1309
    $return = [];
1310
    while ($row = Database::fetch_array($result)) {
1311
        $row['1'] = get_lang($row['1']);
1312
        $return[] = $row;
1313
    }
1314
    // Returning all the information for the sortable table.
1315
    return $return;
1316
}
1317
1318
/**
1319
 * display the edit and delete icons in the sortable table.
1320
 *
1321
 * @param int $id the id of the template
1322
 *
1323
 * @return string code for the link to edit and delete the template
1324
 *
1325
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
1326
 *
1327
 * @version August 2008
1328
 *
1329
 * @since v1.8.6
1330
 */
1331
function actionsFilter($id)
1332
{
1333
    $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>';
1334
    $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>';
1335
1336
    return $return;
1337
}
1338
1339
/**
1340
 * Display the image of the template in the sortable table.
1341
 *
1342
 * @param string $image the image
1343
 *
1344
 * @return string code for the image
1345
 *
1346
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
1347
 *
1348
 * @version August 2008
1349
 *
1350
 * @since v1.8.6
1351
 */
1352
function searchImageFilter($image)
1353
{
1354
    if (!empty($image)) {
1355
        return '<img src="'.api_get_path(WEB_HOME_PATH).'default_platform_document/template_thumb/'.$image.'" alt="'.get_lang('TemplatePreview').'"/>';
1356
    } else {
1357
        return '<img src="'.api_get_path(WEB_HOME_PATH).'default_platform_document/template_thumb/noimage.gif" alt="'.get_lang('NoTemplatePreview').'"/>';
1358
    }
1359
}
1360
1361
/**
1362
 * Add (or edit) a template. This function displays the form and also takes
1363
 * care of uploading the image and storing the information in the database.
1364
 *
1365
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
1366
 *
1367
 * @version August 2008
1368
 *
1369
 * @since v1.8.6
1370
 */
1371
function addEditTemplate()
1372
{
1373
    $language_interface = api_get_interface_language();
1374
1375
    $em = Database::getManager();
1376
    // Initialize the object.
1377
    $id = isset($_GET['id']) ? (int) $_GET['id'] : 0;
1378
1379
    /** @var SystemTemplate $template */
1380
    $template = $id ? $em->find('ChamiloCoreBundle:SystemTemplate', $id) : new SystemTemplate();
1381
1382
    $form = new FormValidator(
1383
        'template',
1384
        'post',
1385
        'settings.php?category=Templates&action='.Security::remove_XSS($_GET['action']).'&id='.$id
1386
    );
1387
1388
    // Setting the form elements: the header.
1389
    if ($_GET['action'] == 'add') {
1390
        $title = get_lang('AddTemplate');
1391
    } else {
1392
        $title = get_lang('EditTemplate');
1393
    }
1394
    $form->addElement('header', '', $title);
1395
1396
    // Setting the form elements: the title of the template.
1397
    $form->addText('title', get_lang('Title'), false);
1398
    $form->addText('comment', get_lang('Description'), false);
1399
1400
    // Setting the form elements: the content of the template (wysiwyg editor).
1401
    $form->addHtmlEditor(
1402
        'template_text',
1403
        get_lang('Text'),
1404
        true,
1405
        true,
1406
        ['ToolbarSet' => 'Documents', 'Width' => '100%', 'Height' => '400']
1407
    );
1408
    if (true === api_get_configuration_value('template_activate_language_filter')) {
1409
        $form->addSelectLanguage('language', get_lang('Language'), null);
1410
    } else {
1411
        $form->addHidden('language', $language_interface);
1412
    }
1413
1414
    // Setting the form elements: the form to upload an image to be used with the template.
1415
    if (empty($template->getImage())) {
1416
        $form->addElement('file', 'template_image', get_lang('Image'), '');
1417
    }
1418
1419
    // Setting the form elements: a little bit information about the template image.
1420
    $form->addElement('static', 'file_comment', '', get_lang('TemplateImageComment100x70'));
1421
1422
    // Getting all the information of the template when editing a template.
1423
    if ($_GET['action'] === 'edit') {
1424
        $defaults['template_id'] = $id;
1425
        $defaults['template_text'] = $template->getContent();
1426
        // Forcing get_lang().
1427
        $defaults['title'] = $template->getTitle();
1428
        $defaults['comment'] = $template->getComment();
1429
        $defaults['language'] = $template->getLanguage();
1430
1431
        // Adding an extra field: a hidden field with the id of the template we are editing.
1432
        $form->addElement('hidden', 'template_id');
1433
1434
        // Adding an extra field: a preview of the image that is currently used.
1435
        if (!empty($template->getImage())) {
1436
            $form->addElement(
1437
                'static',
1438
                'template_image_preview',
1439
                '',
1440
                '<img src="'.api_get_path(WEB_HOME_PATH).
1441
                'default_platform_document/template_thumb/'.$template->getImage()
1442
                    .'" alt="'.get_lang('TemplatePreview')
1443
                    .'"/>'
1444
            );
1445
            $form->addCheckBox('delete_image', null, get_lang('DeletePicture'));
1446
        } else {
1447
            $form->addElement(
1448
                'static',
1449
                'template_image_preview',
1450
                '',
1451
                '<img src="'.api_get_path(WEB_HOME_PATH).'default_platform_document/template_thumb/noimage.gif" alt="'.get_lang('NoTemplatePreview').'"/>'
1452
            );
1453
        }
1454
1455
        // Setting the information of the template that we are editing.
1456
        $form->setDefaults($defaults);
1457
    }
1458
    // Setting the form elements: the submit button.
1459
    $form->addButtonSave(get_lang('Ok'), 'submit');
1460
1461
    // Setting the rules: the required fields.
1462
    if (empty($template->getImage())) {
1463
        $form->addRule(
1464
            'template_image',
1465
            get_lang('ThisFieldIsRequired'),
1466
            'required'
1467
        );
1468
        $form->addRule('title', get_lang('ThisFieldIsRequired'), 'required');
1469
    }
1470
1471
    // if the form validates (complies to all rules) we save the information,
1472
    // else we display the form again (with error message if needed)
1473
    if ($form->validate()) {
1474
        $check = Security::check_token('post', null, 'frm');
1475
        if ($check) {
1476
            // Exporting the values.
1477
            $values = $form->exportValues();
1478
            $isDelete = null;
1479
            if (isset($values['delete_image'])) {
1480
                $isDelete = $values['delete_image'];
1481
            }
1482
1483
            // Upload the file.
1484
            if (!empty($_FILES['template_image']['name'])) {
1485
                $upload_ok = process_uploaded_file($_FILES['template_image']);
1486
1487
                if ($upload_ok) {
1488
                    // Try to add an extension to the file if it hasn't one.
1489
                    $new_file_name = add_ext_on_mime(
1490
                        stripslashes($_FILES['template_image']['name']),
1491
                        $_FILES['template_image']['type']
1492
                    );
1493
1494
                    // The upload directory.
1495
                    $upload_dir = api_get_path(SYS_HOME_PATH).'default_platform_document/template_thumb/';
1496
1497
                    // Create the directory if it does not exist.
1498
                    if (!is_dir($upload_dir)) {
1499
                        mkdir($upload_dir, api_get_permissions_for_new_directories());
1500
                    }
1501
1502
                    // Resize the preview image to max default and upload.
1503
                    $temp = new Image($_FILES['template_image']['tmp_name']);
1504
                    $picture_info = $temp->get_image_info();
1505
1506
                    $max_width_for_picture = 100;
1507
                    if ($picture_info['width'] > $max_width_for_picture) {
1508
                        $temp->resize($max_width_for_picture);
1509
                    }
1510
                    $temp->send_image($upload_dir.$new_file_name);
1511
                }
1512
            }
1513
1514
            // Store the information in the database (as insert or as update).
1515
            //$bootstrap = api_get_css(api_get_path(WEB_PUBLIC_PATH).'assets/bootstrap/dist/css/bootstrap.min.css');
1516
            $viewport = '<meta name="viewport" content="width=device-width, initial-scale=1.0">';
1517
1518
            if ($_GET['action'] == 'add') {
1519
                $templateContent = '<head>'.$viewport.'<title>'.$values['title'].'</title></head>'
1520
                    .$values['template_text'];
1521
                $template
1522
                    ->setTitle($values['title'])
1523
                    ->setComment(Security::remove_XSS($values['comment']))
1524
                    ->setContent(Security::remove_XSS($templateContent, COURSEMANAGERLOWSECURITY))
1525
                    ->setLanguage($values['language'])
1526
                    ->setImage($new_file_name);
1527
                $em->persist($template);
1528
                $em->flush();
1529
1530
                // Display a feedback message.
1531
                echo Display::return_message(
1532
                    get_lang('TemplateAdded'),
1533
                    'confirm'
1534
                );
1535
                echo '<a href="settings.php?category=Templates&action=add">'.
1536
                    Display::return_icon('new_template.png', get_lang('AddTemplate'), '', ICON_SIZE_MEDIUM).
1537
                    '</a>';
1538
            } else {
1539
                $templateContent = $values['template_text'];
1540
                $template
1541
                    ->setTitle($values['title'])
1542
                    ->setComment(Security::remove_XSS($values['comment']))
1543
                    ->setLanguage($values['language'])
1544
                    ->setContent(Security::remove_XSS($templateContent, COURSEMANAGERLOWSECURITY));
1545
1546
                if ($isDelete) {
1547
                    $filePath = api_get_path(SYS_HOME_PATH).'default_platform_document/template_thumb/'.$template->getImage();
1548
                    if (file_exists($filePath)) {
1549
                        unlink($filePath);
1550
                    }
1551
                    $template->setImage(null);
1552
                }
1553
1554
                if (!empty($new_file_name)) {
1555
                    $template->setImage($new_file_name);
1556
                }
1557
1558
                $em->persist($template);
1559
                $em->flush();
1560
1561
                // Display a feedback message.
1562
                echo Display::return_message(get_lang('TemplateEdited'), 'confirm');
1563
            }
1564
        }
1565
        api_flush_settings_cache(api_get_current_access_url_id());
1566
        Security::clear_token('frm');
1567
        header('Location: '.api_get_path(WEB_CODE_PATH).'admin/settings.php?category=Templates');
1568
        exit;
1569
    } else {
1570
        $token = Security::get_token('frm');
1571
        $form->addElement('hidden', 'frm_sec_token');
1572
        $form->setConstants(['frm_sec_token' => $token]);
1573
        // Display the form.
1574
        $form->display();
1575
    }
1576
}
1577
1578
/**
1579
 * Delete a template.
1580
 *
1581
 * @param int $id the id of the template that has to be deleted
1582
 *
1583
 * @author Patrick Cool <[email protected]>, Ghent University, Belgium
1584
 *
1585
 * @version August 2008
1586
 *
1587
 * @since v1.8.6
1588
 */
1589
function deleteTemplate($id)
1590
{
1591
    $id = intval($id);
1592
    // First we remove the image.
1593
    $table = Database::get_main_table('system_template');
1594
    $sql = "SELECT * FROM $table WHERE id = $id";
1595
    $result = Database::query($sql);
1596
    $row = Database::fetch_array($result);
1597
    if (!empty($row['image'])) {
1598
        @unlink(api_get_path(SYS_HOME_PATH).'default_platform_document/template_thumb/'.$row['image']);
1599
    }
1600
1601
    // Now we remove it from the database.
1602
    $sql = "DELETE FROM $table WHERE id = $id";
1603
    Database::query($sql);
1604
1605
    // Display a feedback message.
1606
    echo Display::return_message(get_lang('TemplateDeleted'), 'confirm');
1607
}
1608
1609
/**
1610
 * Returns the list of timezone identifiers used to populate the select
1611
 * This function is called through a call_user_func() in the generate_settings_form function.
1612
 *
1613
 * @return array List of timezone identifiers
1614
 *
1615
 * @author Guillaume Viguier <[email protected]>
1616
 *
1617
 * @since Chamilo 1.8.7
1618
 */
1619
function select_timezone_value()
1620
{
1621
    return api_get_timezones();
1622
}
1623
1624
/**
1625
 * Returns an array containing the list of options used to populate the gradebook_number_decimals variable
1626
 * This function is called through a call_user_func() in the generate_settings_form function.
1627
 *
1628
 * @return array List of gradebook_number_decimals options
1629
 *
1630
 * @author Guillaume Viguier <[email protected]>
1631
 */
1632
function select_gradebook_number_decimals()
1633
{
1634
    return ['0', '1', '2'];
1635
}
1636
1637
/**
1638
 * Get the options for a select element to select gradebook default grade model.
1639
 *
1640
 * @return array
1641
 */
1642
function select_gradebook_default_grade_model_id()
1643
{
1644
    $grade_model = new GradeModel();
1645
    $models = $grade_model->get_all();
1646
    $options = [];
1647
    $options[-1] = get_lang('None');
1648
1649
    if (!empty($models)) {
1650
        foreach ($models as $model) {
1651
            $options[$model['id']] = $model['name'];
1652
        }
1653
    }
1654
1655
    return $options;
1656
}
1657
1658
/**
1659
 * @param array $settings
1660
 * @param array $settings_by_access_list
1661
 *
1662
 * @return FormValidator
1663
 */
1664
function generateSettingsForm($settings, $settings_by_access_list)
1665
{
1666
    global $_configuration, $settings_to_avoid, $convert_byte_to_mega_list;
1667
    $table_settings_current = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
1668
1669
    $form = new FormValidator(
1670
        'settings',
1671
        'post',
1672
        api_get_path(WEB_CODE_PATH).'admin/settings.php?category='.Security::remove_XSS($_GET['category'])
1673
    );
1674
    $form->protect();
1675
1676
    $form->addElement(
1677
        'hidden',
1678
        'search_field',
1679
        (!empty($_GET['search_field']) ? Security::remove_XSS($_GET['search_field']) : null)
1680
    );
1681
1682
    $url_id = api_get_current_access_url_id();
1683
    $hideCompletely = api_get_configuration_value('multiple_url_hide_disabled_settings');
1684
    /*
1685
    if (!empty($_configuration['multiple_access_urls']) && api_is_global_platform_admin() && $url_id == 1) {
1686
        $group = array();
1687
        $group[] = $form->createElement('button', 'mark_all', get_lang('MarkAll'));
1688
        $group[] = $form->createElement('button', 'unmark_all', get_lang('UnmarkAll'));
1689
        $form->addGroup($group, 'buttons_in_action_right');
1690
    }*/
1691
1692
    $default_values = [];
1693
    $url_info = api_get_access_url($url_id);
1694
    $i = 0;
1695
    $addedSettings = [];
1696
    $globalAdmin = api_is_global_platform_admin();
1697
1698
    foreach ($settings as $row) {
1699
        if (in_array($row['variable'], array_keys($settings_to_avoid))) {
1700
            continue;
1701
        }
1702
1703
        if (in_array($row['variable'], $addedSettings)) {
1704
            continue;
1705
        }
1706
1707
        if (!empty($_configuration['multiple_access_urls'])) {
1708
            if ($globalAdmin) {
1709
                if ($row['access_url_locked'] == 0) {
1710
                    if ($url_id == 1) {
1711
                        if ($row['access_url_changeable'] == '1') {
1712
                            $form->addElement(
1713
                                'html',
1714
                                '<div class="pull-right"><a class="share_this_setting" data_status = "0"  data_to_send = "'.$row['variable'].'" href="javascript:void(0);">'.
1715
                                Display::return_icon('shared_setting.png', get_lang('ChangeSharedSetting'), null, ICON_SIZE_MEDIUM).'</a></div>'
1716
                            );
1717
                        } else {
1718
                            $form->addElement(
1719
                                'html',
1720
                                '<div class="pull-right"><a class="share_this_setting" data_status = "1" data_to_send = "'.$row['variable'].'" href="javascript:void(0);">'.
1721
                                Display::return_icon('shared_setting_na.png', get_lang('ChangeSharedSetting'), null, ICON_SIZE_MEDIUM).'</a></div>'
1722
                            );
1723
                        }
1724
                    } else {
1725
                        if ($row['access_url_changeable'] == '1') {
1726
                            $form->addElement(
1727
                                'html',
1728
                                '<div class="pull-right">'.
1729
                                Display::return_icon('shared_setting.png', get_lang('ChangeSharedSetting'), null, ICON_SIZE_MEDIUM).'</div>'
1730
                            );
1731
                        } else {
1732
                            $form->addElement(
1733
                                'html',
1734
                                '<div class="pull-right">'.
1735
                                Display::return_icon('shared_setting_na.png', get_lang('ChangeSharedSetting'), null, ICON_SIZE_MEDIUM).'</div>'
1736
                            );
1737
                        }
1738
                    }
1739
                }
1740
            }
1741
        }
1742
1743
        $hideme = [];
1744
        $hide_element = false;
1745
1746
        if ($_configuration['access_url'] != 1) {
1747
            if ($row['access_url_changeable'] == 0) {
1748
                // We hide the element in other cases (checkbox, radiobutton) we 'freeze' the element.
1749
                $hide_element = true;
1750
                $hideme = ['disabled'];
1751
                if ($hideCompletely && !$globalAdmin) {
1752
                    continue;
1753
                }
1754
            } elseif ($url_info['active'] == 1) {
1755
                // We show the elements.
1756
                if (empty($row['variable'])) {
1757
                    $row['variable'] = 0;
1758
                }
1759
                if (empty($row['subkey'])) {
1760
                    $row['subkey'] = 0;
1761
                }
1762
                if (empty($row['category'])) {
1763
                    $row['category'] = 0;
1764
                }
1765
                if (isset($settings_by_access_list[$row['variable']]) &&
1766
                    isset($settings_by_access_list[$row['variable']][$row['subkey']]) &&
1767
                    is_array($settings_by_access_list[$row['variable']][$row['subkey']][$row['category']])
1768
                ) {
1769
                    // We are sure that the other site have a selected value.
1770
                    if ($settings_by_access_list[$row['variable']][$row['subkey']][$row['category']]['selected_value'] != '') {
1771
                        $row['selected_value'] = $settings_by_access_list[$row['variable']][$row['subkey']][$row['category']]['selected_value'];
1772
                    }
1773
                }
1774
                // There is no else{} statement because we load the default $row['selected_value'] of the main Chamilo site.
1775
            }
1776
        }
1777
1778
        $addedSettings[] = $row['variable'];
1779
1780
        switch ($row['type']) {
1781
            case 'textfield':
1782
                if (in_array($row['variable'], $convert_byte_to_mega_list)) {
1783
                    $form->addElement(
1784
                        'text',
1785
                        $row['variable'],
1786
                        [
1787
                            get_lang($row['title']),
1788
                            get_lang($row['comment']),
1789
                            get_lang('MB'),
1790
                        ],
1791
                        ['maxlength' => '8', 'aria-label' => get_lang($row['title'])]
1792
                    );
1793
                    $form->applyFilter($row['variable'], 'html_filter');
1794
                    $default_values[$row['variable']] = round($row['selected_value'] / 1024 / 1024, 1);
1795
                } elseif ($row['variable'] == 'account_valid_duration') {
1796
                    $form->addElement(
1797
                        'text',
1798
                        $row['variable'],
1799
                        [
1800
                            get_lang($row['title']),
1801
                            get_lang($row['comment']),
1802
                        ],
1803
                        ['maxlength' => '5', 'aria-label' => get_lang($row['title'])]
1804
                    );
1805
                    $form->applyFilter($row['variable'], 'html_filter');
1806
1807
                    // For platform character set selection:
1808
                    // Conversion of the textfield to a select box with valid values.
1809
                    $default_values[$row['variable']] = $row['selected_value'];
1810
                } elseif ($row['variable'] == 'platform_charset') {
1811
                    break;
1812
                } else {
1813
                    $hideme['class'] = 'col-md-4';
1814
                    $hideme['aria-label'] = get_lang($row['title']);
1815
                    $form->addElement(
1816
                        'text',
1817
                        $row['variable'],
1818
                        [
1819
                            get_lang($row['title']),
1820
                            get_lang($row['comment']),
1821
                        ],
1822
                        $hideme
1823
                    );
1824
                    $form->applyFilter($row['variable'], 'html_filter');
1825
                    $default_values[$row['variable']] = $row['selected_value'];
1826
                }
1827
                break;
1828
            case 'textarea':
1829
                if ($row['variable'] == 'header_extra_content') {
1830
                    $file = api_get_home_path().'header_extra_content.txt';
1831
                    $value = '';
1832
                    if (file_exists($file)) {
1833
                        $value = file_get_contents($file);
1834
                    }
1835
                    $form->addElement(
1836
                        'textarea',
1837
                        $row['variable'],
1838
                        [get_lang($row['title']), get_lang($row['comment'])],
1839
                        ['rows' => '10', 'id' => $row['variable']],
1840
                        $hideme
1841
                    );
1842
                    $default_values[$row['variable']] = $value;
1843
                } elseif ($row['variable'] == 'footer_extra_content') {
1844
                    $file = api_get_home_path().'footer_extra_content.txt';
1845
                    $value = '';
1846
                    if (file_exists($file)) {
1847
                        $value = file_get_contents($file);
1848
                    }
1849
                    $form->addElement(
1850
                        'textarea',
1851
                        $row['variable'],
1852
                        [get_lang($row['title']), get_lang($row['comment'])],
1853
                        ['rows' => '10', 'id' => $row['variable']],
1854
                        $hideme
1855
                    );
1856
                    $default_values[$row['variable']] = $value;
1857
                } else {
1858
                    $form->addElement(
1859
                        'textarea',
1860
                        $row['variable'],
1861
                        [get_lang($row['title']),
1862
                        get_lang($row['comment']), ],
1863
                        ['rows' => '10', 'id' => $row['variable']],
1864
                        $hideme
1865
                    );
1866
                    $default_values[$row['variable']] = $row['selected_value'];
1867
                }
1868
                break;
1869
            case 'radio':
1870
                $values = api_get_settings_options($row['variable']);
1871
                $group = [];
1872
                if (is_array($values)) {
1873
                    foreach ($values as $key => $value) {
1874
                        $element = &$form->createElement(
1875
                            'radio',
1876
                            $row['variable'],
1877
                            '',
1878
                            get_lang($value['display_text']),
1879
                            $value['value']
1880
                        );
1881
                        if ($hide_element) {
1882
                            $element->freeze();
1883
                        }
1884
                        $group[] = $element;
1885
                    }
1886
                }
1887
                $form->addGroup(
1888
                    $group,
1889
                    $row['variable'],
1890
                    [get_lang($row['title']), get_lang($row['comment'])],
1891
                    null,
1892
                    false
1893
                );
1894
                $default_values[$row['variable']] = $row['selected_value'];
1895
                break;
1896
            case 'checkbox':
1897
                // 1. We collect all the options of this variable.
1898
                $sql = "SELECT * FROM $table_settings_current
1899
                        WHERE variable = '".$row['variable']."' AND access_url =  1";
1900
1901
                $result = Database::query($sql);
1902
                $group = [];
1903
                while ($rowkeys = Database::fetch_array($result)) {
1904
                    // Profile tab option should be hidden when the social tool is enabled.
1905
                    if (api_get_setting('allow_social_tool') == 'true') {
1906
                        if ($rowkeys['variable'] === 'show_tabs' && $rowkeys['subkey'] === 'my_profile') {
1907
                            continue;
1908
                        }
1909
                    }
1910
1911
                    // Hiding the gradebook option.
1912
                    if ($rowkeys['variable'] === 'show_tabs' && $rowkeys['subkey'] === 'my_gradebook') {
1913
                        continue;
1914
                    }
1915
1916
                    $element = &$form->createElement(
1917
                        'checkbox',
1918
                        $rowkeys['subkey'],
1919
                        '',
1920
                        get_lang($rowkeys['subkeytext'])
1921
                    );
1922
1923
                    if ($row['access_url_changeable'] == 1) {
1924
                        // 2. We look into the DB if there is a setting for a specific access_url.
1925
                        $access_url = $_configuration['access_url'];
1926
                        if (empty($access_url)) {
1927
                            $access_url = 1;
1928
                        }
1929
                        $sql = "SELECT selected_value FROM $table_settings_current
1930
                                WHERE
1931
                                    variable='".$rowkeys['variable']."' AND
1932
                                    subkey='".$rowkeys['subkey']."' AND
1933
                                    subkeytext='".$rowkeys['subkeytext']."' AND
1934
                                    access_url =  $access_url";
1935
                        $result_access = Database::query($sql);
1936
                        if (Database::num_rows($result_access) > 0) {
1937
                            $row_access = Database::fetch_assoc($result_access);
1938
                            if ($row_access['selected_value'] === 'true' && !$form->isSubmitted()) {
1939
                                $element->setChecked(true);
1940
                            }
1941
                        }
1942
                    } else {
1943
                        if ($rowkeys['selected_value'] === 'true' && !$form->isSubmitted()) {
1944
                            $element->setChecked(true);
1945
                        }
1946
                    }
1947
                    if ($hide_element) {
1948
                        $element->freeze();
1949
                    }
1950
                    $group[] = $element;
1951
                }
1952
                $form->addGroup(
1953
                    $group,
1954
                    $row['variable'],
1955
                    [get_lang($row['title']), get_lang($row['comment'])],
1956
                    null
1957
                );
1958
                break;
1959
            case 'link':
1960
                $form->addElement(
1961
                    'static',
1962
                    null,
1963
                    [get_lang($row['title']), get_lang($row['comment'])],
1964
                    get_lang('CurrentValue').' : '.$row['selected_value'],
1965
                    $hideme
1966
                );
1967
                break;
1968
            case 'select':
1969
                /*
1970
                * To populate the list of options, the select type dynamically calls a
1971
                * function that must be called select_ + the name of the variable being displayed.
1972
                * The functions being called must be added to the file settings.lib.php.
1973
                */
1974
                $form->addElement(
1975
                    'select',
1976
                    $row['variable'],
1977
                    [get_lang($row['title']), get_lang($row['comment'])],
1978
                    call_user_func('select_'.$row['variable']),
1979
                    $hideme
1980
                );
1981
                $default_values[$row['variable']] = $row['selected_value'];
1982
                break;
1983
            case 'custom':
1984
                break;
1985
            case 'select_course':
1986
                $courseSelectOptions = [];
1987
                if (!empty($row['selected_value'])) {
1988
                    $course = api_get_course_entity($row['selected_value']);
1989
                    if ($course) {
1990
                        $courseSelectOptions[$course->getId()] = $course->getTitle();
1991
                    }
1992
                }
1993
1994
                $form->addElement(
1995
                    'select_ajax',
1996
                    $row['variable'],
1997
                    [get_lang($row['title']), get_lang($row['comment'])],
1998
                    $courseSelectOptions,
1999
                    ['url' => api_get_path(WEB_AJAX_PATH).'course.ajax.php?a=search_course']
2000
                );
2001
                $default_values[$row['variable']] = $row['selected_value'];
2002
                break;
2003
        }
2004
2005
        switch ($row['variable']) {
2006
            case 'upload_extensions_replace_by':
2007
                $default_values[$row['variable']] = api_replace_dangerous_char(
2008
                    str_replace('.', '', $default_values[$row['variable']])
2009
                );
2010
                break;
2011
            case 'pdf_export_watermark_enable':
2012
                $url = PDF::get_watermark(null);
2013
2014
                if ($url != false) {
2015
                    $delete_url = '<a href="?delete_watermark">'.get_lang('DelImage').' '.Display::return_icon('delete.png', get_lang('DelImage')).'</a>';
2016
                    $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>');
2017
                }
2018
2019
                $form->addElement('file', 'pdf_export_watermark_path', get_lang('AddWaterMark'));
2020
                $allowed_picture_types = ['jpg', 'jpeg', 'png', 'gif'];
2021
                $form->addRule(
2022
                    'pdf_export_watermark_path',
2023
                    get_lang('OnlyImagesAllowed').' ('.implode(',', $allowed_picture_types).')',
2024
                    'filetype',
2025
                    $allowed_picture_types
2026
                );
2027
2028
                break;
2029
            case 'timezone_value':
2030
                $timezone = $row['selected_value'];
2031
                if (empty($timezone)) {
2032
                    $timezone = api_get_timezone();
2033
                }
2034
                $form->addLabel('', sprintf(get_lang('LocalTimeUsingPortalTimezoneXIsY'), $timezone, api_get_local_time()));
2035
                break;
2036
        }
2037
    } // end for
2038
2039
    if (!empty($settings)) {
2040
        $form->setDefaults($default_values);
2041
    }
2042
    $form->addHtml('<div class="bottom_actions">');
2043
    $form->addButtonSave(get_lang('SaveSettings'));
2044
    $form->addHtml('</div>');
2045
2046
    return $form;
2047
}
2048
2049
/**
2050
 * Searches a platform setting in all categories except from the Plugins category.
2051
 *
2052
 * @param string $search
2053
 *
2054
 * @return array
2055
 */
2056
function searchSetting($search)
2057
{
2058
    if (empty($search)) {
2059
        return [];
2060
    }
2061
    $table_settings_current = Database::get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
2062
    $sql = "SELECT * FROM $table_settings_current
2063
            WHERE category <> 'Plugins' ORDER BY id ASC ";
2064
    $result = Database::store_result(Database::query($sql), 'ASSOC');
2065
    $settings = [];
2066
2067
    $search = api_strtolower($search);
2068
2069
    if (!empty($result)) {
2070
        foreach ($result as $setting) {
2071
            $found = false;
2072
2073
            $title = api_strtolower(get_lang($setting['title']));
2074
            // try the title
2075
            if (strpos($title, $search) === false) {
2076
                $comment = api_strtolower(get_lang($setting['comment']));
2077
                //Try the comment
2078
                if (strpos($comment, $search) === false) {
2079
                    //Try the variable name
2080
                    if (strpos($setting['variable'], $search) === false) {
2081
                        continue;
2082
                    } else {
2083
                        $found = true;
2084
                    }
2085
                } else {
2086
                    $found = true;
2087
                }
2088
            } else {
2089
                $found = true;
2090
            }
2091
            if ($found) {
2092
                $settings[] = $setting;
2093
            }
2094
        }
2095
    }
2096
2097
    return $settings;
2098
}
2099
/**
2100
 * Helper function to generates a form elements group.
2101
 *
2102
 * @param object $form   The form where the elements group has to be added
2103
 * @param array  $values Values to browse through
2104
 *
2105
 * @return array
2106
 */
2107
function formGenerateElementsGroup($form, $values, $elementName)
2108
{
2109
    $group = [];
2110
    if (is_array($values)) {
2111
        foreach ($values as $key => $value) {
2112
            $element = &$form->createElement('radio', $elementName, '', get_lang($value['display_text']), $value['value']);
2113
            $group[] = $element;
2114
        }
2115
    }
2116
2117
    return $group;
2118
}
2119
/**
2120
 * Helper function with allowed file types for CSS.
2121
 *
2122
 * @return array Array of file types (no indexes)
2123
 */
2124
function getAllowedFileTypes()
2125
{
2126
    $allowedFiles = [
2127
        'css',
2128
        'zip',
2129
        'jpeg',
2130
        'jpg',
2131
        'png',
2132
        'gif',
2133
        'ico',
2134
        'psd',
2135
        'xcf',
2136
        'svg',
2137
        'webp',
2138
        'woff',
2139
        'woff2',
2140
        'md',
2141
        'html',
2142
        'xml',
2143
        'markdown',
2144
        'txt',
2145
    ];
2146
2147
    return $allowedFiles;
2148
}
2149
/**
2150
 * Helper function to set settings in the database.
2151
 *
2152
 * @param array $parameters List of values
2153
 * @param int   $accessUrl  The current access URL
2154
 */
2155
function setConfigurationSettingsInDatabase($parameters, $accessUrl)
2156
{
2157
    api_set_settings_category('Search', 'false', $accessUrl);
2158
    // Save the settings.
2159
    foreach ($parameters as $key => $value) {
2160
        api_set_setting($key, $value, null, null);
2161
    }
2162
}
2163
2164
/**
2165
 * Helper function to show the status of the search settings table.
2166
 *
2167
 * @param array $data Data to show
2168
 */
2169
function showSearchSettingsTable($data)
2170
{
2171
    echo Display::tag('h3', get_lang('Settings'));
2172
    $table = new SortableTableFromArray($data);
2173
    $table->set_header(0, get_lang('Setting'), false);
2174
    $table->set_header(1, get_lang('Status'), false);
2175
    echo $table->display();
2176
}
2177
/**
2178
 * Helper function to show status table for each command line tool installed.
2179
 */
2180
function showSearchToolsStatusTable()
2181
{
2182
    //@todo windows support
2183
    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...
2184
        $list_of_programs = ['pdftotext', 'ps2pdf', 'catdoc', 'html2text', 'unrtf', 'catppt', 'xls2csv'];
2185
        foreach ($list_of_programs as $program) {
2186
            $output = [];
2187
            $ret_val = null;
2188
            exec("which $program", $output, $ret_val);
2189
2190
            if (!$output) {
2191
                $output[] = '';
2192
            }
2193
2194
            $icon = Display::return_icon('bullet_red.png', get_lang('NotInstalled'));
2195
            if (!empty($output[0])) {
2196
                $icon = Display::return_icon('bullet_green.png', get_lang('Installed'));
2197
            }
2198
            $data2[] = [$program, $output[0], $icon];
2199
        }
2200
        echo Display::tag('h3', get_lang('ProgramsNeededToConvertFiles'));
2201
        $table = new SortableTableFromArray($data2);
2202
        $table->set_header(0, get_lang('Program'), false);
2203
        $table->set_header(1, get_lang('Path'), false);
2204
        $table->set_header(2, get_lang('Status'), false);
2205
        echo $table->display();
2206
    } else {
2207
        echo Display::return_message(
2208
            get_lang('YouAreUsingChamiloInAWindowsPlatformSadlyYouCantConvertDocumentsInOrderToSearchTheContentUsingThisTool'),
2209
            'warning'
2210
        );
2211
    }
2212
}
2213
/**
2214
 * Helper function to generate and show CSS Zip download message.
2215
 *
2216
 * @param string $style Style path
2217
 */
2218
function generateCSSDownloadLink($style)
2219
{
2220
    $arch = api_get_path(SYS_ARCHIVE_PATH).$style.'.zip';
2221
    $themeDir = Template::getThemeDir($style);
2222
    $dir = api_get_path(SYS_CSS_PATH).$themeDir;
2223
    $check = Security::check_abs_path(
2224
        $dir,
2225
        api_get_path(SYS_CSS_PATH).'themes'
2226
    );
2227
    if (is_dir($dir) && $check) {
2228
        $zip = new PclZip($arch);
2229
        // Remove path prefix except the style name and put file on disk
2230
        $zip->create($dir, PCLZIP_OPT_REMOVE_PATH, dirname($dir));
2231
        $url = api_get_path(WEB_CODE_PATH).'course_info/download.php?archive_path=&archive='.str_replace(api_get_path(SYS_ARCHIVE_PATH), '', $arch);
2232
2233
        //@TODO: use more generic script to download.
2234
        $str = '<a class="btn btn-primary btn-large" href="'.$url.'">'.get_lang('ClickHereToDownloadTheFile').'</a>';
2235
        echo Display::return_message($str, 'normal', false);
2236
    } else {
2237
        echo Display::return_message(get_lang('FileNotFound'), 'warning');
2238
    }
2239
}
2240
2241
/**
2242
 * Helper function to tell if the style is changeable in the current URL.
2243
 *
2244
 * @return bool $changeable Whether the style can be changed in this URL or not
2245
 */
2246
function isStyleChangeable()
2247
{
2248
    $changeable = false;
2249
    $urlId = api_get_current_access_url_id();
2250
    if ($urlId) {
2251
        $style_info = api_get_settings('stylesheets', '', 1, 0);
2252
        $url_info = api_get_access_url($urlId);
2253
        if ($style_info[0]['access_url_changeable'] == 1 && $url_info['active'] == 1) {
2254
            $changeable = true;
2255
        }
2256
    } else {
2257
        $changeable = true;
2258
    }
2259
2260
    return $changeable;
2261
}
2262
2263
/**
2264
 * Get all settings of one category prepared for display in admin/settings.php.
2265
 *
2266
 * @param string $category
2267
 *
2268
 * @return array
2269
 */
2270
function getCategorySettings($category = '')
2271
{
2272
    $url_id = api_get_current_access_url_id();
2273
    $settings_by_access_list = [];
2274
2275
    if ($url_id == 1) {
2276
        $settings = api_get_settings($category, 'group', $url_id);
2277
    } else {
2278
        $url_info = api_get_access_url($url_id);
2279
        if ($url_info['active'] == 1) {
2280
            $categoryToSearch = $category;
2281
            if ($category == 'search_setting') {
2282
                $categoryToSearch = '';
2283
            }
2284
            // The default settings of Chamilo
2285
            $settings = api_get_settings($categoryToSearch, 'group', 1, 0);
2286
            // The settings that are changeable from a particular site.
2287
            $settings_by_access = api_get_settings($categoryToSearch, 'group', $url_id, 1);
2288
2289
            foreach ($settings_by_access as $row) {
2290
                if (empty($row['variable'])) {
2291
                    $row['variable'] = 0;
2292
                }
2293
                if (empty($row['subkey'])) {
2294
                    $row['subkey'] = 0;
2295
                }
2296
                if (empty($row['category'])) {
2297
                    $row['category'] = 0;
2298
                }
2299
2300
                // One more validation if is changeable.
2301
                if ($row['access_url_changeable'] == 1) {
2302
                    $settings_by_access_list[$row['variable']][$row['subkey']][$row['category']] = $row;
2303
                } else {
2304
                    $settings_by_access_list[$row['variable']][$row['subkey']][$row['category']] = [];
2305
                }
2306
            }
2307
        }
2308
    }
2309
2310
    if (isset($category) && $category == 'search_setting') {
2311
        if (!empty($_REQUEST['search_field'])) {
2312
            $settings = searchSetting($_REQUEST['search_field']);
2313
        }
2314
    }
2315
2316
    return [
2317
        'settings' => $settings,
2318
        'settings_by_access_list' => $settings_by_access_list,
2319
    ];
2320
}
2321