diff options
Diffstat (limited to 'code/admin')
-rw-r--r-- | code/admin/add.php | 55 | ||||
-rw-r--r-- | code/admin/admin.css | 15 | ||||
-rw-r--r-- | code/admin/admin.js | 123 | ||||
-rw-r--r-- | code/admin/ajax.php | 63 | ||||
-rw-r--r-- | code/admin/auth.php | 53 | ||||
-rw-r--r-- | code/admin/editor-bind-code.html | 71 | ||||
-rw-r--r-- | code/admin/index.php | 111 | ||||
-rw-r--r-- | code/admin/render.php | 59 | ||||
-rw-r--r-- | code/admin/utils.php | 179 |
9 files changed, 729 insertions, 0 deletions
diff --git a/code/admin/add.php b/code/admin/add.php new file mode 100644 index 0000000..c839e0a --- /dev/null +++ b/code/admin/add.php @@ -0,0 +1,55 @@ +<?php + require_once('utils.php'); + need_auth(); + + // Config loading + $site_conf = load_ini_site_conf("content/site_conf.ini"); + if ( ! is_array($site_conf) ) trigger_error("Error parsing site_conf.ini", E_USER_ERROR); + + // Localization Init + l10n_init($site_conf['site_admin_lang']); + + $kind=sanitize($_GET, 'kind', '/[^a-z_]+/', 'page'); /* Could be : page, media */ +?> +<!DOCTYPE html> +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<link rel="stylesheet" href="treeview.css"> +<link rel="stylesheet" href="admin.css"> +<script type="text/javascript" src="admin.js"></script> +<title><?=($kind=='media')?_('Add media'):_('Add page')?></title> +</head> +<body> +<form> + +<fieldset> +<legend><?=($kind=='media')?_('Media tree'):_('Page tree')?></legend> +<div class="css-treeview"> +<?php + if ($kind=='media') { + $tree=find_all('../media', 'media'); + } else { + $tree=find_all('./content', 'page'); + } + php_array_to_tree($tree, 'select_fold'); +?> +</div> +</fieldset> + +<fieldset> +<legend><?=($kind=='media')?_('Media folder'):_('Page folder')?></legend> +<label for="fold_path"><?=_('Folder path')?></label> +<input id="fold_path" name="fold_path" readonly="readonly" value="<?=_('(choose a folder in the tree)')?>"><br> + +<label for="fold_add_name"><?=_('New item name')?></label> +<input id="fold_add_name" type="text" value=""> + +<label for="fold_add_fold"><?=_('Actions')?></label> +<input id="fold_add_fold" type="button" value="<?=_('Add folder')?>" onclick="go_add('<?=$kind?>','fold');"> +<input id="fold_add_item" type="button" value="<?=_('Add page')?>" onclick="go_add('<?=$kind?>','item');"> +</fieldset> + +</form> +</body> +</html> diff --git a/code/admin/admin.css b/code/admin/admin.css new file mode 100644 index 0000000..f01a35d --- /dev/null +++ b/code/admin/admin.css @@ -0,0 +1,15 @@ +fieldset { + display:inline-block; + vertical-align: top; + margin: 0.5em; + width:45%; +} +fieldset>label { + display:inline-block; + text-align:right; + width: 12em; +} +.tree_add { + display:block; + float:right; +} diff --git a/code/admin/admin.js b/code/admin/admin.js new file mode 100644 index 0000000..3d0125d --- /dev/null +++ b/code/admin/admin.js @@ -0,0 +1,123 @@ +// Helpers +function gEBId(id) { return document.getElementById(id) }; + +function microAjaxJSON(query,callback) { + microAjax(query,function (res) { + var parsed_json; + try { + parsed_json = JSON.parse(res); + } catch(err) { + alert(res); + return; + } + callback(parsed_json); + }); +} + +// Admin simple actions +function select_fold(path) { + gEBId("fold_path").value=path; +} + +// Admin AJAX actions +function load_page_props(path) { + gEBId("page_path").value=path; + var url = "ajax.php?action=load_page_props&path=" + encodeURIComponent(path); + microAjaxJSON(url, function (parsed_json) { + gEBId("page_title").value = parsed_json.page_title; + gEBId("page_description").value = parsed_json.page_description; + gEBId("page_keywords").value = parsed_json.page_keywords; + }); +} + +function load_media_props(path) { + gEBId("media_path").value=path; + var url = "ajax.php?action=load_media_props&path=" + encodeURIComponent(path); + microAjaxJSON(url, function (parsed_json) { + gEBId("media_title").value = parsed_json.media_title; + gEBId("media_description").value = parsed_json.media_description; + //gEBId("media_keywords").value = parsed_json.media_keywords; + }); +} + +function save_page_props() { + var path = gEBId("page_path").value; + var page_title = gEBId("page_title").value; + var page_description = gEBId("page_description").value; + var page_keywords = gEBId("page_keywords").value; + + //TODO : check against regex + + var url = "ajax.php?action=save_page_props" + + "&path=" + encodeURIComponent(path) + + "&page_title=" + encodeURIComponent(page_title) + + "&page_description=" + encodeURIComponent(page_description) + + "&page_keywords=" + encodeURIComponent(page_keywords); + + microAjaxJSON(url, function (parsed_json) { + if ( parsed_json.result != "OK" ) { + alert("Error\nResult: " + parsed_json.result + "\nRequest: " + url); + return; + } + //TODO : says to user that the work is done + }); +} + +function save_media_props() { + var path = gEBId("media_path").value; + var title = gEBId("media_title").value; + var description = gEBId("media_description").value; + //var keywords = gEBId("media_keywords").value; + + //TODO : check against regex + + var url = "ajax.php?action=save_media_props" + + "&path=" + encodeURIComponent(path) + + "&title=" + encodeURIComponent(title) + + "&description=" + encodeURIComponent(description); + // + "&keywords=" + encodeURIComponent(keywords); + + microAjaxJSON(url, function (parsed_json) { + if ( parsed_json.result != "OK" ) { + alert("Error\nResult: " + parsed_json.result + "\nRequest: " + url); + return; + } + //TODO : says to user that the work is done + }); +} + +function save_site_props() { + //TODO +} + +// Admin other actions (with page change or refresh) +function go_add_form(kind) { + document.location = 'add.php?kind=' + encodeURIComponent(kind); +} + +function go_add(kind,type) { + var path = gEBId("fold_path").value; + var name = gEBId("fold_add_name").value; + // TODO : check name and path against regex + var url = 'add.php?kind=' + encodeURIComponent(kind) + + '&action=add_' + encodeURIComponent(type) + + '&path=' + encodeURIComponent(path) + + '&name=' + encodeURIComponent(name); + document.location = url; +} + +function go_edit_page() { + var path = gEBId("page_path").value; + document.location = 'render.php?action=edit&page=' + encodeURIComponent(path); +} + +function go_delete_page() { + var path = gEBId("page_path").value; + //TODO : confirmation, ajax query, if OK, confirm then refresh +} + +function go_delete_media() { + var path = gEBId("page_path").value; + //TODO : confirmation, ajax query, if OK, confirm then refresh +} + diff --git a/code/admin/ajax.php b/code/admin/ajax.php new file mode 100644 index 0000000..0893843 --- /dev/null +++ b/code/admin/ajax.php @@ -0,0 +1,63 @@ +<?php + require_once('utils.php'); + need_auth(); + + function load_page_props($path) { + return load_ini_page_props($path); + } + + function load_media_props($path) { + return array( + 'media_title' => 'test title', + 'media_description' => 'test descr', + 'media_keywords' => 'test, keyword', + ); + } + + function save_page_props($path) { + //TODO : Should validate props here also... + $props=load_page_props($path); + + foreach ( array('page_title', 'page_description', 'page_keywords') as $k ) { + if ( array_key_exists($k,$_GET) ) $props[$k]=$_GET[$k]; + } + + $ini_path="content/$path/props.ini"; + return write_ini_file($props, $ini_path, false); + } + + function save_media_props($path) { + return FALSE; + } + + // URL params clean-up + $action=sanitize($_GET, 'action', '/[^a-z_]+/', 'none'); /* Could be : load_page_props, load_media_props... */ + $path=sanitize($_GET, 'path', '/[^a-z0-9\/]+/', ''); // Never put \. in this regex + + switch($action) { + case 'load_page_props': + $res = load_page_props($path); + break; + case 'load_media_props': + $res = load_media_props($path); + break; + case 'save_page_props': + if ( save_page_props($path) ) { + $res=array('result' => 'OK'); + } else { + $res=array('result' => 'FAILED'); + } + break; + case 'save_media_props': + if ( save_media_props($path) ) { + $res=array('result' => 'OK'); + } else { + $res=array('result' => 'FAILED'); + } + break; + default: + $res = array('result' => 'ERROR', 'error'=>'invalid action'); + break; + } + echo json_encode($res); +?> diff --git a/code/admin/auth.php b/code/admin/auth.php new file mode 100644 index 0000000..f4afee0 --- /dev/null +++ b/code/admin/auth.php @@ -0,0 +1,53 @@ +<?php + // Edit secrets here + $configured_user = 'admin'; + $configured_pass = 'admin'; + + // Auth validation + $auth_fail=FALSE; + if ( array_key_exists('u', $_POST) && array_key_exists('p', $_POST) ) { + if ( $_POST['u'] === $configured_user && $_POST['p'] === $configured_pass ) { + // Auth success + session_start(); + $_SESSION['auth_user'] = TRUE; + // Auto-redirect to previous page + if ( array_key_exists('auth_return', $_SESSION) && (strlen($_SESSION['auth_return']) > 0) ) { + header('Location: ' . $_SESSION['auth_return']); + } + echo "Authenticated\n"; + exit(); + } else { + $auth_fail=TRUE; + } + } +?> +<!DOCTYPE html> +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<title>Authentification</title> +</head> +<body> +<form method="post"> + <fieldset style="float:left"> + <legend>Authentification</legend> + <table> + <tr> + <td><label>User</label></td> + <td><input type="text" name="u" value="admin"></td> + </tr> + <tr> + <td><label>Pass</label></td> + <td><input type="password" name="p" value="admin"></td> + </tr> + <tr> + <td colspan="2" align="right"> + <span><?php if ($auth_fail) echo "Login failed";?></span> + <input type="submit" value="Login"> + </td> + </tr> + </table> + </fieldset> +</form> +</body> +</html> diff --git a/code/admin/editor-bind-code.html b/code/admin/editor-bind-code.html new file mode 100644 index 0000000..d6a9825 --- /dev/null +++ b/code/admin/editor-bind-code.html @@ -0,0 +1,71 @@ +<!-- Editor deffered loading --> +<link href="http://cdn.aloha-editor.org/latest/css/aloha.css" type="text/css" rel="stylesheet"> +<script type="text/javascript" src="http://cdn.aloha-editor.org/latest/lib/vendor/jquery-1.7.1.js"></script> +<script type="text/javascript" src="http://cdn.aloha-editor.org/latest/lib/require.js"></script> +<script> + var Aloha = window.Aloha || ( window.Aloha = {} ); + + Aloha.settings = { + locale: 'fr', + plugins: { + format: { + config : [ 'b', 'i','sub','sup'], + editables : { + // no formatting allowed for title + '#title' : [ ], + // formatting for all editable DIVs + 'div' : [ 'b', 'i', 'del', 'sub', 'sup' ], + // content is a DIV and has class .article so it gets both buttons + '.article' : [ 'b', 'i', 'p', 'title', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'pre', 'removeFormat'] + } + }, + list: { + // all elements with no specific configuration get an UL, just for fun :) + config : [ 'ul' ], + editables : { + // Even if this is configured it is not set because OL and UL are not allowed in H1. + '#title' : [ 'ol' ], + // all divs get OL + 'div' : [ 'ol' ], + // content is a DIV. It would get only OL but with class .article it also gets UL. + '.article' : [ 'ul' ] + } + }, + link: { + config : [ 'a' ], + editables : { + // No links in the title. + '#title' : [ ] + } + } + }, + sidebar: { + disabled: false + } + }; +</script> + +<script type="text/javascript" src="http://cdn.aloha-editor.org/latest/lib/aloha.js" + data-aloha-plugins="common/ui, + common/format, + common/table, + common/list, + common/link, + common/highlighteditables, + common/block, + common/undo, + common/image, + common/contenthandler, + common/paste, + common/commands, + common/abbr"></script> + +<script type="text/javascript"> +Aloha.ready(function() { + // mark the editable parts + $('#title').aloha(); + $('#teaser').aloha(); + $('#content').aloha(); +}); + +</script> diff --git a/code/admin/index.php b/code/admin/index.php new file mode 100644 index 0000000..ddb95b3 --- /dev/null +++ b/code/admin/index.php @@ -0,0 +1,111 @@ +<?php + require_once('utils.php'); + need_auth(); + + // Config loading + $site_conf = load_ini_site_conf("content/site_conf.ini"); + if ( ! is_array($site_conf) ) trigger_error("Error parsing site_conf.ini", E_USER_ERROR); + + // Localization Init + l10n_init($site_conf['site_admin_lang']); +?> +<!DOCTYPE html> +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<link rel="stylesheet" href="treeview.css"> +<link rel="stylesheet" href="admin.css"> +<script type="text/javascript" src="microajax.minified.js"></script> +<script type="text/javascript" src="admin.js"></script> +<title><?=_('Admin')?></title> +</head> +<body> +<form> + +<fieldset> +<legend><?=_('Page tree')?></legend> +<input id="page_add" class="tree_add" type="button" value="<?=_('Add page')?>" onclick="go_add_form('page');"> +<div class="css-treeview"> +<?php + $page_tree=find_all('./content', 'page'); + //echo '<pre>' . print_r($page_tree,true) . '</pre>' . "\n"; + php_array_to_tree($page_tree, '', 'load_page_props', '', 'pagedir-0'); +?> +</div> +</fieldset> + +<fieldset> +<legend><?=_('Selected page')?></legend> +<label for="page_path"><?=_('Page path')?></label> +<input id="page_path" name="page_path" readonly="readonly" value="<?=_('(choose a page in the tree)')?>"><br> + +<label for="page_edit"><?=_('Actions')?></label> +<input id="page_edit" type="button" value="<?=_('Edit page')?>" onclick="go_edit_page();"> +<input id="page_delete" type="button" value="<?=_('Delete page')?>" onclick="go_delete_page();"> + +<br><br> + +<label for="page_title"><?=_('Page title')?></label> +<input id="page_title" name="page_title" value=""><br> + +<label for="page_description"><?=_('Page description')?></label> +<input id="page_description" name="page_description" value=""><br> + +<label for="page_keywords"><?=_('Page keywords')?></label> +<input id="page_keywords" name="page_keywords" value=""><br> + +<label for="page_submit"></label> +<input id="page_submit" type="button" value="<?=_('Save properties')?>" onclick="save_page_props();"><br> +</fieldset> + +<fieldset> +<legend><?=_('Media tree')?></legend> +<input id="media_add" class="tree_add" type="button" value="<?=_('Add media')?>" onclick="go_add_form('media');"> +<div class="css-treeview"> +<?php + $media_tree=find_all('../media', 'media'); + //echo '<pre>' . print_r($media_tree,true) . '</pre>' . "\n"; + php_array_to_tree($media_tree, '', 'load_media_props', '', 'mediadir-0'); +?> +</div> +</fieldset> + +<fieldset> +<legend><?=_('Selected Media')?></legend> +<label for="media_path"><?=_('Media path')?></label> +<input id="media_path" name="media_path" readonly="readonly" value="<?=_('(choose a media in the tree)')?>"><br> + +<label for="media_edit"><?=_('Actions')?></label> +<!--<input id="media_edit" type="button" value="Edit media">--> +<input id="media_delete" type="button" value="<?=_('Delete media')?>" onclick="go_delete_media();"> + +<br><br> + +<label for="media_title"><?=_('Media title')?></label> +<input id="media_title" name="media_title" value=""><br> + +<label for="media_description"><?=_('Media description')?></label> +<input id="media_description" name="media_description" value=""><br> +<!-- +<label for="media_keywords">Media keywords</label> +<input id="media_keywords" name="media_keywords" value=""><br> +--> +<label for="media_submit"></label> +<input id="media_submit" type="button" value="<?=_('Save properties')?>" onclick="save_media_props();"><br> +</fieldset> + +<fieldset> +<legend><?=_('Site properties')?></legend> +<label for="site_admin_lang"><?=_('Admin lang')?></label> +<input id="site_admin_lang" name="site_admin_lang" value="<?=$site_conf['site_admin_lang']?>"><br> + +<label for="site_default_page"><?=_('Default page')?></label> +<input id="site_default_page" name="site_default_page" value="<?=$site_conf['site_default_page']?>"><br> + +<label for="site_submit"></label> +<input id="site_submit" type="button" value="<?=_('Save properties')?>" onclick="save_site_props();"><br> +</fieldset> + +</form> +</body> +</html> diff --git a/code/admin/render.php b/code/admin/render.php new file mode 100644 index 0000000..9d4175e --- /dev/null +++ b/code/admin/render.php @@ -0,0 +1,59 @@ +<?php + require_once('utils.php'); + need_auth(); + + // Config loading + $site_conf = load_ini_site_conf("content/site_conf.ini"); + if ( ! is_array($site_conf) ) trigger_error("Error parsing site_conf.ini", E_USER_ERROR); + + // URL params clean-up + $action=sanitize($_GET, 'action', '/[^a-z_]+/', 'preview'); /* Could be : preview, edit, publish */ + $page=sanitize($_GET, 'page', '/[^a-z0-9\/]+/', $site_conf['site_default_page']); // Never put \. in this regex + + // Template vars init ($page, $page_path, $page_props, $page_tpl_url) + $page_path = "content/$page"; + if ( ! is_dir($page_path) ) trigger_error("Error : page does not exists ($page)", E_USER_ERROR); + $page_props = load_ini_page_props($page); + if ( ! is_array($page_props) ) trigger_error("Error parsing page properties ($page/props.ini)", E_USER_ERROR); + $page_tpl_url = str_repeat('../', substr_count($page, '/')) . "admin/templates/" . $page_props['page_template'] . '/'; + + if ($action === 'publish') ob_start(); /* Buffering for redirecting to file instead of browser */ + + // Basic HTML5 skeleton + page props insertion + template call +?> +<!DOCTYPE html> +<html> +<head> +<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> +<title><?=$page_props['page_title']?></title> +<meta name="description" content="<?=$page_props['page_description']?>"> +<meta name="keywords" content="<?=$page_props['page_keywords']?>"> +<link rel="stylesheet" href="<?="$page_tpl_url" /*FIXME*/?>screen.css"> +</head> +<body> +<?php + require("templates/" . $page_props['page_template'] . '/layout-' . $page_props['page_layout'] . '.php'); + if ( $action === 'edit') require('editor-bind-code.html'); +?> +</body> +</html> +<?php + // If publishing, write resulting HTML page on a .html file + if ($action === 'publish') { + $out=ob_get_contents(); + ob_end_clean(); + $dest="../$page.html"; + $destfold=dirname($dest); + if ( ! is_dir($destfold) ) { + if ( ! mkdir($destfold,0777,true) ) { + trigger_error("Error : Can't create '$destfold'", E_USER_ERROR); + } + } + $size=file_put_contents($dest, $out); + if ( $size === FALSE ) { + trigger_error("Error : Can't write " . strlen($out) . " bytes to '$dest'", E_USER_ERROR); + } else { + echo json_encode(array('result'=>'ok', 'size' => $size)); + } + } +?> diff --git a/code/admin/utils.php b/code/admin/utils.php new file mode 100644 index 0000000..f02146a --- /dev/null +++ b/code/admin/utils.php @@ -0,0 +1,179 @@ +<?php + function sanitize($arg_array, $arg_key, $replace_chars_re, $default_value) { + //FIXME : should check string type and strlen ! + if ( ! array_key_exists($arg_key, $arg_array) ) return $default_value; + return preg_replace($replace_chars_re, '_', $arg_array[$arg_key]); + } + + function sanitize_ini($ini_path, $array_entry_props) { + $array_ini = parse_ini_file($ini_path); + if ( is_array($array_ini) ) { + // Sanitize any existing ini entries. Destroy unwanted ones. + foreach ( $array_ini as $k => $v ) { + if ( array_key_exists($k, $array_entry_props) + && array_key_exists('replace_chars_re', $array_entry_props[$k]) + && array_key_exists('default_value', $array_entry_props[$k]) + ) { + $array_ini[$k] = sanitize($array_ini, $k, + $array_entry_props[$k]['replace_chars_re'], + $array_entry_props[$k]['default_value'] ); + } else { + unset($array_ini[$k]); + } + } + // Set default value for all missing ini entries (if default value exists) + foreach ( $array_entry_props as $k => $v ) { + if ( !array_key_exists($k, $array_ini) && array_key_exists('default_value', $array_entry_props[$k]) ) { + $array_ini[$k] = $array_entry_props[$k]['default_value']; + } + } + } + return $array_ini; + } + + function load_ini_site_conf($ini_path) { + $sanitize_site_conf = array( + 'site_admin_lang' => array( 'replace_chars_re' => '/[^a-zA-Z\/\_-]+/', 'default_value' => 'C' ), + 'site_default_page' => array( 'replace_chars_re' => '/[^a-z0-9\/]+/', 'default_value' => 'en/index' ), + ); + return sanitize_ini($ini_path, $sanitize_site_conf); + } + + function load_ini_page_props($page) { + $sanitize_page_props = array( + //FIXME : title regex : all but html special chars ? + 'page_title' => array( 'replace_chars_re' => '/[^\w !_,.-]+/', 'default_value' => '(missing title in props.ini)' ), + 'page_template' => array( 'replace_chars_re' => '/[^a-z0-9]+/', 'default_value' => 'default' ), + 'page_layout' => array( 'replace_chars_re' => '/[^a-z0-9]+/', 'default_value' => 'article' ), + 'page_description' => array( 'replace_chars_re' => '/[^\w !_,.-]+/', 'default_value' => '(missing description in props.ini)' ), + 'page_keywords' => array( 'replace_chars_re' => '/[^\w !_,.-]+/', 'default_value' => '(missing keywords in props.ini)' ), + ); + $ini_path="content/$page/props.ini"; + return sanitize_ini($ini_path, $sanitize_page_props); + } + + function l10n_init($lang) { + setlocale(LC_MESSAGES, "$lang.utf8"); + $base = bindtextdomain('editablesite', './locale'); + $domain = textdomain('editablesite'); + bind_textdomain_codeset('editablesite', 'UTF-8'); + //echo "<pre>l10n file is '$base/$lang.utf8/LC_MESSAGES/$domain.mo'</pre>\n"; + } + + function need_auth() { + session_start(); + if ( ! array_key_exists('auth_user', $_SESSION) || $_SESSION['auth_user'] !== TRUE ) { + $_SESSION['auth_return'] = $_SERVER['REQUEST_URI']; + header('Location: auth.php'); + exit(); + } + } + + function is_ress($kind, $path) { + switch ($kind) { + case 'page': return is_file($path.'/props.ini'); + case 'media': return substr($path, -4)=='.jpg' && is_file($path); + default : return FALSE; + } + } + + function strcmp_tree($a,$b) { + if (is_array($a) || is_array($b) ) return 0; + return strnatcasecmp($a,$b); + } + + function find_all($path, $kind) { + $result=array(); + if ( $handle = opendir($path) ) { + while (FALSE !== ($entry = readdir($handle))) { + if ( array_search($entry, array('.','..')) !== FALSE ) continue; + $childpath=$path.'/'.$entry; + if ( is_ress($kind, $childpath) ) $result[] = $entry; + else if ( is_dir($childpath) ) $result[$entry]=find_all($childpath,$kind); + } + closedir($handle); + } + uasort($result, 'strcmp_tree'); + return $result; + } + + function php_array_to_tree($page_tree, $node_cb, $leaf_cb='', $path='', $itemid="item-0") { + if ( ! is_array($page_tree) ) return; + echo "<ul>\n"; + foreach ($page_tree as $k => $v) { + if ( is_numeric($k) ) { + // Leaf + if ( strlen($leaf_cb) > 0 ) { + echo '<li><a href="javascript:' . $leaf_cb . "('$path$v');" . '">' . $v . '</a></li>' . "\n"; + } else { + echo "<li>$v</li>\n"; + } + } else { + // Node + // Increment $itemid last component + // "1-1-2-1" will come "1-1-2-2" + $tmp = explode('-', $itemid); + array_push($tmp, array_pop($tmp) + 1); + $itemid = implode('-', $tmp); + $tmp=null; + /// Write the node + echo "<li>\n"; + echo '<input type="checkbox" checked="checked" id="' . $itemid . '">' . "\n"; + echo '<label for="' . $itemid . '">'; + if ( strlen($node_cb) > 0 ) { + echo '<a href="javascript:' . $node_cb . "('$path$k');" . '">' . $k . '</a>'; + } else { + echo $k; + } + echo "</label>\n"; + // Recursively build the tree below the node + php_array_to_tree($v, $node_cb, $leaf_cb, $path.$k.'/', $itemid."-0"); + echo "</li>\n"; + } + } + echo "</ul>\n"; + } + + function safe_put_file($path, $content) { + //FIXME : if exists, then mktemp, put in it then rm and mv. Right preservation problems ? + if ($handle = fopen($path, 'w')) { + $res = fwrite($handle, $content); + fclose($handle); + } + } + + function _write_ini_file_r(&$content, $assoc_arr, $has_sections) + { + foreach ($assoc_arr as $key => $val) { + if (is_array($val)) { + if($has_sections) { + $content .= "[$key]\n"; + _write_ini_file_r($content, $val, false); + } else { + foreach($val as $iKey => $iVal) { + if (is_int($iKey)) + $content .= $key ."[] = $iVal\n"; + else + $content .= $key ."[$iKey] = $iVal\n"; + } + } + } else { + if ( preg_match('/^\w+$/',$val)===1 ) + $content .= "$key = $val\n"; + else + $content .= "$key = \"" . str_replace('"', '\"', $val) . "\"\n"; + } + } + } + + function write_ini_file($assoc_arr, $path, $has_sections) { + $res=FALSE; + $content = ''; + _write_ini_file_r($content, $assoc_arr, $has_sections); + if (is_string($content) && strlen($content) > 0) { + safe_put_file($path, $content); + } + + return $res; + } + |