settings.lib.php 66 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744
  1. <?php
  2. /* For licensing terms, see /license.txt */
  3. use Symfony\Component\Filesystem\Filesystem;
  4. use Chamilo\CoreBundle\Component\Utils\ChamiloApi;
  5. /**
  6. * Library of the settings.php file
  7. *
  8. * @author Julio Montoya <gugli100@gmail.com>
  9. * @author Guillaume Viguier <guillaume@viguierjust.com>
  10. *
  11. * @since Chamilo 1.8.7
  12. * @package chamilo.admin
  13. */
  14. define('CSS_UPLOAD_PATH', api_get_path(SYS_APP_PATH).'Resources/public/css/themes/');
  15. /**
  16. * This function allows easy activating and inactivating of regions
  17. * @author Julio Montoya <gugli100@gmail.com> Beeznest 2012
  18. */
  19. function handleRegions()
  20. {
  21. if (isset($_POST['submit_plugins'])) {
  22. storeRegions();
  23. // Add event to the system log.
  24. $user_id = api_get_user_id();
  25. $category = $_GET['category'];
  26. Event::addEvent(
  27. LOG_CONFIGURATION_SETTINGS_CHANGE,
  28. LOG_CONFIGURATION_SETTINGS_CATEGORY,
  29. $category,
  30. api_get_utc_datetime(),
  31. $user_id
  32. );
  33. Display :: display_confirmation_message(get_lang('SettingsStored'));
  34. }
  35. $plugin_obj = new AppPlugin();
  36. $possible_plugins = $plugin_obj->read_plugins_from_path();
  37. $installed_plugins = $plugin_obj->get_installed_plugins();
  38. echo '<form name="plugins" method="post" action="'.api_get_self().'?category='.Security::remove_XSS($_GET['category']).'">';
  39. echo '<table class="data_table">';
  40. echo '<tr>';
  41. echo '<th width="400px">';
  42. echo get_lang('Plugin');
  43. echo '</th><th>';
  44. echo get_lang('Regions');
  45. echo '</th>';
  46. echo '</th>';
  47. echo '</tr>';
  48. /* We display all the possible plugins and the checkboxes */
  49. $plugin_region_list = array();
  50. $my_plugin_list = $plugin_obj->get_plugin_regions();
  51. foreach ($my_plugin_list as $plugin_item) {
  52. $plugin_region_list[$plugin_item] = $plugin_item;
  53. }
  54. // Removing course tool
  55. unset($plugin_region_list['course_tool_plugin']);
  56. foreach ($installed_plugins as $pluginName) {
  57. $plugin_info_file = api_get_path(SYS_PLUGIN_PATH).$pluginName.'/plugin.php';
  58. if (file_exists($plugin_info_file)) {
  59. $plugin_info = array();
  60. require $plugin_info_file;
  61. if (isset($_GET['name']) && $_GET['name'] === $pluginName) {
  62. echo '<tr class="row_selected">';
  63. } else {
  64. echo '<tr>';
  65. }
  66. echo '<td>';
  67. echo '<h4>'.$plugin_info['title'].' <small>v'.$plugin_info['version'].'</small></h4>';
  68. echo '<p>'.$plugin_info['comment'].'</p>';
  69. echo '</td><td>';
  70. $selected_plugins = $plugin_obj->get_areas_by_plugin($pluginName);
  71. $region_list = [];
  72. $isAdminPlugin = isset($plugin_info['is_admin_plugin']) && $plugin_info['is_admin_plugin'];
  73. $isCoursePlugin = isset($plugin_info['is_course_plugin']) && $plugin_info['is_course_plugin'];
  74. if (!$isAdminPlugin && !$isCoursePlugin) {
  75. $region_list = $plugin_region_list;
  76. } else {
  77. if ($isAdminPlugin) {
  78. $region_list['menu_administrator'] = 'menu_administrator';
  79. }
  80. if ($isCoursePlugin) {
  81. $region_list['course_tool_plugin'] = 'course_tool_plugin';
  82. }
  83. }
  84. echo Display::select(
  85. 'plugin_'.$pluginName.'[]',
  86. $region_list,
  87. $selected_plugins,
  88. array('multiple' => 'multiple', 'style' => 'width:500px'),
  89. true,
  90. get_lang('None')
  91. );
  92. echo '</td></tr>';
  93. }
  94. }
  95. echo '</table>';
  96. echo '<br />';
  97. echo '<button class="btn btn-success" type="submit" name="submit_plugins">'.get_lang('EnablePlugins').'</button></form>';
  98. }
  99. function handleExtensions()
  100. {
  101. echo Display::page_subheader(get_lang('ConfigureExtensions'));
  102. echo '<a class="btn btn-success" href="configure_extensions.php?display=ppt2lp" role="button">'.get_lang('Ppt2lp').'</a>';
  103. }
  104. /**
  105. * This function allows easy activating and inactivating of plugins
  106. * @todo: a similar function needs to be written to activate or inactivate additional tools.
  107. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  108. * @author Julio Montoya <gugli100@gmail.com> Beeznest 2012
  109. */
  110. function handlePlugins()
  111. {
  112. $plugin_obj = new AppPlugin();
  113. $token = Security::get_token();
  114. if (isset($_POST['submit_plugins'])) {
  115. storePlugins();
  116. // Add event to the system log.
  117. $user_id = api_get_user_id();
  118. $category = $_GET['category'];
  119. Event::addEvent(
  120. LOG_CONFIGURATION_SETTINGS_CHANGE,
  121. LOG_CONFIGURATION_SETTINGS_CATEGORY,
  122. $category,
  123. api_get_utc_datetime(),
  124. $user_id
  125. );
  126. Display :: display_confirmation_message(get_lang('SettingsStored'));
  127. }
  128. $all_plugins = $plugin_obj->read_plugins_from_path();
  129. $installed_plugins = $plugin_obj->get_installed_plugins();
  130. //Plugins NOT installed
  131. echo Display::page_subheader(get_lang('Plugins'));
  132. echo '<form class="form-horizontal" name="plugins" method="post" action="'.api_get_self().'?category='.Security::remove_XSS($_GET['category']).'&sec_token=' . $token . '">';
  133. echo '<table class="data_table">';
  134. echo '<tr>';
  135. echo '<th width="20px">';
  136. echo get_lang('Action');
  137. echo '</th><th>';
  138. echo get_lang('Description');
  139. echo '</th>';
  140. echo '</tr>';
  141. /*$plugin_list = array();
  142. $my_plugin_list = $plugin_obj->get_plugin_regions();
  143. foreach($my_plugin_list as $plugin_item) {
  144. $plugin_list[$plugin_item] = $plugin_item;
  145. }*/
  146. foreach ($all_plugins as $pluginName) {
  147. $plugin_info_file = api_get_path(SYS_PLUGIN_PATH).$pluginName.'/plugin.php';
  148. if (file_exists($plugin_info_file)) {
  149. $plugin_info = array();
  150. require $plugin_info_file;
  151. if (in_array($pluginName, $installed_plugins)) {
  152. echo '<tr class="row_selected">';
  153. } else {
  154. echo '<tr>';
  155. }
  156. echo '<td>';
  157. //Checkbox
  158. if (in_array($pluginName, $installed_plugins)) {
  159. echo '<input type="checkbox" name="plugin_'.$pluginName.'[]" checked="checked">';
  160. } else {
  161. echo '<input type="checkbox" name="plugin_'.$pluginName.'[]">';
  162. }
  163. echo '</td><td>';
  164. echo '<h4>'.$plugin_info['title'].' <small>v '.$plugin_info['version'].'</small></h4>';
  165. echo '<p>'.$plugin_info['comment'].'</p>';
  166. echo '<p>'.get_lang('Author').': '.$plugin_info['author'].'</p>';
  167. echo '<div class="btn-group">';
  168. if (in_array($pluginName, $installed_plugins)) {
  169. echo Display::url('<em class="fa fa-cogs"></em> '.get_lang('Configure'), 'configure_plugin.php?name='.$pluginName, array('class' => 'btn btn-default'));
  170. echo Display::url('<em class="fa fa-th-large"></em> '.get_lang('Regions'), 'settings.php?category=Regions&name='.$pluginName, array('class' => 'btn btn-default'));
  171. }
  172. if (file_exists(api_get_path(SYS_PLUGIN_PATH).$pluginName.'/readme.txt')) {
  173. echo Display::url(
  174. "<em class='fa fa-file-text-o'></em> readme.txt",
  175. api_get_path(WEB_PLUGIN_PATH) . $pluginName . "/readme.txt",
  176. [
  177. 'class' => 'btn btn-default ajax',
  178. 'data-title' => $plugin_info['title'],
  179. 'data-size' => 'lg',
  180. '_target' => '_blank'
  181. ]
  182. );
  183. }
  184. $readmeFile = api_get_path(SYS_PLUGIN_PATH).$pluginName.'/README.md';
  185. if (file_exists($readmeFile)) {
  186. echo Display::url(
  187. "<em class='fa fa-file-text-o'></em> README.md",
  188. api_get_path(WEB_AJAX_PATH).'plugin.ajax.php?a=md_to_html&plugin='.$pluginName,
  189. [
  190. 'class' => 'btn btn-default ajax',
  191. 'data-title' => $plugin_info['title'],
  192. 'data-size' => 'lg',
  193. '_target' => '_blank'
  194. ]
  195. );
  196. }
  197. echo '</div>';
  198. echo '</td></tr>';
  199. }
  200. }
  201. echo '</table>';
  202. echo '<div class="form-actions bottom_actions">';
  203. echo '<button class="btn btn-success" type="submit" name="submit_plugins">'.
  204. get_lang('EnablePlugins').'</button>';
  205. echo '</div>';
  206. echo '</form>';
  207. }
  208. /**
  209. * This function allows the platform admin to choose the default stylesheet
  210. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  211. * @author Julio Montoya <gugli100@gmail.com>, Chamilo
  212. */
  213. function handleStylesheets()
  214. {
  215. global $_configuration;
  216. // Current style.
  217. $currentstyle = api_get_setting('stylesheets');
  218. $is_style_changeable = isStyleChangeable();
  219. $form = new FormValidator(
  220. 'stylesheet_upload',
  221. 'post',
  222. 'settings.php?category=Stylesheets#tabs-3'
  223. );
  224. $form->addElement('text', 'name_stylesheet', get_lang('NameStylesheet'),
  225. array('size' => '40', 'maxlength' => '40'));
  226. $form->addRule('name_stylesheet', get_lang('ThisFieldIsRequired'), 'required');
  227. $form->addElement('file', 'new_stylesheet', get_lang('UploadNewStylesheet'));
  228. $allowed_file_types = getAllowedFileTypes();
  229. $form->addRule('new_stylesheet', get_lang('InvalidExtension') . ' (' . implode(',', $allowed_file_types) . ')',
  230. 'filetype', $allowed_file_types);
  231. $form->addRule('new_stylesheet', get_lang('ThisFieldIsRequired'), 'required');
  232. $form->addButtonUpload(get_lang('Upload'), 'stylesheet_upload');
  233. $show_upload_form = false;
  234. if (!is_writable(CSS_UPLOAD_PATH)) {
  235. Display::display_error_message(CSS_UPLOAD_PATH.get_lang('IsNotWritable'));
  236. } else {
  237. // Uploading a new stylesheet.
  238. if ($_configuration['access_url'] == 1) {
  239. $show_upload_form = true;
  240. } else {
  241. if ($is_style_changeable) {
  242. $show_upload_form = true;
  243. }
  244. }
  245. }
  246. // Stylesheet upload.
  247. if (isset($_POST['stylesheet_upload'])) {
  248. if ($form->validate()) {
  249. $values = $form->exportValues();
  250. $picture_element = $form->getElement('new_stylesheet');
  251. $picture = $picture_element->getValue();
  252. $result = uploadStylesheet($values, $picture);
  253. // Add event to the system log.
  254. $user_id = api_get_user_id();
  255. $category = $_GET['category'];
  256. Event::addEvent(
  257. LOG_CONFIGURATION_SETTINGS_CHANGE,
  258. LOG_CONFIGURATION_SETTINGS_CATEGORY,
  259. $category,
  260. api_get_utc_datetime(),
  261. $user_id
  262. );
  263. if ($result) {
  264. Display::display_confirmation_message(get_lang('StylesheetAdded'));
  265. }
  266. }
  267. }
  268. $form_change = new FormValidator(
  269. 'stylesheet_upload',
  270. 'post',
  271. api_get_self().'?category=Stylesheets',
  272. null,
  273. array('id' => 'stylesheets_id')
  274. );
  275. $list_of_names = array();
  276. $selected = '';
  277. $dirpath = '';
  278. $safe_style_dir = '';
  279. if ($handle = @opendir(CSS_UPLOAD_PATH)) {
  280. $counter = 1;
  281. while (false !== ($style_dir = readdir($handle))) {
  282. if (substr($style_dir, 0, 1) == '.') {
  283. // Skip directories starting with a '.'
  284. continue;
  285. }
  286. $dirpath = CSS_UPLOAD_PATH.$style_dir;
  287. if (is_dir($dirpath)) {
  288. if ($style_dir != '.' && $style_dir != '..') {
  289. if (isset($_POST['style']) &&
  290. (isset($_POST['preview']) || isset($_POST['download'])) &&
  291. $_POST['style'] == $style_dir
  292. ) {
  293. $safe_style_dir = $style_dir;
  294. } else {
  295. if ($currentstyle == $style_dir || ($style_dir == 'chamilo' && !$currentstyle)) {
  296. if (isset($_POST['style'])) {
  297. $selected = Database::escape_string($_POST['style']);
  298. } else {
  299. $selected = $style_dir;
  300. }
  301. }
  302. }
  303. $show_name = ucwords(str_replace('_', ' ', $style_dir));
  304. if ($is_style_changeable) {
  305. $list_of_names[$style_dir] = $show_name;
  306. }
  307. $counter++;
  308. }
  309. }
  310. }
  311. closedir($handle);
  312. }
  313. // Sort styles in alphabetical order.
  314. asort($list_of_names);
  315. $select_list = array();
  316. foreach ($list_of_names as $style_dir => $item) {
  317. $select_list[$style_dir] = $item;
  318. }
  319. $styles = &$form_change->addElement('select', 'style', get_lang('NameStylesheet'), $select_list);
  320. $styles->setSelected($selected);
  321. if ($form_change->validate()) {
  322. // Submit stylesheets.
  323. if (isset($_POST['save'])) {
  324. storeStylesheets();
  325. Display::display_normal_message(get_lang('Saved'));
  326. }
  327. if (isset($_POST['download'])) {
  328. generateCSSDownloadLink($safe_style_dir);
  329. }
  330. }
  331. $logoForm = new FormValidator(
  332. 'logo_upload',
  333. 'post',
  334. 'settings.php?category=Stylesheets#tabs-2'
  335. );
  336. $logoForm->addHtml(
  337. Display::return_message(sprintf(get_lang('TheLogoMustBeSizeXAndFormatY'), '250 x 70', 'PNG'), 'info')
  338. );
  339. $dir = api_get_path(SYS_PUBLIC_PATH).'css/themes/' . $selected . '/images/';
  340. $url = api_get_path(WEB_CSS_PATH).'themes/' . $selected . '/images/';
  341. $logoFileName = 'header-logo.png';
  342. $newLogoFileName = 'header-logo-custom' . api_get_current_access_url_id() . '.png';
  343. $webPlatformLogoPath = ChamiloApi::getWebPlatformLogoPath();
  344. if ($webPlatformLogoPath !== null) {
  345. $logoForm->addLabel(
  346. get_lang('CurrentLogo'),
  347. '<img id="header-logo-custom" src="' . $webPlatformLogoPath . '?' . time() . '">'
  348. );
  349. }
  350. $logoForm->addFile('new_logo', get_lang('UpdateLogo'));
  351. $allowedFileTypes = ['png'];
  352. if (isset($_POST['logo_reset'])) {
  353. if (is_file($dir.$newLogoFileName)) {
  354. unlink($dir.$newLogoFileName);
  355. echo Display::return_message(get_lang('ResetToTheOriginalLogo'));
  356. echo '<script>'
  357. . '$("#header-logo").attr("src","'.$url.$logoFileName.'");'
  358. . '</script>';
  359. }
  360. } elseif (isset($_POST['logo_upload'])) {
  361. $logoForm->addRule('new_logo', get_lang('InvalidExtension').' ('.implode(',', $allowedFileTypes).')', 'filetype', $allowedFileTypes);
  362. $logoForm->addRule('new_logo', get_lang('ThisFieldIsRequired'), 'required');
  363. if ($logoForm->validate()) {
  364. $imageInfo = getimagesize($_FILES['new_logo']['tmp_name']);
  365. $width = $imageInfo[0];
  366. $height = $imageInfo[1];
  367. if ($width <= 250 && $height <= 70 ) {
  368. if (is_file($dir.$newLogoFileName)) {
  369. unlink($dir.$newLogoFileName);
  370. }
  371. $status = move_uploaded_file($_FILES['new_logo']['tmp_name'], $dir.$newLogoFileName);
  372. if ($status) {
  373. echo Display::return_message(get_lang('NewLogoUpdated'));
  374. echo '<script>'
  375. . '$("#header-logo").attr("src","'.$url.$newLogoFileName.'");'
  376. . '</script>';
  377. } else {
  378. echo Display::return_message('Error - '.get_lang('UplNoFileUploaded'), 'error');
  379. }
  380. } else {
  381. Display::return_message('Error - '.get_lang('InvalidImageDimensions'), 'error');
  382. }
  383. }
  384. }
  385. if ($is_style_changeable) {
  386. $group = [
  387. $form_change->addButtonSave(get_lang('SaveSettings'), 'save', true),
  388. $form_change->addButtonPreview(get_lang('Preview'), 'preview', true),
  389. $form_change->addButtonDownload(get_lang('Download'), 'download', true)
  390. ];
  391. $form_change->addGroup($group);
  392. $logoGroup = [
  393. $logoForm->addButtonUpload(get_lang('Upload'), 'logo_upload', true),
  394. $logoForm->addButtonCancel(get_lang('Reset'), 'logo_reset', true)
  395. ];
  396. $logoForm->addGroup($logoGroup);
  397. if ($show_upload_form) {
  398. echo '<script>
  399. $(function() {
  400. $( "#tabs" ).tabs();
  401. });
  402. </script>';
  403. echo Display::tabs(
  404. array(get_lang('Update'),get_lang('UpdateLogo'), get_lang('UploadNewStylesheet')),
  405. array($form_change->return_form(), $logoForm->returnForm(), $form->returnForm())
  406. );
  407. } else {
  408. $form_change->display();
  409. }
  410. //Little hack to update the logo image in update form when submiting
  411. if (isset($_POST['logo_reset'])) {
  412. echo '<script>'
  413. . '$("#header-logo-custom").attr("src","'.$url.$logoFileName.'");'
  414. . '</script>';
  415. } elseif (isset($_POST['logo_upload']) && is_file($dir.$newLogoFileName)) {
  416. echo '<script>'
  417. . '$("#header-logo-custom").attr("src","'.$url.$newLogoFileName.'");'
  418. . '</script>';
  419. }
  420. } else {
  421. $form_change->freeze();
  422. }
  423. }
  424. /**
  425. * Creates the folder (if needed) and uploads the stylesheet in it
  426. * @param array $values the values of the form
  427. * @param array $picture the values of the uploaded file
  428. * @return bool
  429. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University, Belgium
  430. * @version May 2008
  431. * @since v1.8.5
  432. */
  433. function uploadStylesheet($values, $picture)
  434. {
  435. $result = false;
  436. // Valid name for the stylesheet folder.
  437. $style_name = api_preg_replace('/[^A-Za-z0-9]/', '', $values['name_stylesheet']);
  438. $cssToUpload = CSS_UPLOAD_PATH;
  439. // Create the folder if needed.
  440. if (!is_dir($cssToUpload.$style_name.'/')) {
  441. mkdir($cssToUpload.$style_name.'/', api_get_permissions_for_new_directories());
  442. }
  443. $info = pathinfo($picture['name']);
  444. if ($info['extension'] == 'zip') {
  445. // Try to open the file and extract it in the theme.
  446. $zip = new ZipArchive();
  447. if ($zip->open($picture['tmp_name'])) {
  448. // Make sure all files inside the zip are images or css.
  449. $num_files = $zip->numFiles;
  450. $valid = true;
  451. $single_directory = true;
  452. $invalid_files = array();
  453. $allowedFiles = getAllowedFileTypes();
  454. for ($i = 0; $i < $num_files; $i++) {
  455. $file = $zip->statIndex($i);
  456. if (substr($file['name'], -1) != '/') {
  457. $path_parts = pathinfo($file['name']);
  458. if (!in_array($path_parts['extension'], $allowedFiles)) {
  459. $valid = false;
  460. $invalid_files[] = $file['name'];
  461. }
  462. }
  463. if (strpos($file['name'], '/') === false) {
  464. $single_directory = false;
  465. }
  466. }
  467. if (!$valid) {
  468. $error_string = '<ul>';
  469. foreach ($invalid_files as $invalid_file) {
  470. $error_string .= '<li>'.$invalid_file.'</li>';
  471. }
  472. $error_string .= '</ul>';
  473. Display::display_error_message(
  474. get_lang('ErrorStylesheetFilesExtensionsInsideZip').$error_string,
  475. false
  476. );
  477. } else {
  478. // If the zip does not contain a single directory, extract it.
  479. if (!$single_directory) {
  480. // Extract zip file.
  481. $zip->extractTo($cssToUpload.$style_name.'/');
  482. $result = true;
  483. } else {
  484. $extraction_path = $cssToUpload.$style_name.'/';
  485. for ($i = 0; $i < $num_files; $i++) {
  486. $entry = $zip->getNameIndex($i);
  487. if (substr($entry, -1) == '/') {
  488. continue;
  489. }
  490. $pos_slash = strpos($entry, '/');
  491. $entry_without_first_dir = substr($entry, $pos_slash + 1);
  492. // If there is still a slash, we need to make sure the directories are created.
  493. if (strpos($entry_without_first_dir, '/') !== false) {
  494. if (!is_dir($extraction_path.dirname($entry_without_first_dir))) {
  495. // Create it.
  496. @mkdir($extraction_path.dirname($entry_without_first_dir), $mode = 0777, true);
  497. }
  498. }
  499. $fp = $zip->getStream($entry);
  500. $ofp = fopen($extraction_path.dirname($entry_without_first_dir).'/'.basename($entry), 'w');
  501. while (!feof($fp)) {
  502. fwrite($ofp, fread($fp, 8192));
  503. }
  504. fclose($fp);
  505. fclose($ofp);
  506. }
  507. $result = true;
  508. }
  509. }
  510. $zip->close();
  511. } else {
  512. Display::display_error_message(get_lang('ErrorReadingZip').$info['extension'], false);
  513. }
  514. } else {
  515. // Simply move the file.
  516. move_uploaded_file($picture['tmp_name'], $cssToUpload.$style_name.'/'.$picture['name']);
  517. $result = true;
  518. }
  519. if ($result) {
  520. $fs = new Filesystem();
  521. $fs->mirror($cssToUpload, api_get_path(SYS_PATH).'web/css/themes/');
  522. }
  523. return $result;
  524. }
  525. /**
  526. * Store plugin regions.
  527. */
  528. function storeRegions()
  529. {
  530. $plugin_obj = new AppPlugin();
  531. // Get a list of all current 'Plugins' settings
  532. $installed_plugins = $plugin_obj->get_installed_plugins();
  533. $shortlist_installed = array();
  534. if (!empty($installed_plugins)) {
  535. foreach ($installed_plugins as $plugin) {
  536. if (isset($plugin['subkey'])) {
  537. $shortlist_installed[] = $plugin['subkey'];
  538. }
  539. }
  540. }
  541. $shortlist_installed = array_flip(array_flip($shortlist_installed));
  542. $plugin_list = $plugin_obj->read_plugins_from_path();
  543. foreach ($plugin_list as $plugin) {
  544. if (isset($_POST['plugin_'.$plugin])) {
  545. $areas_to_installed = $_POST['plugin_'.$plugin];
  546. if (!empty($areas_to_installed)) {
  547. $plugin_obj->remove_all_regions($plugin);
  548. foreach ($areas_to_installed as $region) {
  549. if (!empty($region) && $region != '-1' ) {
  550. $plugin_obj->add_to_region($plugin, $region);
  551. }
  552. }
  553. }
  554. }
  555. }
  556. }
  557. /**
  558. * This function allows easy activating and inactivating of plugins
  559. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  560. */
  561. function storePlugins()
  562. {
  563. $appPlugin = new AppPlugin();
  564. // Get a list of all current 'Plugins' settings
  565. $plugin_list = $appPlugin->read_plugins_from_path();
  566. $installed_plugins = array();
  567. foreach ($plugin_list as $plugin) {
  568. if (isset($_POST['plugin_'.$plugin])) {
  569. $appPlugin->install($plugin);
  570. $installed_plugins[] = $plugin;
  571. }
  572. }
  573. if (!empty($installed_plugins)) {
  574. $remove_plugins = array_diff($plugin_list, $installed_plugins);
  575. } else {
  576. $remove_plugins = $plugin_list;
  577. }
  578. foreach ($remove_plugins as $plugin) {
  579. $appPlugin->uninstall($plugin);
  580. }
  581. }
  582. /**
  583. * This function allows the platform admin to choose which should be the default stylesheet
  584. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  585. */
  586. function storeStylesheets()
  587. {
  588. // Insert the stylesheet.
  589. if (isStyle($_POST['style'])) {
  590. api_set_setting(
  591. 'stylesheets',
  592. $_POST['style'],
  593. null,
  594. 'stylesheets',
  595. api_get_current_access_url_id()
  596. );
  597. }
  598. return true;
  599. }
  600. /**
  601. * This function checks if the given style is a recognize style that exists in the css directory as
  602. * a standalone directory.
  603. * @param string Style
  604. * @return bool True if this style is recognized, false otherwise
  605. */
  606. function isStyle($style)
  607. {
  608. $dir = CSS_UPLOAD_PATH;
  609. $dirs = scandir($dir);
  610. $style = str_replace(array('/', '\\'), array('', ''), $style); // Avoid slashes or backslashes.
  611. if (in_array($style, $dirs) && is_dir($dir.$style)) {
  612. return true;
  613. }
  614. return false;
  615. }
  616. /**
  617. * Search options
  618. * TODO: support for multiple site. aka $_configuration['access_url'] == 1
  619. * @author Marco Villegas <marvil07@gmail.com>
  620. */
  621. function handleSearch()
  622. {
  623. global $SettingsStored, $_configuration;
  624. require_once api_get_path(LIBRARY_PATH).'specific_fields_manager.lib.php';
  625. $search_enabled = api_get_setting('search.search_enabled');
  626. $form = new FormValidator('search-options', 'post', api_get_self().'?category=Search');
  627. $values = api_get_settings_options('search_enabled');
  628. $form->addElement('header', null, get_lang('SearchEnabledTitle'));
  629. $group = formGenerateElementsGroup($form, $values, 'search_enabled');
  630. //SearchEnabledComment
  631. $form->addGroup($group, 'search_enabled', array(get_lang('SearchEnabledTitle'), get_lang('SearchEnabledComment')), null, false);
  632. $search_enabled = api_get_setting('search_enabled');
  633. if ($form->validate()) {
  634. $formValues = $form->exportValues();
  635. setConfigurationSettingsInDatabase($formValues, $_configuration['access_url']);
  636. $search_enabled = $formValues['search_enabled'];
  637. Display::display_confirmation_message($SettingsStored);
  638. }
  639. $specific_fields = get_specific_field_list();
  640. if ($search_enabled == 'true') {
  641. $values = api_get_settings_options('search_show_unlinked_results');
  642. $group = formGenerateElementsGroup($form, $values, 'search_show_unlinked_results');
  643. $form->addGroup($group, 'search_show_unlinked_results', array(get_lang('SearchShowUnlinkedResultsTitle'),get_lang('SearchShowUnlinkedResultsComment')), null, false);
  644. $default_values['search_show_unlinked_results'] = api_get_setting('search_show_unlinked_results');
  645. $sf_values = array();
  646. foreach ($specific_fields as $sf) {
  647. $sf_values[$sf['code']] = $sf['name'];
  648. }
  649. $url = Display::div(Display::url(get_lang('AddSpecificSearchField'), 'specific_fields.php'), array('class'=>'sectioncomment'));
  650. if (empty($sf_values)) {
  651. $form->addElement('label', [get_lang('SearchPrefilterPrefix'), $url]);
  652. } else {
  653. $form->addElement('select', 'search_prefilter_prefix', array(get_lang('SearchPrefilterPrefix'), $url), $sf_values, '');
  654. $default_values['search_prefilter_prefix'] = api_get_setting('search_prefilter_prefix');
  655. }
  656. }
  657. $default_values['search_enabled'] = $search_enabled;
  658. $form->addButtonSave(get_lang('Save'));
  659. $form->setDefaults($default_values);
  660. echo '<div id="search-options-form">';
  661. $form->display();
  662. echo '</div>';
  663. if ($search_enabled == 'true') {
  664. $xapianPath = api_get_path(SYS_UPLOAD_PATH).'plugins/xapian/searchdb';
  665. /*
  666. @todo Test the Xapian connection
  667. if (extension_loaded('xapian')) {
  668. require_once 'xapian.php';
  669. try {
  670. $db = new XapianDatabase($xapianPath.'/');
  671. } catch (Exception $e) {
  672. var_dump($e->getMessage());
  673. }
  674. require_once api_get_path(LIBRARY_PATH) . 'search/ChamiloIndexer.class.php';
  675. require_once api_get_path(LIBRARY_PATH) . 'search/IndexableChunk.class.php';
  676. require_once api_get_path(LIBRARY_PATH) . 'specific_fields_manager.lib.php';
  677. $indexable = new IndexableChunk();
  678. $indexable->addValue("content", 'Test');
  679. $di = new ChamiloIndexer();
  680. $di->connectDb(NULL, NULL, 'english');
  681. $di->addChunk($indexable);
  682. $did = $di->index();
  683. }
  684. */
  685. $xapianLoaded = Display::return_icon('bullet_green.png', get_lang('Ok'));
  686. $dir_exists = Display::return_icon('bullet_green.png', get_lang('Ok'));
  687. $dir_is_writable = Display::return_icon('bullet_green.png', get_lang('Ok'));
  688. $specific_fields_exists = Display::return_icon('bullet_green.png', get_lang('Ok'));
  689. //Testing specific fields
  690. if (empty($specific_fields)) {
  691. $specific_fields_exists = Display::return_icon('bullet_red.png', get_lang('AddSpecificSearchField'));
  692. }
  693. //Testing xapian extension
  694. if (!extension_loaded('xapian')) {
  695. $xapianLoaded = Display::return_icon('bullet_red.png', get_lang('Error'));
  696. }
  697. //Testing xapian searchdb path
  698. if (!is_dir($xapianPath)) {
  699. $dir_exists = Display::return_icon('bullet_red.png', get_lang('Error'));
  700. }
  701. //Testing xapian searchdb path is writable
  702. if (!is_writable($xapianPath)) {
  703. $dir_is_writable = Display::return_icon('bullet_red.png', get_lang('Error'));
  704. }
  705. $data = array();
  706. $data[] = array(get_lang('XapianModuleInstalled'), $xapianLoaded);
  707. $data[] = array(get_lang('DirectoryExists').' - '.$xapianPath, $dir_exists);
  708. $data[] = array(get_lang('IsWritable').' - '.$xapianPath, $dir_is_writable);
  709. $data[] = array(get_lang('SpecificSearchFieldsAvailable') ,$specific_fields_exists);
  710. showSearchSettingsTable($data);
  711. showSearchToolsStatusTable();
  712. }
  713. }
  714. /**
  715. * Wrapper for the templates
  716. *
  717. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University, Belgium
  718. * @author Julio Montoya.
  719. * @version August 2008
  720. * @since v1.8.6
  721. */
  722. function handleTemplates()
  723. {
  724. /* Drive-by fix to avoid undefined var warnings, without repeating
  725. * isset() combos all over the place. */
  726. $action = isset($_GET['action']) ? $_GET['action'] : "invalid";
  727. if ($action != 'add') {
  728. echo '<div class="actions" style="margin-left: 1px;">';
  729. echo '<a href="settings.php?category=Templates&action=add">'.
  730. Display::return_icon('new_template.png', get_lang('AddTemplate'),'',ICON_SIZE_MEDIUM).'</a>';
  731. echo '</div>';
  732. }
  733. if ($action == 'add' || ($action == 'edit' && is_numeric($_GET['id']))) {
  734. addEditTemplate();
  735. // Add event to the system log.
  736. $user_id = api_get_user_id();
  737. $category = $_GET['category'];
  738. Event::addEvent(
  739. LOG_CONFIGURATION_SETTINGS_CHANGE,
  740. LOG_CONFIGURATION_SETTINGS_CATEGORY,
  741. $category,
  742. api_get_utc_datetime(),
  743. $user_id
  744. );
  745. } else {
  746. if ($action == 'delete' && is_numeric($_GET['id'])) {
  747. deleteTemplate($_GET['id']);
  748. // Add event to the system log
  749. $user_id = api_get_user_id();
  750. $category = $_GET['category'];
  751. Event::addEvent(
  752. LOG_CONFIGURATION_SETTINGS_CHANGE,
  753. LOG_CONFIGURATION_SETTINGS_CATEGORY,
  754. $category,
  755. api_get_utc_datetime(),
  756. $user_id
  757. );
  758. }
  759. displayTemplates();
  760. }
  761. }
  762. /**
  763. * Display a sortable table with all the templates that the platform administrator has defined.
  764. *
  765. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University, Belgium
  766. * @version August 2008
  767. * @since v1.8.6
  768. */
  769. function displayTemplates()
  770. {
  771. $table = new SortableTable('templates', 'getNumberOfTemplates', 'getTemplateData', 1);
  772. $table->set_additional_parameters(array('category' => Security::remove_XSS($_GET['category'])));
  773. $table->set_header(0, get_lang('Image'), true, array('style' => 'width: 101px;'));
  774. $table->set_header(1, get_lang('Title'));
  775. $table->set_header(2, get_lang('Actions'), false, array('style' => 'width:50px;'));
  776. $table->set_column_filter(2, 'actionsFilter');
  777. $table->set_column_filter(0, 'searchImageFilter');
  778. $table->display();
  779. }
  780. /**
  781. * Gets the number of templates that are defined by the platform admin.
  782. *
  783. * @return integer
  784. *
  785. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University, Belgium
  786. * @version August 2008
  787. * @since v1.8.6
  788. */
  789. function getNumberOfTemplates()
  790. {
  791. // Database table definition.
  792. $table_system_template = Database :: get_main_table('system_template');
  793. // The sql statement.
  794. $sql = "SELECT COUNT(id) AS total FROM $table_system_template";
  795. $result = Database::query($sql);
  796. $row = Database::fetch_array($result);
  797. // Returning the number of templates.
  798. return $row['total'];
  799. }
  800. /**
  801. * Gets all the template data for the sortable table.
  802. *
  803. * @param integer $from the start of the limit statement
  804. * @param integer $number_of_items the number of elements that have to be retrieved from the database
  805. * @param integer $column the column that is
  806. * @param string $direction the sorting direction (ASC or DESC�
  807. * @return array
  808. *
  809. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University, Belgium
  810. * @version August 2008
  811. * @since v1.8.6
  812. */
  813. function getTemplateData($from, $number_of_items, $column, $direction)
  814. {
  815. // Database table definition.
  816. $table_system_template = Database :: get_main_table('system_template');
  817. // The sql statement.
  818. $sql = "SELECT image as col0, title as col1, id as col2 FROM $table_system_template";
  819. $sql .= " ORDER BY col$column $direction ";
  820. $sql .= " LIMIT $from,$number_of_items";
  821. $result = Database::query($sql);
  822. $return = array();
  823. while ($row = Database::fetch_array($result)) {
  824. $row['1'] = get_lang($row['1']);
  825. $return[] = $row;
  826. }
  827. // Returning all the information for the sortable table.
  828. return $return;
  829. }
  830. /**
  831. * display the edit and delete icons in the sortable table
  832. *
  833. * @param integer $id the id of the template
  834. * @return string code for the link to edit and delete the template
  835. *
  836. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University, Belgium
  837. * @version August 2008
  838. * @since v1.8.6
  839. */
  840. function actionsFilter($id) {
  841. $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>';
  842. $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>';
  843. return $return;
  844. }
  845. /**
  846. * Display the image of the template in the sortable table
  847. *
  848. * @param string $image the image
  849. * @return string code for the image
  850. *
  851. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University, Belgium
  852. * @version August 2008
  853. * @since v1.8.6
  854. */
  855. function searchImageFilter($image)
  856. {
  857. if (!empty($image)) {
  858. return '<img src="'.api_get_path(WEB_APP_PATH).'home/default_platform_document/template_thumb/'.$image.'" alt="'.get_lang('TemplatePreview').'"/>';
  859. } else {
  860. return '<img src="'.api_get_path(WEB_APP_PATH).'home/default_platform_document/template_thumb/noimage.gif" alt="'.get_lang('NoTemplatePreview').'"/>';
  861. }
  862. }
  863. /**
  864. * Add (or edit) a template. This function displays the form and also takes
  865. * care of uploading the image and storing the information in the database
  866. *
  867. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University, Belgium
  868. * @version August 2008
  869. * @since v1.8.6
  870. */
  871. function addEditTemplate()
  872. {
  873. // Initialize the object.
  874. $id = isset($_GET['id']) ? '&id='.Security::remove_XSS($_GET['id']) : '';
  875. $form = new FormValidator('template', 'post', 'settings.php?category=Templates&action='.Security::remove_XSS($_GET['action']).$id);
  876. // Setting the form elements: the header.
  877. if ($_GET['action'] == 'add') {
  878. $title = get_lang('AddTemplate');
  879. } else {
  880. $title = get_lang('EditTemplate');
  881. }
  882. $form->addElement('header', '', $title);
  883. // Setting the form elements: the title of the template.
  884. $form->addText('title', get_lang('Title'), false);
  885. // Setting the form elements: the content of the template (wysiwyg editor).
  886. $form->addHtmlEditor(
  887. 'template_text',
  888. get_lang('Text'),
  889. false,
  890. false,
  891. array(
  892. 'ToolbarSet' => 'AdminTemplates',
  893. 'Width' => '100%',
  894. 'Height' => '400',
  895. )
  896. );
  897. // Setting the form elements: the form to upload an image to be used with the template.
  898. $form->addElement('file','template_image',get_lang('Image'),'');
  899. // Setting the form elements: a little bit information about the template image.
  900. $form->addElement('static', 'file_comment', '', get_lang('TemplateImageComment100x70'));
  901. // Getting all the information of the template when editing a template.
  902. if ($_GET['action'] == 'edit') {
  903. // Database table definition.
  904. $table_system_template = Database :: get_main_table('system_template');
  905. $sql = "SELECT * FROM $table_system_template WHERE id = ".intval($_GET['id'])."";
  906. $result = Database::query($sql);
  907. $row = Database::fetch_array($result);
  908. $defaults['template_id'] = intval($_GET['id']);
  909. $defaults['template_text'] = $row['content'];
  910. // Forcing get_lang().
  911. $defaults['title'] = get_lang($row['title']);
  912. // Adding an extra field: a hidden field with the id of the template we are editing.
  913. $form->addElement('hidden', 'template_id');
  914. // Adding an extra field: a preview of the image that is currently used.
  915. if (!empty($row['image'])) {
  916. $form->addElement('static', 'template_image_preview', '',
  917. '<img src="' . api_get_path(WEB_APP_PATH) . 'home/default_platform_document/template_thumb/' . $row['image'] . '" alt="' . get_lang('TemplatePreview') . '"/>');
  918. } else {
  919. $form->addElement('static', 'template_image_preview', '',
  920. '<img src="' . api_get_path(WEB_APP_PATH) . 'home/default_platform_document/template_thumb/noimage.gif" alt="' . get_lang('NoTemplatePreview') . '"/>');
  921. }
  922. // Setting the information of the template that we are editing.
  923. $form->setDefaults($defaults);
  924. }
  925. // Setting the form elements: the submit button.
  926. $form->addButtonSave(get_lang('Ok'), 'submit');
  927. // Setting the rules: the required fields.
  928. $form->addRule('template_image', get_lang('ThisFieldIsRequired'), 'required');
  929. $form->addRule('title', get_lang('ThisFieldIsRequired'), 'required');
  930. $form->addRule('template_text', get_lang('ThisFieldIsRequired'), 'required');
  931. // if the form validates (complies to all rules) we save the information, else we display the form again (with error message if needed)
  932. if ($form->validate()) {
  933. $check = Security::check_token('post');
  934. if ($check) {
  935. // Exporting the values.
  936. $values = $form->exportValues();
  937. // Upload the file.
  938. if (!empty($_FILES['template_image']['name'])) {
  939. $upload_ok = process_uploaded_file($_FILES['template_image']);
  940. if ($upload_ok) {
  941. // Try to add an extension to the file if it hasn't one.
  942. $new_file_name = add_ext_on_mime(stripslashes($_FILES['template_image']['name']), $_FILES['template_image']['type']);
  943. // The upload directory.
  944. $upload_dir = api_get_path(SYS_APP_PATH).'home/default_platform_document/template_thumb/';
  945. // Create the directory if it does not exist.
  946. if (!is_dir($upload_dir)) {
  947. mkdir($upload_dir, api_get_permissions_for_new_directories());
  948. }
  949. // Resize the preview image to max default and upload.
  950. $temp = new Image($_FILES['template_image']['tmp_name']);
  951. $picture_info = $temp->get_image_info();
  952. $max_width_for_picture = 100;
  953. if ($picture_info['width'] > $max_width_for_picture) {
  954. $temp->resize($max_width_for_picture);
  955. }
  956. $temp->send_image($upload_dir.$new_file_name);
  957. }
  958. }
  959. // Store the information in the database (as insert or as update).
  960. $table_system_template = Database :: get_main_table('system_template');
  961. if ($_GET['action'] == 'add') {
  962. $content_template = Security::remove_XSS($values['template_text'], COURSEMANAGERLOWSECURITY);
  963. $params = [
  964. 'title' => $values['title'],
  965. 'content' => $content_template,
  966. 'image' => $new_file_name
  967. ];
  968. Database::insert($table_system_template, $params);
  969. // Display a feedback message.
  970. Display::display_confirmation_message(get_lang('TemplateAdded'));
  971. echo '<a href="settings.php?category=Templates&action=add">'.Display::return_icon('new_template.png', get_lang('AddTemplate'),'',ICON_SIZE_MEDIUM).'</a>';
  972. } else {
  973. $content_template = '<head>{CSS}<style type="text/css">.text{font-weight: normal;}</style></head><body>'.Database::escape_string($values['template_text']).'</body>';
  974. $sql = "UPDATE $table_system_template set title = '".Database::escape_string($values['title'])."', content = '".$content_template."'";
  975. if (!empty($new_file_name)) {
  976. $sql .= ", image = '".Database::escape_string($new_file_name)."'";
  977. }
  978. $sql .= " WHERE id = ".intval($_GET['id'])."";
  979. Database::query($sql);
  980. // Display a feedback message.
  981. Display::display_confirmation_message(get_lang('TemplateEdited'));
  982. }
  983. }
  984. Security::clear_token();
  985. displayTemplates();
  986. } else {
  987. $token = Security::get_token();
  988. $form->addElement('hidden','sec_token');
  989. $form->setConstants(array('sec_token' => $token));
  990. // Display the form.
  991. $form->display();
  992. }
  993. }
  994. /**
  995. * Delete a template
  996. *
  997. * @param integer $id the id of the template that has to be deleted
  998. *
  999. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University, Belgium
  1000. * @version August 2008
  1001. * @since v1.8.6
  1002. */
  1003. function deleteTemplate($id)
  1004. {
  1005. // First we remove the image.
  1006. $table_system_template = Database :: get_main_table('system_template');
  1007. $sql = "SELECT * FROM $table_system_template WHERE id = ".intval($id)."";
  1008. $result = Database::query($sql);
  1009. $row = Database::fetch_array($result);
  1010. if (!empty($row['image'])) {
  1011. @unlink(api_get_path(SYS_APP_PATH).'home/default_platform_document/template_thumb/'.$row['image']);
  1012. }
  1013. // Now we remove it from the database.
  1014. $sql = "DELETE FROM $table_system_template WHERE id = ".intval($id)."";
  1015. Database::query($sql);
  1016. // Display a feedback message.
  1017. Display::display_confirmation_message(get_lang('TemplateDeleted'));
  1018. }
  1019. /**
  1020. * Returns the list of timezone identifiers used to populate the select
  1021. * This function is called through a call_user_func() in the generate_settings_form function.
  1022. * @return array List of timezone identifiers
  1023. *
  1024. * @author Guillaume Viguier <guillaume.viguier@beeznest.com>
  1025. * @since Chamilo 1.8.7
  1026. */
  1027. function select_timezone_value()
  1028. {
  1029. return api_get_timezones();
  1030. }
  1031. /**
  1032. * Returns an array containing the list of options used to populate the gradebook_number_decimals variable
  1033. * This function is called through a call_user_func() in the generate_settings_form function.
  1034. * @return array List of gradebook_number_decimals options
  1035. *
  1036. * @author Guillaume Viguier <guillaume.viguier@beeznest.com>
  1037. */
  1038. function select_gradebook_number_decimals() {
  1039. return array('0', '1', '2');
  1040. }
  1041. /**
  1042. * Get the options for a select element to select gradebook default grade model
  1043. * @return array
  1044. */
  1045. function select_gradebook_default_grade_model_id()
  1046. {
  1047. $grade_model = new GradeModel();
  1048. $models = $grade_model->get_all();
  1049. $options = array();
  1050. $options[-1] = get_lang('None');
  1051. if (!empty($models)) {
  1052. foreach ($models as $model) {
  1053. $options[$model['id']] = $model['name'];
  1054. }
  1055. }
  1056. return $options;
  1057. }
  1058. /**
  1059. * @param array $settings
  1060. * @param array $settings_by_access_list
  1061. *
  1062. * @return FormValidator
  1063. *
  1064. * @throws \Doctrine\ORM\ORMException
  1065. * @throws \Doctrine\ORM\OptimisticLockException
  1066. * @throws \Doctrine\ORM\TransactionRequiredException
  1067. */
  1068. function generateSettingsForm($settings, $settings_by_access_list)
  1069. {
  1070. global $_configuration, $settings_to_avoid, $convert_byte_to_mega_list;
  1071. $em = Database::getManager();
  1072. $table_settings_current = Database :: get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
  1073. $form = new FormValidator('settings', 'post', 'settings.php?category='.Security::remove_XSS($_GET['category']));
  1074. $form->addElement(
  1075. 'hidden',
  1076. 'search_field',
  1077. (!empty($_GET['search_field']) ? Security::remove_XSS($_GET['search_field']) : null)
  1078. );
  1079. $url_id = api_get_current_access_url_id();
  1080. /*
  1081. if (!empty($_configuration['multiple_access_urls']) && api_is_global_platform_admin() && $url_id == 1) {
  1082. $group = array();
  1083. $group[] = $form->createElement('button', 'mark_all', get_lang('MarkAll'));
  1084. $group[] = $form->createElement('button', 'unmark_all', get_lang('UnmarkAll'));
  1085. $form->addGroup($group, 'buttons_in_action_right');
  1086. }*/
  1087. $default_values = array();
  1088. $url_info = api_get_access_url($url_id);
  1089. $i = 0;
  1090. $addedSettings = [];
  1091. foreach ($settings as $row) {
  1092. if (in_array($row['variable'], array_keys($settings_to_avoid))) {
  1093. continue;
  1094. }
  1095. if (in_array($row['variable'], $addedSettings)) {
  1096. continue;
  1097. }
  1098. $addedSettings[] = $row['variable'];
  1099. if (!empty($_configuration['multiple_access_urls'])) {
  1100. if (api_is_global_platform_admin()) {
  1101. if ($row['access_url_locked'] == 0) {
  1102. if ($url_id == 1) {
  1103. if ($row['access_url_changeable'] == '1') {
  1104. $form->addElement(
  1105. 'html',
  1106. '<div class="pull-right"><a class="share_this_setting" data_status = "0" data_to_send = "'.$row['variable'].'" href="javascript:void(0);">'.
  1107. Display::return_icon('shared_setting.png', get_lang('ChangeSharedSetting') , null, ICON_SIZE_MEDIUM).'</a></div>'
  1108. );
  1109. } else {
  1110. $form->addElement(
  1111. 'html',
  1112. '<div class="pull-right"><a class="share_this_setting" data_status = "1" data_to_send = "'.$row['variable'].'" href="javascript:void(0);">'.
  1113. Display::return_icon('shared_setting_na.png', get_lang('ChangeSharedSetting'), null, ICON_SIZE_MEDIUM ).'</a></div>'
  1114. );
  1115. }
  1116. } else {
  1117. if ($row['access_url_changeable'] == '1') {
  1118. $form->addElement(
  1119. 'html',
  1120. '<div class="pull-right">'.
  1121. Display::return_icon('shared_setting.png', get_lang('ChangeSharedSetting'), null, ICON_SIZE_MEDIUM ).'</div>'
  1122. );
  1123. } else {
  1124. $form->addElement(
  1125. 'html',
  1126. '<div class="pull-right">'.
  1127. Display::return_icon('shared_setting_na.png', get_lang('ChangeSharedSetting'), null, ICON_SIZE_MEDIUM ).'</div>'
  1128. );
  1129. }
  1130. }
  1131. }
  1132. }
  1133. }
  1134. $hideme = array();
  1135. $hide_element = false;
  1136. if ($_configuration['access_url'] != 1) {
  1137. if ($row['access_url_changeable'] == 0) {
  1138. // We hide the element in other cases (checkbox, radiobutton) we 'freeze' the element.
  1139. $hide_element = true;
  1140. $hideme = array('disabled');
  1141. } elseif ($url_info['active'] == 1) {
  1142. // We show the elements.
  1143. if (empty($row['variable'])) {
  1144. $row['variable'] = 0;
  1145. }
  1146. if (empty($row['subkey'])) {
  1147. $row['subkey'] = 0;
  1148. }
  1149. if (empty($row['category'])) {
  1150. $row['category'] = 0;
  1151. }
  1152. if (isset($settings_by_access_list[$row['variable']]) &&
  1153. is_array($settings_by_access_list[$row['variable']][$row['subkey']][$row['category']])) {
  1154. if ($settings_by_access_list[$row['variable']][$row['subkey']][$row['category']]['selected_value'] != '') {
  1155. $row['selected_value'] = $settings_by_access_list[$row['variable']] [$row['subkey']] [$row['category']]['selected_value'];
  1156. }
  1157. }
  1158. // There is no else{} statement because we load the default $row['selected_value'] of the main Chamilo site.
  1159. }
  1160. }
  1161. switch ($row['type']) {
  1162. case 'textfield':
  1163. if (in_array($row['variable'], $convert_byte_to_mega_list)) {
  1164. $form->addElement(
  1165. 'text',
  1166. $row['variable'],
  1167. array(
  1168. get_lang($row['title']),
  1169. get_lang($row['comment']),
  1170. get_lang('MB')
  1171. ),
  1172. array('maxlength' => '8')
  1173. );
  1174. $form->applyFilter($row['variable'], 'html_filter');
  1175. $default_values[$row['variable']] = round($row['selected_value']/1024/1024, 1);
  1176. } elseif ($row['variable'] == 'account_valid_duration') {
  1177. $form->addElement(
  1178. 'text',
  1179. $row['variable'],
  1180. array(
  1181. get_lang($row['title']),
  1182. get_lang($row['comment']),
  1183. ),
  1184. array('maxlength' => '5')
  1185. );
  1186. $form->applyFilter($row['variable'], 'html_filter');
  1187. $default_values[$row['variable']] = $row['selected_value'];
  1188. // For platform character set selection: Conversion of the textfield to a select box with valid values.
  1189. } elseif ($row['variable'] == 'platform_charset') {
  1190. continue;
  1191. } else {
  1192. $hideme['class'] = 'col-md-4';
  1193. $form->addElement(
  1194. 'text',
  1195. $row['variable'],
  1196. array(
  1197. get_lang($row['title']),
  1198. get_lang($row['comment'])
  1199. ),
  1200. $hideme
  1201. );
  1202. $form->applyFilter($row['variable'],'html_filter');
  1203. $default_values[$row['variable']] = $row['selected_value'];
  1204. }
  1205. break;
  1206. case 'textarea':
  1207. if ($row['variable'] == 'header_extra_content') {
  1208. $file = api_get_path(SYS_PATH).api_get_home_path().'header_extra_content.txt';
  1209. $value = '';
  1210. if (file_exists($file)) {
  1211. $value = file_get_contents($file);
  1212. }
  1213. $form->addElement('textarea', $row['variable'], array(get_lang($row['title']), get_lang($row['comment'])) , array('rows'=>'10'), $hideme);
  1214. $default_values[$row['variable']] = $value;
  1215. } elseif ($row['variable'] == 'footer_extra_content') {
  1216. $file = api_get_path(SYS_PATH).api_get_home_path().'footer_extra_content.txt';
  1217. $value = '';
  1218. if (file_exists($file)) {
  1219. $value = file_get_contents($file);
  1220. }
  1221. $form->addElement('textarea', $row['variable'], array(get_lang($row['title']), get_lang($row['comment'])) , array('rows'=>'10'), $hideme);
  1222. $default_values[$row['variable']] = $value;
  1223. } else {
  1224. $form->addElement('textarea', $row['variable'], array(get_lang($row['title']), get_lang($row['comment'])) , array('rows'=>'10'), $hideme);
  1225. $default_values[$row['variable']] = $row['selected_value'];
  1226. }
  1227. break;
  1228. case 'radio':
  1229. $values = api_get_settings_options($row['variable']);
  1230. $group = array ();
  1231. if (is_array($values)) {
  1232. foreach ($values as $key => $value) {
  1233. $element = &$form->createElement(
  1234. 'radio',
  1235. $row['variable'],
  1236. '',
  1237. get_lang($value['display_text']),
  1238. $value['value']
  1239. );
  1240. if ($hide_element) {
  1241. $element->freeze();
  1242. }
  1243. $group[] = $element;
  1244. }
  1245. }
  1246. $form->addGroup(
  1247. $group,
  1248. $row['variable'],
  1249. array(get_lang($row['title']), get_lang($row['comment'])),
  1250. null,
  1251. false
  1252. );
  1253. $default_values[$row['variable']] = $row['selected_value'];
  1254. break;
  1255. case 'checkbox':
  1256. // 1. We collect all the options of this variable.
  1257. $sql = "SELECT * FROM $table_settings_current
  1258. WHERE variable='".$row['variable']."' AND access_url = 1";
  1259. $result = Database::query($sql);
  1260. $group = array ();
  1261. while ($rowkeys = Database::fetch_array($result)) {
  1262. // Profile tab option should be hidden when the social tool is enabled.
  1263. if (api_get_setting('social.allow_social_tool') == 'true') {
  1264. if ($rowkeys['variable'] == 'show_tabs' && $rowkeys['subkey'] == 'my_profile') {
  1265. continue;
  1266. }
  1267. }
  1268. // Hiding the gradebook option.
  1269. if ($rowkeys['variable'] == 'show_tabs' && $rowkeys['subkey'] == 'my_gradebook') {
  1270. continue;
  1271. }
  1272. $element = &$form->createElement(
  1273. 'checkbox',
  1274. $rowkeys['subkey'],
  1275. '',
  1276. get_lang($rowkeys['subkeytext'])
  1277. );
  1278. if ($row['access_url_changeable'] == 1) {
  1279. // 2. We look into the DB if there is a setting for a specific access_url.
  1280. $access_url = $_configuration['access_url'];
  1281. if (empty($access_url)) {
  1282. $access_url = 1;
  1283. }
  1284. $sql = "SELECT selected_value FROM $table_settings_current
  1285. WHERE
  1286. variable='".$rowkeys['variable']."' AND
  1287. subkey='".$rowkeys['subkey']."' AND
  1288. subkeytext='".$rowkeys['subkeytext']."' AND
  1289. access_url = $access_url";
  1290. $result_access = Database::query($sql);
  1291. $row_access = Database::fetch_array($result_access);
  1292. if ($row_access['selected_value'] === 'true' && !$form->isSubmitted()) {
  1293. $element->setChecked(true);
  1294. }
  1295. } else {
  1296. if ($rowkeys['selected_value'] === 'true' && !$form->isSubmitted()) {
  1297. $element->setChecked(true);
  1298. }
  1299. }
  1300. if ($hide_element) {
  1301. $element->freeze();
  1302. }
  1303. $group[] = $element;
  1304. }
  1305. $form->addGroup(
  1306. $group,
  1307. $row['variable'],
  1308. array(get_lang($row['title']), get_lang($row['comment'])),
  1309. null
  1310. );
  1311. break;
  1312. case 'link':
  1313. $form->addElement('static', null, array(get_lang($row['title']), get_lang($row['comment'])),
  1314. get_lang('CurrentValue') . ' : ' . $row['selected_value'], $hideme);
  1315. break;
  1316. case 'select':
  1317. /*
  1318. * To populate the list of options, the select type dynamically calls a function that must be called select_ + the name of the variable being displayed.
  1319. * The functions being called must be added to the file settings.lib.php.
  1320. */
  1321. $form->addElement(
  1322. 'select',
  1323. $row['variable'],
  1324. array(get_lang($row['title']), get_lang($row['comment'])),
  1325. call_user_func('select_'.$row['variable']),
  1326. $hideme
  1327. );
  1328. $default_values[$row['variable']] = $row['selected_value'];
  1329. break;
  1330. case 'custom':
  1331. break;
  1332. case 'select_course':
  1333. $courseSelectOptions = [];
  1334. if (!empty($row['selected_value'])) {
  1335. $course = $em->find('ChamiloCoreBundle:Course', $row['selected_value']);
  1336. $courseSelectOptions[$course->getId()] = $course->getTitle();
  1337. }
  1338. $form->addElement(
  1339. 'select_ajax',
  1340. $row['variable'],
  1341. [get_lang($row['title']), get_lang($row['comment'])],
  1342. $courseSelectOptions,
  1343. ['url' => api_get_path(WEB_AJAX_PATH) . 'course.ajax.php?a=search_course']
  1344. );
  1345. $default_values[$row['variable']] = $row['selected_value'];
  1346. break;
  1347. }
  1348. switch ($row['variable']) {
  1349. case 'pdf_export_watermark_enable':
  1350. $url = PDF::get_watermark(null);
  1351. if ($url != false) {
  1352. $delete_url = '<a href="?delete_watermark">'.get_lang('DelImage').' '.Display::return_icon('delete.png',get_lang('DelImage')).'</a>';
  1353. $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>');
  1354. }
  1355. $form->addElement('file', 'pdf_export_watermark_path', get_lang('AddWaterMark'));
  1356. $allowed_picture_types = array('jpg', 'jpeg', 'png', 'gif');
  1357. $form->addRule('pdf_export_watermark_path', get_lang('OnlyImagesAllowed').' ('.implode(',', $allowed_picture_types).')', 'filetype', $allowed_picture_types);
  1358. break;
  1359. case 'timezone_value':
  1360. $timezone = $row['selected_value'];
  1361. if (empty($timezone)) {
  1362. $timezone = api_get_timezone();
  1363. }
  1364. $form->addLabel('', sprintf(get_lang('LocalTimeUsingPortalTimezoneXIsY'), $timezone, api_get_local_time()));
  1365. break;
  1366. }
  1367. } // end for
  1368. if (!empty($settings)) {
  1369. $form->setDefaults($default_values);
  1370. }
  1371. $form->addHtml('<div class="bottom_actions">');
  1372. $form->addButtonSave(get_lang('SaveSettings'));
  1373. $form->addHtml('</div>');
  1374. return $form;
  1375. }
  1376. /**
  1377. * Searches a platform setting in all categories except from the Plugins category
  1378. * @param string $search
  1379. * @return array
  1380. */
  1381. function searchSetting($search)
  1382. {
  1383. if (empty($search)) {
  1384. return array();
  1385. }
  1386. $table_settings_current = Database :: get_main_table(TABLE_MAIN_SETTINGS_CURRENT);
  1387. $sql = "SELECT * FROM $table_settings_current
  1388. WHERE category <> 'Plugins' ORDER BY id ASC ";
  1389. $result = Database::store_result(Database::query($sql), 'ASSOC');
  1390. $settings = array();
  1391. $search = api_strtolower($search);
  1392. if (!empty($result)) {
  1393. foreach ($result as $setting) {
  1394. $found = false;
  1395. $title = api_strtolower(get_lang($setting['title']));
  1396. // try the title
  1397. if (strpos($title, $search) === false) {
  1398. $comment = api_strtolower(get_lang($setting['comment']));
  1399. //Try the comment
  1400. if (strpos($comment, $search) === false) {
  1401. //Try the variable name
  1402. if (strpos($setting['variable'], $search) === false) {
  1403. continue;
  1404. } else {
  1405. $found = true;
  1406. }
  1407. } else {
  1408. $found = true;
  1409. }
  1410. } else {
  1411. $found = true;
  1412. }
  1413. if ($found) {
  1414. $settings[] = $setting;
  1415. }
  1416. }
  1417. }
  1418. return $settings;
  1419. }
  1420. /**
  1421. * Helper function to generates a form elements group
  1422. * @param object $form The form where the elements group has to be added
  1423. * @param array $values Values to browse through
  1424. * @return array
  1425. */
  1426. function formGenerateElementsGroup($form, $values = array(), $elementName)
  1427. {
  1428. $group = array();
  1429. if (is_array($values)) {
  1430. foreach ($values as $key => $value) {
  1431. $element = &$form->createElement('radio', $elementName, '', get_lang($value['display_text']), $value['value']);
  1432. $group[] = $element;
  1433. }
  1434. }
  1435. return $group;
  1436. }
  1437. /**
  1438. * Helper function with allowed file types for CSS
  1439. * @return array Array of file types (no indexes)
  1440. */
  1441. function getAllowedFileTypes()
  1442. {
  1443. $allowedFiles = array(
  1444. 'css',
  1445. 'zip',
  1446. 'jpeg',
  1447. 'jpg',
  1448. 'png',
  1449. 'gif',
  1450. 'ico',
  1451. 'psd',
  1452. 'xcf',
  1453. 'svg',
  1454. 'webp',
  1455. 'woff',
  1456. 'woff2'
  1457. );
  1458. return $allowedFiles;
  1459. }
  1460. /**
  1461. * Helper function to set settings in the database
  1462. * @param array $parameters List of values
  1463. * @param int $accessUrl The current access URL
  1464. * @return void
  1465. */
  1466. function setConfigurationSettingsInDatabase($parameters, $accessUrl)
  1467. {
  1468. $r = api_set_settings_category('Search', 'false', $accessUrl);
  1469. // Save the settings.
  1470. foreach ($parameters as $key => $value) {
  1471. $result = api_set_setting($key, $value, null, null);
  1472. }
  1473. }
  1474. /**
  1475. * Helper function to show the status of the search settings table
  1476. * @param array $data Data to show
  1477. * @return void
  1478. */
  1479. function showSearchSettingsTable($data)
  1480. {
  1481. echo Display::tag('h3', get_lang('Settings'));
  1482. $table = new SortableTableFromArray($data);
  1483. $table->set_header(0, get_lang('Setting'), false);
  1484. $table->set_header(1, get_lang('Status'), false);
  1485. echo $table->display();
  1486. }
  1487. /**
  1488. * Helper function to show status table for each command line tool installed
  1489. * @return void
  1490. */
  1491. function showSearchToolsStatusTable()
  1492. {
  1493. //@todo windows support
  1494. if (api_is_windows_os() == false) {
  1495. $list_of_programs = array('pdftotext', 'ps2pdf', 'catdoc', 'html2text', 'unrtf', 'catppt', 'xls2csv');
  1496. foreach($list_of_programs as $program) {
  1497. $output = [];
  1498. $ret_val = null;
  1499. exec("which $program", $output, $ret_val);
  1500. if (!$output) {
  1501. $output[] = '';
  1502. }
  1503. $icon = Display::return_icon('bullet_red.png', get_lang('NotInstalled'));
  1504. if (!empty($output[0])) {
  1505. $icon = Display::return_icon('bullet_green.png', get_lang('Installed'));
  1506. }
  1507. $data2[]= array($program, $output[0], $icon);
  1508. }
  1509. echo Display::tag('h3', get_lang('ProgramsNeededToConvertFiles'));
  1510. $table = new SortableTableFromArray($data2);
  1511. $table->set_header(0, get_lang('Program'), false);
  1512. $table->set_header(1, get_lang('Path'), false);
  1513. $table->set_header(2, get_lang('Status'), false);
  1514. echo $table->display();
  1515. } else {
  1516. Display::display_warning_message(
  1517. get_lang('YouAreUsingChamiloInAWindowsPlatformSadlyYouCantConvertDocumentsInOrderToSearchTheContentUsingThisTool')
  1518. );
  1519. }
  1520. }
  1521. /**
  1522. * Helper function to generate and show CSS Zip download message
  1523. * @param string $style Style path
  1524. * @return void
  1525. */
  1526. function generateCSSDownloadLink($style)
  1527. {
  1528. $arch = api_get_path(SYS_ARCHIVE_PATH).$style.'.zip';
  1529. $dir = api_get_path(SYS_CSS_PATH).'themes/'.$style;
  1530. if (is_dir($dir)) {
  1531. $zip = new PclZip($arch);
  1532. // Remove path prefix except the style name and put file on disk
  1533. $zip->create($dir, PCLZIP_OPT_REMOVE_PATH, substr($dir,0,-strlen($style)));
  1534. //@TODO: use more generic script to download.
  1535. $str = '<a class="btn btn-primary btn-large" href="' . api_get_path(WEB_CODE_PATH) . 'course_info/download.php?archive=' . str_replace(api_get_path(SYS_ARCHIVE_PATH), '', $arch) . '">'.get_lang('ClickHereToDownloadTheFile').'</a>';
  1536. Display::display_normal_message($str, false);
  1537. } else {
  1538. Display::addFlash(Display::return_message(get_lang('FileNotFound'), 'warning'));
  1539. }
  1540. }
  1541. /**
  1542. * Helper function to tell if the style is changeable in the current URL
  1543. * @return bool $changeable Whether the style can be changed in this URL or not
  1544. */
  1545. function isStyleChangeable() {
  1546. global $_configuration;
  1547. $changeable = false;
  1548. if ($_configuration['access_url'] != 1) {
  1549. $style_info = api_get_settings('stylesheets', '', 1, 0);
  1550. $url_info = api_get_access_url($_configuration['access_url']);
  1551. if ($style_info[0]['access_url_changeable'] == 1 && $url_info['active'] == 1) {
  1552. $changeable = true;
  1553. }
  1554. } else {
  1555. $changeable = true;
  1556. }
  1557. return $changeable;
  1558. }