summaryrefslogtreecommitdiff
path: root/code/admin
diff options
context:
space:
mode:
Diffstat (limited to 'code/admin')
-rw-r--r--code/admin/add.php55
-rw-r--r--code/admin/admin.css15
-rw-r--r--code/admin/admin.js123
-rw-r--r--code/admin/ajax.php63
-rw-r--r--code/admin/auth.php53
-rw-r--r--code/admin/editor-bind-code.html71
-rw-r--r--code/admin/index.php111
-rw-r--r--code/admin/render.php59
-rw-r--r--code/admin/utils.php179
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;
+ }
+