aboutsummaryrefslogtreecommitdiff
path: root/ratatoeskr
diff options
context:
space:
mode:
Diffstat (limited to 'ratatoeskr')
-rw-r--r--ratatoeskr/config.php11
-rw-r--r--ratatoeskr/languages.php189
-rw-r--r--ratatoeskr/setup/create_tables.php139
-rw-r--r--ratatoeskr/sys/db.php103
-rw-r--r--ratatoeskr/sys/default_settings.php10
-rw-r--r--ratatoeskr/sys/models.php2071
-rw-r--r--ratatoeskr/sys/utils.php164
-rw-r--r--ratatoeskr/templates/usertemplates/foo.tpl14
-rw-r--r--ratatoeskr/translations/de.php0
-rw-r--r--ratatoeskr/translations/en.php7
10 files changed, 2704 insertions, 4 deletions
diff --git a/ratatoeskr/config.php b/ratatoeskr/config.php
index 1691b4a..c8c4acb 100644
--- a/ratatoeskr/config.php
+++ b/ratatoeskr/config.php
@@ -1,8 +1,11 @@
<?php
-$conf["mysql"]["db"] = "s_db_47";
-$conf["mysql"]["user"] = "dbuser_47";
-$conf["mysql"]["passwd"] = "DfXVQBoVOBPbLlL";
-$conf["mysql"]["prefix"] = "ratatoeskr_";
+define("__DEBUG__", True);
+define("CONFIG_FILLED_OUT", True);
+
+$config["mysql"]["db"] = "s_db_47";
+$config["mysql"]["user"] = "dbuser_47";
+$config["mysql"]["passwd"] = "DfXVQBoVOBPbLlL";
+$config["mysql"]["prefix"] = "ratatoeskr_";
?>
diff --git a/ratatoeskr/languages.php b/ratatoeskr/languages.php
new file mode 100644
index 0000000..1448911
--- /dev/null
+++ b/ratatoeskr/languages.php
@@ -0,0 +1,189 @@
+<?php
+/* Source: http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes */
+$languages = array(
+ "ab" => array("language" => "аҧсуа", "translation_exist" => False),
+ "aa" => array("language" => "Afaraf", "translation_exist" => False),
+ "af" => array("language" => "Afrikaans", "translation_exist" => False),
+ "ak" => array("language" => "Akan", "translation_exist" => False),
+ "sq" => array("language" => "Shqip", "translation_exist" => False),
+ "am" => array("language" => "አማርኛ", "translation_exist" => False),
+ "ar" => array("language" => "العربية", "translation_exist" => False),
+ "an" => array("language" => "Aragonés", "translation_exist" => False),
+ "hy" => array("language" => "Հայերեն", "translation_exist" => False),
+ "as" => array("language" => "অসমীয়া", "translation_exist" => False),
+ "av" => array("language" => "авар мацӀ, магӀарул мацӀ", "translation_exist" => False),
+ "ae" => array("language" => "avesta", "translation_exist" => False),
+ "ay" => array("language" => "aymar aru", "translation_exist" => False),
+ "az" => array("language" => "azərbaycan dili", "translation_exist" => False),
+ "bm" => array("language" => "bamanankan", "translation_exist" => False),
+ "ba" => array("language" => "башҡорт теле", "translation_exist" => False),
+ "eu" => array("language" => "euskara, euskera", "translation_exist" => False),
+ "be" => array("language" => "Беларуская", "translation_exist" => False),
+ "bn" => array("language" => "বাংলা", "translation_exist" => False),
+ "bh" => array("language" => "भोजपुरी", "translation_exist" => False),
+ "bi" => array("language" => "Bislama", "translation_exist" => False),
+ "bs" => array("language" => "bosanski jezik", "translation_exist" => False),
+ "br" => array("language" => "brezhoneg", "translation_exist" => False),
+ "bg" => array("language" => "български език", "translation_exist" => False),
+ "my" => array("language" => "ဗမာစာ", "translation_exist" => False),
+ "ca" => array("language" => "Català", "translation_exist" => False),
+ "ch" => array("language" => "Chamoru", "translation_exist" => False),
+ "ce" => array("language" => "нохчийн мотт", "translation_exist" => False),
+ "ny" => array("language" => "chiCheŵa, chinyanja", "translation_exist" => False),
+ "zh" => array("language" => "中文, 汉语, 漢語", "translation_exist" => False),
+ "cv" => array("language" => "чӑваш чӗлхи", "translation_exist" => False),
+ "kw" => array("language" => "Kernewek", "translation_exist" => False),
+ "co" => array("language" => "corsu, lingua corsa", "translation_exist" => False),
+ "cr" => array("language" => "ᓀᐦᐃᔭᐍᐏᐣ", "translation_exist" => False),
+ "hr" => array("language" => "hrvatski", "translation_exist" => False),
+ "cs" => array("language" => "česky, čeština", "translation_exist" => False),
+ "da" => array("language" => "dansk", "translation_exist" => False),
+ "dv" => array("language" => "ދިވެހި", "translation_exist" => False),
+ "nl" => array("language" => "Nederlands, Vlaams", "translation_exist" => False),
+ "dz" => array("language" => "རྫོང་ཁ", "translation_exist" => False),
+ "en" => array("language" => "English", "translation_exist" => True),
+ "eo" => array("language" => "Esperanto", "translation_exist" => False),
+ "et" => array("language" => "eesti, eesti keel", "translation_exist" => False),
+ "ee" => array("language" => "Eʋegbe", "translation_exist" => False),
+ "fo" => array("language" => "føroyskt", "translation_exist" => False),
+ "fj" => array("language" => "vosa Vakaviti", "translation_exist" => False),
+ "fi" => array("language" => "suomi, suomen kieli", "translation_exist" => False),
+ "fr" => array("language" => "français, langue française", "translation_exist" => False),
+ "ff" => array("language" => "Fulfulde, Pulaar, Pular", "translation_exist" => False),
+ "gl" => array("language" => "Galego", "translation_exist" => False),
+ "ka" => array("language" => "ქართული", "translation_exist" => False),
+ "de" => array("language" => "Deutsch", "translation_exist" => True),
+ "el" => array("language" => "Ελληνικά", "translation_exist" => False),
+ "gn" => array("language" => "Avañe'ẽ", "translation_exist" => False),
+ "gu" => array("language" => "ગુજરાતી", "translation_exist" => False),
+ "ht" => array("language" => "Kreyòl ayisyen", "translation_exist" => False),
+ "ha" => array("language" => "Hausa, هَوُسَ", "translation_exist" => False),
+ "he" => array("language" => "עברית", "translation_exist" => False),
+ "hz" => array("language" => "Otjiherero", "translation_exist" => False),
+ "hi" => array("language" => "हिन्दी, हिंदी", "translation_exist" => False),
+ "ho" => array("language" => "Hiri Motu", "translation_exist" => False),
+ "hu" => array("language" => "Magyar", "translation_exist" => False),
+ "ia" => array("language" => "Interlingua", "translation_exist" => False),
+ "id" => array("language" => "Bahasa Indonesia", "translation_exist" => False),
+ "ie" => array("language" => "Originally called ", "translation_exist" => False),
+ "ga" => array("language" => "Gaeilge", "translation_exist" => False),
+ "ig" => array("language" => "Asụsụ Igbo", "translation_exist" => False),
+ "ik" => array("language" => "Iñupiaq, Iñupiatun", "translation_exist" => False),
+ "io" => array("language" => "Ido", "translation_exist" => False),
+ "is" => array("language" => "Íslenska", "translation_exist" => False),
+ "it" => array("language" => "Italiano", "translation_exist" => False),
+ "iu" => array("language" => "ᐃᓄᒃᑎᑐᑦ", "translation_exist" => False),
+ "ja" => array("language" => "日本語 (にほんご)", "translation_exist" => False),
+ "jv" => array("language" => "basa Jawa", "translation_exist" => False),
+ "kl" => array("language" => "kalaallisut, kalaallit oqaasii", "translation_exist" => False),
+ "kn" => array("language" => "ಕನ್ನಡ", "translation_exist" => False),
+ "kr" => array("language" => "Kanuri", "translation_exist" => False),
+ "ks" => array("language" => "कश्मीरी, كشميري‎", "translation_exist" => False),
+ "kk" => array("language" => "Қазақ тілі", "translation_exist" => False),
+ "km" => array("language" => "ភាសាខ្មែរ", "translation_exist" => False),
+ "ki" => array("language" => "Gĩkũyũ", "translation_exist" => False),
+ "rw" => array("language" => "Ikinyarwanda", "translation_exist" => False),
+ "ky" => array("language" => "кыргыз тили", "translation_exist" => False),
+ "kv" => array("language" => "коми кыв", "translation_exist" => False),
+ "kg" => array("language" => "KiKongo", "translation_exist" => False),
+ "ko" => array("language" => "한국어 (韓國語), 조선어 (朝鮮語)", "translation_exist" => False),
+ "ku" => array("language" => "Kurdî, كوردی‎", "translation_exist" => False),
+ "kj" => array("language" => "Kuanyama", "translation_exist" => False),
+ "la" => array("language" => "latine, lingua latina", "translation_exist" => False),
+ "lb" => array("language" => "Lëtzebuergesch", "translation_exist" => False),
+ "lg" => array("language" => "Luganda", "translation_exist" => False),
+ "li" => array("language" => "Limburgs", "translation_exist" => False),
+ "ln" => array("language" => "Lingála", "translation_exist" => False),
+ "lo" => array("language" => "ພາສາລາວ", "translation_exist" => False),
+ "lt" => array("language" => "lietuvių kalba", "translation_exist" => False),
+ "lu" => array("language" => "Luba-Katanga", "translation_exist" => False),
+ "lv" => array("language" => "latviešu valoda", "translation_exist" => False),
+ "gv" => array("language" => "Gaelg, Gailck", "translation_exist" => False),
+ "mk" => array("language" => "македонски јазик", "translation_exist" => False),
+ "mg" => array("language" => "Malagasy fiteny", "translation_exist" => False),
+ "ms" => array("language" => "bahasa Melayu, بهاس ملايو‎", "translation_exist" => False),
+ "ml" => array("language" => "മലയാളം", "translation_exist" => False),
+ "mt" => array("language" => "Malti", "translation_exist" => False),
+ "mi" => array("language" => "te reo Māori", "translation_exist" => False),
+ "mr" => array("language" => "मराठी", "translation_exist" => False),
+ "mh" => array("language" => "Kajin M̧ajeļ", "translation_exist" => False),
+ "mn" => array("language" => "монгол", "translation_exist" => False),
+ "na" => array("language" => "Ekakairũ Naoero", "translation_exist" => False),
+ "nv" => array("language" => "Diné bizaad, Dinékʼehǰí", "translation_exist" => False),
+ "nb" => array("language" => "Norsk bokmål", "translation_exist" => False),
+ "nd" => array("language" => "isiNdebele", "translation_exist" => False),
+ "ne" => array("language" => "नेपाली", "translation_exist" => False),
+ "ng" => array("language" => "Owambo", "translation_exist" => False),
+ "nn" => array("language" => "Norsk nynorsk", "translation_exist" => False),
+ "no" => array("language" => "Norsk", "translation_exist" => False),
+ "ii" => array("language" => "ꆈꌠ꒿ Nuosuhxop", "translation_exist" => False),
+ "nr" => array("language" => "isiNdebele", "translation_exist" => False),
+ "oc" => array("language" => "Occitan", "translation_exist" => False),
+ "oj" => array("language" => "ᐊᓂᔑᓈᐯᒧᐎᓐ", "translation_exist" => False),
+ "cu" => array("language" => "ѩзыкъ словѣньскъ", "translation_exist" => False),
+ "om" => array("language" => "Afaan Oromoo", "translation_exist" => False),
+ "or" => array("language" => "ଓଡ଼ିଆ", "translation_exist" => False),
+ "os" => array("language" => "ирон æвзаг", "translation_exist" => False),
+ "pa" => array("language" => "ਪੰਜਾਬੀ, پنجابی‎", "translation_exist" => False),
+ "pi" => array("language" => "पाऴि", "translation_exist" => False),
+ "fa" => array("language" => "فارسی", "translation_exist" => False),
+ "pl" => array("language" => "polski", "translation_exist" => False),
+ "ps" => array("language" => "پښتو", "translation_exist" => False),
+ "pt" => array("language" => "Português", "translation_exist" => False),
+ "qu" => array("language" => "Runa Simi, Kichwa", "translation_exist" => False),
+ "rm" => array("language" => "rumantsch grischun", "translation_exist" => False),
+ "rn" => array("language" => "Ikirundi", "translation_exist" => False),
+ "ro" => array("language" => "română", "translation_exist" => False),
+ "ru" => array("language" => "русский язык", "translation_exist" => False),
+ "sa" => array("language" => "संस्कृतम्", "translation_exist" => False),
+ "sc" => array("language" => "sardu", "translation_exist" => False),
+ "sd" => array("language" => "yângâ tî sängö", "translation_exist" => False),
+ "se" => array("language" => "Davvisámegiella", "translation_exist" => False),
+ "sm" => array("language" => "gagana fa'a Samoa", "translation_exist" => False),
+ "sg" => array("language" => "yângâ tî sängö", "translation_exist" => False),
+ "sr" => array("language" => "српски језик", "translation_exist" => False),
+ "gd" => array("language" => "Gàidhlig", "translation_exist" => False),
+ "sn" => array("language" => "chiShona", "translation_exist" => False),
+ "si" => array("language" => "සිංහල", "translation_exist" => False),
+ "sk" => array("language" => "slovenčina", "translation_exist" => False),
+ "sl" => array("language" => "slovenščina", "translation_exist" => False),
+ "so" => array("language" => "Soomaaliga, af Soomaali", "translation_exist" => False),
+ "st" => array("language" => "Sesotho", "translation_exist" => False),
+ "es" => array("language" => "español, castellano", "translation_exist" => False),
+ "su" => array("language" => "Basa Sunda", "translation_exist" => False),
+ "sw" => array("language" => "Kiswahili", "translation_exist" => False),
+ "ss" => array("language" => "SiSwati", "translation_exist" => False),
+ "sv" => array("language" => "svenska", "translation_exist" => False),
+ "ta" => array("language" => "தமிழ்", "translation_exist" => False),
+ "te" => array("language" => "తెలుగు", "translation_exist" => False),
+ "tg" => array("language" => " тоҷикӣ, toğikī, تاجیکی‎", "translation_exist" => False),
+ "th" => array("language" => "ไทย", "translation_exist" => False),
+ "ti" => array("language" => "ትግርኛ", "translation_exist" => False),
+ "bo" => array("language" => "བོད་ཡིག", "translation_exist" => False),
+ "tk" => array("language" => "Türkmen, Түркмен", "translation_exist" => False),
+ "tl" => array("language" => "Wikang Tagalog", "translation_exist" => False),
+ "tn" => array("language" => "Setswana", "translation_exist" => False),
+ "to" => array("language" => "faka Tonga", "translation_exist" => False),
+ "tr" => array("language" => "Türkçe", "translation_exist" => False),
+ "ts" => array("language" => "Xitsonga", "translation_exist" => False),
+ "tt" => array("language" => "татарча, tatarça, تاتارچا‎", "translation_exist" => False),
+ "tw" => array("language" => "Twi", "translation_exist" => False),
+ "ty" => array("language" => "Reo Tahiti", "translation_exist" => False),
+ "ug" => array("language" => "Uyƣurqə, ئۇيغۇرچە‎", "translation_exist" => False),
+ "uk" => array("language" => "українська", "translation_exist" => False),
+ "ur" => array("language" => "اردو", "translation_exist" => False),
+ "uz" => array("language" => "O'zbek, Ўзбек, أۇزبېك‎", "translation_exist" => False),
+ "ve" => array("language" => "Tshivenḓa", "translation_exist" => False),
+ "vi" => array("language" => "Tiếng Việt", "translation_exist" => False),
+ "vo" => array("language" => "Volapük", "translation_exist" => False),
+ "wa" => array("language" => "Walon", "translation_exist" => False),
+ "cy" => array("language" => "Cymraeg", "translation_exist" => False),
+ "wo" => array("language" => "Wollof", "translation_exist" => False),
+ "fy" => array("language" => "Frysk", "translation_exist" => False),
+ "xh" => array("language" => "isiXhosa", "translation_exist" => False),
+ "yi" => array("language" => "ייִדיש", "translation_exist" => False),
+ "yo" => array("language" => "Yorùbá", "translation_exist" => False),
+ "za" => array("language" => "Saɯ cueŋƅ, Saw cuengh", "translation_exist" => False),
+ "zu" => array("language" => "isiZulu", "translation_exist" => False)
+);
+?>
diff --git a/ratatoeskr/setup/create_tables.php b/ratatoeskr/setup/create_tables.php
new file mode 100644
index 0000000..b024d51
--- /dev/null
+++ b/ratatoeskr/setup/create_tables.php
@@ -0,0 +1,139 @@
+<?php
+
+
+$sql = <<<SQL
+SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
+
+CREATE TABLE `PREFIX_acl` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `acl_json` text COLLATE utf8_unicode_ci NOT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+
+CREATE TABLE `PREFIX_articles` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `urltitle` text COLLATE utf8_unicode_ci NOT NULL,
+ `title` int(11) NOT NULL,
+ `text` int(11) NOT NULL,
+ `excerpt` int(11) NOT NULL,
+ `meta` text COLLATE utf8_unicode_ci NOT NULL,
+ `custom` text COLLATE utf8_unicode_ci NOT NULL,
+ `acl` int(11) NOT NULL,
+ `article_img` int(11) NOT NULL,
+ `status` int(11) NOT NULL,
+ `section` int(11) NOT NULL,
+ `timestamp` bigint(20) NOT NULL,
+ `allow_comments` int(11) NOT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+
+CREATE TABLE `PREFIX_article_tag_relations` (
+ `tag` int(11) NOT NULL,
+ `article` int(11) NOT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+
+CREATE TABLE `PREFIX_comments` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `article` int(11) NOT NULL,
+ `language` varchar(10) COLLATE utf8_unicode_ci NOT NULL,
+ `author_name` text COLLATE utf8_unicode_ci NOT NULL,
+ `author_mail` text COLLATE utf8_unicode_ci NOT NULL,
+ `text` text COLLATE utf8_unicode_ci NOT NULL,
+ `timestamp` bigint(20) NOT NULL,
+ `visible` tinyint(4) NOT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+
+CREATE TABLE `PREFIX_groups` (
+ `int` int(11) NOT NULL AUTO_INCREMENT,
+ `name` text COLLATE utf8_unicode_ci NOT NULL,
+ PRIMARY KEY (`int`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+
+CREATE TABLE `PREFIX_group_memers` (
+ `user` int(11) NOT NULL,
+ `group` int(11) NOT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+
+CREATE TABLE `PREFIX_images` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `name` text COLLATE utf8_unicode_ci NOT NULL,
+ `alt` int(11) NOT NULL,
+ `file` text COLLATE utf8_unicode_ci NOT NULL,
+ `acl` int(11) NOT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+
+CREATE TABLE `PREFIX_multilingual` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ PRIMARY KEY (`id`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+
+CREATE TABLE `PREFIX_plugins` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `name` text COLLATE utf8_unicode_ci NOT NULL,
+ `class` text COLLATE utf8_unicode_ci NOT NULL,
+ `version` text COLLATE utf8_unicode_ci NOT NULL,
+ `author` text COLLATE utf8_unicode_ci NOT NULL,
+ `author_url` text COLLATE utf8_unicode_ci NOT NULL,
+ `description` text COLLATE utf8_unicode_ci NOT NULL,
+ `help` text COLLATE utf8_unicode_ci NOT NULL,
+ `phpcode` text COLLATE utf8_unicode_ci NOT NULL,
+ `active` tinyint(4) NOT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+
+CREATE TABLE `PREFIX_plugin_kvstorage` (
+ `plugin` int(11) NOT NULL,
+ `key` text COLLATE utf8_unicode_ci NOT NULL,
+ `value` text COLLATE utf8_unicode_ci NOT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+
+CREATE TABLE `PREFIX_sections` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `name` text COLLATE utf8_unicode_ci NOT NULL,
+ `title` int(11) NOT NULL,
+ `template` text COLLATE utf8_unicode_ci NOT NULL,
+ `styles` text COLLATE utf8_unicode_ci NOT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+
+CREATE TABLE `PREFIX_settings_kvstorage` (
+ `key` text COLLATE utf8_unicode_ci NOT NULL,
+ `value` text COLLATE utf8_unicode_ci NOT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+
+CREATE TABLE `PREFIX_styles` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `name` text COLLATE utf8_unicode_ci NOT NULL,
+ `code` text COLLATE utf8_unicode_ci NOT NULL,
+ `acl` int(11) NOT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+
+CREATE TABLE `PREFIX_tags` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `name` text COLLATE utf8_unicode_ci NOT NULL,
+ `title` int(11) NOT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+
+CREATE TABLE `PREFIX_translations` (
+ `multilingual` int(11) NOT NULL,
+ `language` varchar(10) COLLATE utf8_unicode_ci NOT NULL,
+ `text` text COLLATE utf8_unicode_ci NOT NULL,
+ `texttype` text COLLATE utf8_unicode_ci NOT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+
+CREATE TABLE `PREFIX_users` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `username` text COLLATE utf8_unicode_ci NOT NULL,
+ `pwhash` text COLLATE utf8_unicode_ci NOT NULL,
+ `mail` text COLLATE utf8_unicode_ci NOT NULL,
+ `fullname` text COLLATE utf8_unicode_ci NOT NULL,
+ `language` varchar(10) COLLATE utf8_unicode_ci NOT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+SQL;
+
+?>
diff --git a/ratatoeskr/sys/db.php b/ratatoeskr/sys/db.php
new file mode 100644
index 0000000..0f3357a
--- /dev/null
+++ b/ratatoeskr/sys/db.php
@@ -0,0 +1,103 @@
+<?php
+/*
+ * File: db.php
+ *
+ * Helper functions for dealing with MySQL.
+ *
+ * This file is part of Ratatöskr.
+ * Ratatöskr is licensed unter the MIT / X11 License.
+ * See "ratatoeskr/licenses/ratatoeskr" for more information.
+ */
+
+require_once(dirname(__FILE__) . "/../config.php");
+require_once(dirname(__FILE__) . "/utils.php");
+
+/*
+ * Function: db_connect
+ *
+ * Establish a connection to the MySQL database.
+ */
+function db_connect()
+{
+ global $config;
+ $db_connection = mysql_pconnect(
+ $config["mysql"]["server"],
+ $config["mysql"]["user"],
+ $config["mysql"]["passwd"]);
+ if(!$db_connection)
+ die("Could not connect to database server. " . mysql_error());
+
+ if(!mysql_select_db($config["mysql"]["db"], $db_connection))
+ die("Could not open database. " . mysql_error());
+
+ mysql_query("SET NAMES 'utf8'", $db_connection);
+}
+
+function sqlesc($str)
+{
+ return mysql_real_escape_string($str);
+}
+
+/*
+ * Class: MySQLException
+ */
+class MySQLException extends Exception { }
+
+/*
+ * Function: qdb_vfmt
+ * Like <qdb_fmt>, but needs arguments as single array.
+ *
+ * Parameters:
+ * $args - The arguments as an array.
+ *
+ * Returns:
+ * The formatted string.
+ */
+function qdb_vfmt($args)
+{
+ global $config;
+
+ if(count($args) < 1)
+ throw new InvalidArgumentException('Need at least one parameter');
+
+ $query = $args[0];
+
+ $data = array_map(function($x) { return is_string($x) ? sqlesc($x) : $x; }, array_slice($args, 1));
+ $query = str_replace("PREFIX_", $config["mysql"]["prefix"], $query);
+
+ return vsprintf($query, $data);
+}
+
+/*
+ * Function: qdb_fmt
+ * Formats a string like <qdb>, that means it replaces "PREFIX_" and <sqlesc>'s everything before sends everything to vsprintf.
+ *
+ * Returns:
+ * The formatted string.
+ */
+function qdb_fmt()
+{
+ return qdb_vfmt(fung_get_args());
+}
+
+/*
+ * Function: qdb
+ * Query Database.
+ *
+ * This function replaces mysql_query and should eliminate SQL-Injections.
+ * Use it like this:
+ *
+ * $result = qdb("SELECT `foo` FROM `bar` WHERE `id` = %d AND `baz` = '%s'", 100, "lol");
+ *
+ * It will also replace "PREFIX_" with the prefix defined in 'config.php'.
+ */
+function qdb()
+{
+ $query = qdb_vfmt(func_get_args());
+ $rv = mysql_query($query);
+ if($rv === false)
+ throw new MySQLException(mysql_errno() . ': ' . mysql_error() . (__DEBUG__ ? ("[[FULL QUERY: " . $query . "]]") : "" ));
+ return $rv;
+}
+
+?>
diff --git a/ratatoeskr/sys/default_settings.php b/ratatoeskr/sys/default_settings.php
new file mode 100644
index 0000000..7b42028
--- /dev/null
+++ b/ratatoeskr/sys/default_settings.php
@@ -0,0 +1,10 @@
+<?php
+
+$default_settings = array(
+ "comment_visible_default" => False,
+ "default_language" => "en",
+ "default_section" => 0/* Must be created */
+ "allow_comments_default" => True
+);
+
+?>
diff --git a/ratatoeskr/sys/models.php b/ratatoeskr/sys/models.php
new file mode 100644
index 0000000..13d5843
--- /dev/null
+++ b/ratatoeskr/sys/models.php
@@ -0,0 +1,2071 @@
+<?php
+/*
+ * File: models.php
+ * Data models to make database accesses more comfortable.
+ *
+ * This file is part of Ratatöskr.
+ * Ratatöskr is licensed unter the MIT / X11 License.
+ * See "ratatoeskr/licenses/ratatoeskr" for more information.
+ */
+
+require_once(dirname(__FILE__) . "/db.php");
+require_once(dirname(__FILE__) . "/utils.php");
+
+db_connect();
+
+/*
+ * Class: DoesNotExistError
+ * This Exception is thrown by an ::by_*-constructor or any array-like object if the desired object is not present in the database.
+ */
+class DoesNotExistError extends Exception { }
+
+/*
+ * Class: AlreadyExistsError
+ * This Exception is thrown by an ::create-constructor if the creation of the object would result in duplicates.
+ */
+class AlreadyExistsError extends Exception { }
+
+/*
+ * Class: NotAllowedError
+ */
+class NotAllowedError extends Exception { }
+
+/*
+ * Class: User
+ * Data model for Users
+ */
+class User
+{
+ private $id;
+
+ /*
+ * Variables: Public class properties
+ *
+ * $username - The username
+ * $pwhash - SHA1-Hash of the password
+ * $mail - E-Mail-address
+ * $fullname - The full name of the user.
+ * $language - Users language
+ */
+ public $username;
+ public $pwhash;
+ public $mail;
+ public $fullname;
+ public $language;
+
+ /* Should not be constructed directly. */
+ private function __construct() { }
+
+ /*
+ * Constructor: create
+ * Creates a new user.
+ *
+ * Parameters:
+ * $username - The username
+ * $pwhash - SHA1-Hash of the password
+ * $mail - E-Mail-address
+ * $fullname - The full name.
+ *
+ * Returns:
+ * An User object
+ */
+ public static function create($username, $pwhash, $mail, $fullname)
+ {
+ try
+ {
+ $obj = self::by_name($name);
+ }
+ catch(DoesNotExistError $e)
+ {
+ global $ratatoeskr_settings;
+ qdb("INSERT INTO `PREFIX_users` (`username`, `pwhash`, `mail`, `username`, `language`) VALUES ('%s', '%s', '%s', '%s', '%s')",
+ $username, $pwhash, $mail, $fullname, $ratatoeskr_settings["default_language"]);
+ $obj = new self;
+
+ $obj->id = mysql_insert_id();
+ $obj->username = $username;
+ $obj->pwhash = $pwhash;
+ $obj->mail = $mail;
+ $obj->fullname = $fullname;
+ $obj->language = $ratatoeskr_settings["default_language"];
+
+ return $obj;
+ }
+ throw new AlreadyExistsError("\"$name\" is already in database.");
+ }
+
+ /* DANGER: $result must be valid! The calling function has to check this! */
+ private function populate_by_sqlresult($result)
+ {
+ $sqlrow = mysql_fetch_assoc($result);
+ if($sqlrow == False)
+ throw new DoesNotExistError();
+
+ $this->id = $sqlrow["id"];
+ $this->username = $sqlrow["username"];
+ $this->pwhash = $sqlrow["pwhash"];
+ $this->mail = $sqlrow["mail"];
+ $this->fullname = $sqlrow["fullname"];
+ $this->language = $sqlrow["language"];
+ }
+
+ /*
+ * Constructor: by_id
+ * Get a User object by ID
+ *
+ * Parameters:
+ * $id - The ID.
+ *
+ * Returns:
+ * An User object.
+ */
+ public static function by_id($id)
+ {
+ $result = qdb("SELECT `id`, `username`, `pwhash`, `mail`, `fullname`, `language` FROM `PREFIX_users` WHERE `id` = %d", $id);
+
+ $obj = new self;
+ $obj->populate_by_sqlresult($result);
+ return $obj;
+ }
+
+ /*
+ * Constructor: by_username
+ * Get a User object by username
+ *
+ * Parameters:
+ * $username - The username.
+ *
+ * Returns:
+ * An User object.
+ */
+ public static function by_name($username)
+ {
+ $result = qdb("SELECT `id`, `username`, `pwhash`, `mail`, `fullname`, `language` FROM `PREFIX_users` WHERE `name` = '%s'", $username);
+
+ $obj = new self;
+ $obj->populate_by_sqlresult($result);
+ return $obj;
+ }
+
+ /*
+ * Function: all_users
+ * Returns array of all available users.
+ */
+ public static function all_users()
+ {
+ $rv = array();
+
+ $result = qdb("SELECT `id` FROM `PREFIX_users` WHERE 1");
+ while($sqlrow = mysql_fetch_assoc($result))
+ $rv[] = self::by_id($sqlrow["id"]);
+
+ return $rv;
+ }
+
+ /*
+ * Function: get_id
+ * Returns:
+ * The user ID.
+ */
+ public function get_id()
+ {
+ return $this->id;
+ }
+
+ /*
+ * Function: save
+ * Saves the object to database
+ */
+ public function save()
+ {
+ qdb("UPDATE `PREFIX_users` SET `username` = '%s', `pwhash` = '%s', `mail` = '%s', `fullname` = '%s', `language` = '%s' WHERE `id` = %d",
+ $this->username, $this->pwhash, $this->mail, $this->id, $this->fullname, $this->language);
+ }
+
+ /*
+ * Function: delete
+ * Deletes the user from the database.
+ * WARNING: Do NOT use this object any longer after you called this function!
+ */
+ public function delete()
+ {
+ qdb("DELETE FROM `PREFIX_group_members` WHERE `user` = %d", $this->id);
+ qdb("DELETE FROM `PREFIX_users` WHERE `id` = %d", $this->id);
+ }
+
+ /*
+ * Function: get_groups
+ * Returns:
+ * List of all groups where this user is a member (array of <Group> objects).
+ */
+ public function get_groups()
+ {
+ $rv = array();
+ $result = qdb("SELECT `group` FROM `PREFIX_group_members` WHERE `user` = %d", $this->id);
+ while($sqlrow = mysql_fetch_assoc($result))
+ {
+ try
+ {
+ $rv[] = Group::by_id($sqlrow["group"]);
+ }
+ catch(DoesNotExistError $e)
+ {
+ /* WTF?!? This should be fixed! */
+ qdb("DELETE FROM `PREFIX_group_members` WHERE `user` = %d AND `group` = %d", $this->id, $sqlrow["group"]);
+ }
+ }
+ return $rv;
+ }
+
+ /*
+ * Function: member_of
+ * Checks, if the user is a member of a group.
+ *
+ * Parameters:
+ * $group - A Group object
+ *
+ * Returns:
+ * True, if the user is a member of $group. False, if not.
+ */
+ public function member_of($group)
+ {
+ $result = qdb("SELECT COUNT(*) AS `num` FROM `PREFIX_group_members` WHERE `user` = %d AND `group` = %d", $this->id, $group->get_id());
+ $sqlrow = mysql_fetch_assoc($result);
+ return ($sqlrow["num"] > 0);
+ }
+}
+
+/*
+ * Class: Group
+ * Data model for groups
+ */
+class Group
+{
+ private $id;
+
+ /*
+ * Variables: Public class properties
+ *
+ * $name - Name of the group.
+ */
+ public $name;
+
+ /* Should not be constructed directly. */
+ private function __construct() { }
+
+ /*
+ * Constructor: create
+ * Creates a new group.
+ *
+ * Parameters:
+ * $name - The name of the group.
+ *
+ * Returns:
+ * An Group object
+ */
+ public static function create($name)
+ {
+ try
+ {
+ $obj = self::by_username($name);
+ }
+ catch(DoesNotExistError $e)
+ {
+ qdb("INSERT INTO `PREFIX_groups` (`name`) VALUES ('%s')", $name);
+ $obj = new self;
+
+ $obj->id = mysql_insert_id();
+ $obj->name = $name;
+
+ return $obj;
+ }
+ throw new AlreadyExistsError("\"$name\" is already in database.");
+ }
+
+ /* DANGER: $result must be valid! The calling function has to check this! */
+ private function populate_by_sqlresult($result)
+ {
+ $sqlrow = mysql_fetch_assoc($result);
+ if($sqlrow == False)
+ throw new DoesNotExistError();
+
+ $this->id = $sqlrow["id"];
+ $this->name = $sqlrow["name"];
+ }
+
+ /*
+ * Constructor: by_id
+ * Get a Group object by ID
+ *
+ * Parameters:
+ * $id - The ID.
+ *
+ * Returns:
+ * A Group object.
+ */
+ public static function by_id($id)
+ {
+ $result = qdb("SELECT `id`, `name` FROM `PREFIX_groups` WHERE `id` = %d", $id);
+
+ $obj = new self;
+ $obj->populate_by_sqlresult($result);
+ return $obj;
+ }
+
+ /*
+ * Constructor: by_name
+ * Get a Group object by name
+ *
+ * Parameters:
+ * $name - The group name.
+ *
+ * Returns:
+ * A Group object.
+ */
+ public static function by_name($name)
+ {
+ $result = qdb("SELECT `id`, `name` FROM `PREFIX_groups` WHERE `name` = '%s'", $name);
+
+ $obj = new self;
+ $obj->populate_by_sqlresult($result);
+ return $obj;
+ }
+
+ /*
+ * Function: all_groups
+ * Returns array of all groups
+ */
+ public static function all_groups()
+ {
+ $rv = array();
+
+ $result = qdb("SELECT `id` FROM `PREFIX_groups` WHERE 1");
+ while($sqlrow = mysql_fetch_assoc($result))
+ $rv[] = self::by_id($sqlrow["id"]);
+
+ return $rv;
+ }
+
+ /*
+ * Function: get_id
+ * Returns:
+ * The group ID.
+ */
+ public function get_id()
+ {
+ return $this->id;
+ }
+
+ /*
+ * Function: delete
+ * Deletes the group from the database.
+ * WARNING: Do NOT use this object any longer after you called this function!
+ */
+ public function delete()
+ {
+ qdb("DELETE FROM `PREFIX_group_members` WHERE `group` = %d", $this->id);
+ qdb("DELETE FROM `PREFIX_groups` WHERE `id` = %d", $this->id);
+ }
+
+ /*
+ * Function: get_members
+ * Get all members of the group.
+ *
+ * Returns:
+ * Array of <User> objects.
+ */
+ public function get_members()
+ {
+ $rv = array();
+ $result = qdb("SELECT `user` FROM `PREFIX_group_members` WHERE `group` = %d", $this->id);
+ while($sqlrow = mysql_fetch_assoc($result))
+ {
+ try
+ {
+ $rv[] = User::by_id($sqlrow["user"]);
+ }
+ catch(DoesNotExistError $e)
+ {
+ /* WTF?!? This should be fixed!*/
+ qdb("DELETE FROM `PREFIX_group_members` WHERE `user` = %d AND `group` = %d", $sqlrow["user"], $this->id);
+ }
+ }
+ return $rv;
+ }
+
+ /*
+ * Function: exclude_user
+ * Excludes user from group.
+ *
+ * Parameters:
+ * $user - <User> object.
+ */
+ public function exclude_user($user)
+ {
+ qdb("DELETE FROM `PREFIX_group_members` WHERE `user` = %d AND `group` = %d", $user->get_id(), $this->id);
+ }
+
+ /*
+ * Function: include_user
+ * Includes user to group.
+ *
+ * Parameters:
+ * $user - <User> object.
+ */
+ public function include_user($user)
+ {
+ if(!$user->member_of($this))
+ qdb("INSERT INTO `PREFIX_group_members` (`user`, `group`) VALUES (%d, %d)", $user->get_id(), $this->id);
+ }
+}
+
+/*
+ * Class: ACL
+ * Data model for AccessControlLists
+ */
+class ACL
+{
+ private $id;
+
+ /*
+ * Variables: Public class properties. *_rights are arrays, which can have this elements: "read", "write", "delete".
+ *
+ * $users - Array of <User> objects
+ * $user_rights - User rights
+ * $groups - Array of <Group> objects
+ * $group_rights - Group rights
+ * $others_rights - The rights of everyone
+ */
+ public $users;
+ public $user_rights;
+ public $groups;
+ public $group_rights;
+ public $others_rights;
+
+ /* Should not be constructed directly. */
+ private function __construct()
+ {
+ $this->users = array();
+ $this->user_rights = array();
+ $this->groups = array();
+ $this->group_rights = array();
+ $this->others_rights = array();
+ }
+
+ /*
+ * Function: get_id
+ * Returns:
+ * The ACL ID.
+ */
+ public function get_id()
+ {
+ return $this->id;
+ }
+
+ private static function filter_invalid_rights($rights)
+ {
+ return array_filter($rights, function($x) { return in_array($x, array("read", "write", "delete")); });
+ }
+
+ /*
+ * Constructor: by_json
+ * Creates an ACL object from an JSON string.
+ *
+ * Parameters:
+ * json - The JSON string
+ *
+ * Returns:
+ * An ACL object
+ */
+ public static function by_json($json)
+ {
+ $obj = new self;
+ $obj->id = 0;
+
+ $pre = json_decode($json, True);
+ if($pre === NULL)
+ return $obj;
+
+ $obj->users = array_filter(
+ array_map(
+ function($x){ try{ return User::by_id($x); } catch(DoesNotExistError $e) { return NULL; } },
+ $pre["users"]),
+ function($x) { return $x!==NULL; });
+ $obj->groups = array_filter(
+ array_map(
+ function($x){ try{ return Group::by_id($x); } catch(DoesNotExistError $e) { return NULL; } },
+ $pre["groups"]),
+ function($x) { return $x!==NULL; });
+ $obj->user_rights = self::filter_invalid_rights($pre["rights"]["users"]);
+ $obj->group_rights = self::filter_invalid_rights($pre["rights"]["groups"]);
+ $obj->others_rights = self::filter_invalid_rights($pre["rights"]["others"]);
+
+ return $obj;
+ }
+
+ /*
+ * Constructor: create
+ * Creates a new ACL object.
+ *
+ * Params:
+ * $in_db - Should this ACL be stored in the database? (Defaults to True)
+ *
+ * Returns:
+ * ACL object.
+ */
+ public static function create($in_db = True)
+ {
+ $obj = new self;
+
+ if($in_db)
+ {
+ qdb("INSERT INTO `PREFIX_acl` (`acl_json`) VALUES ('%s')", $obj->to_json());
+ $obj->id = mysql_insert_id();
+ }
+
+ return $obj;
+ }
+
+ /*
+ * Constructor: by_id
+ * Gets ACL object by id.
+ *
+ * Parameters:
+ * $id - The ID.
+ *
+ * Returns:
+ * An ACL object.
+ */
+ public static function by_id($id)
+ {
+ $result = qdb("SELECT `acl_json` FROM `PREFIX_acl` WHERE `id` = %d", $id);
+
+ $sqlrow = mysql_fetch_assoc($result);
+ if($sqlrow == False)
+ throw new DoesNotExistError("ACL with ID = \"$id\" does not exist.");
+ $obj = self::by_json($sqlrow["acl_json"]);
+ $obj->id = $id;
+
+ return $obj;
+ }
+
+ /*
+ * Function: to_json
+ * Genearets JSON string
+ *
+ * Returns:
+ * JSON string.
+ */
+ public function to_json()
+ {
+ return json_encode(array(
+ "users" => array_map(function($x) { return $x->get_id(); }, $this->users),
+ "groups" => array_map(function($x) { return $x->get_id(); }, $this->groups),
+ "rights" => array(
+ "users" => self::filter_invalid_rights($this->user_rights),
+ "groups" => self::filter_invalid_rights($this->group_rights),
+ "others" => self::filter_invalid_rights($this->others_rights)
+ )
+ ));
+ }
+
+ /*
+ * Function: save
+ * If ACL comes from database, save it. Do nothing otherwise.
+ */
+ public function save()
+ {
+ if($this->id > 0)
+ qdb("UPDATE `PREFIX_acl` SET `acl_json` = '%s'", $this->to_json);
+ }
+
+ /*
+ * Function: delete
+ * If ACL comes from database, delete it. Do nothing otherwise.
+ */
+ public function delete()
+ {
+ if($this->id > 0)
+ {
+ qdb("DELETE FROM `PREFIX_acl` WHERE `id` = %d", $this->id);
+ $this->id = 0;
+ }
+ }
+
+ /*
+ * Function: user_rights
+ * Get the rights of $user.
+ *
+ * Parameters:
+ * $user - A <User> object.
+ *
+ * Returns:
+ * An Array of rights.
+ */
+ public function user_rights($user)
+ {
+ $get_id_func = function($x) { return $x->get_id(); };
+ $rights = $this->others_rights;
+ if(in_array($user->get_id(), array_map($get_id_func, $this->users)))
+ $rights = array_merge($rights, $this->user_rights);
+ $temp = array_intersect(array_map($get_id_func, $user->get_groups()), $this->groups);
+ if(!empty($temp))
+ $rights = array_merge($rights, $this->group_rights);
+ return self::filter_invalid_rights(array_unique($rights));
+ }
+}
+
+/*
+ * Class: Translation
+ * A translation. Can only be stored using an <Multilingual> object.
+ */
+class Translation
+{
+ /*
+ * Varialbes: Public class variables.
+ *
+ * $text - The translated text.
+ * $texttype - The type of the text. Has only a meaning in a context.
+ */
+ public $text;
+ public $texttype;
+
+ /*
+ * Constructor: __construct
+ * Creates a new Translation object.
+ * IT WILL NOT BE STORED TO DATABASE!
+ *
+ * Parameters:
+ * $text - The translated text.
+ * $texttype - The type of the text. Has only a meaning in a context.
+ *
+ * See also:
+ * <Multilingual>
+ */
+ public function __construct($text, $texttype)
+ {
+ $this->text = $text;
+ $this->texttype = $texttype;
+ }
+}
+
+/*
+ * Class: Multilingual
+ * Container for <Translation> objects.
+ * Translations can be accessed array-like. So, if you want the german translation: $translation = $my_multilingual["de"];
+ *
+ * See also:
+ * <languages.php>
+ */
+class Multilingual implements Countable, ArrayAccess, IteratorAggregate
+{
+ private $translations;
+ private $id;
+ private $to_be_deleted;
+ private $to_be_created;
+
+ private function __construct()
+ {
+ $this->translations = array();
+ $this->to_be_deleted = array();
+ $this->to_be_created = array();
+ }
+
+ /*
+ * Function: get_id
+ * Retuurns the ID of the object.
+ */
+ public function get_id()
+ {
+ return $this->id;
+ }
+
+ /*
+ * Constructor: create
+ * Creates a new Multilingual object
+ *
+ * Returns:
+ * An Multilingual object.
+ */
+ public static function create()
+ {
+ $obj = new self;
+ qdb("INSERT INTO `PREFIX_multilingual` () VALUES ()");
+ $obj->id = mysql_insert_id();
+ return $obj;
+ }
+
+ /*
+ * Constructor: by_id
+ * Gets an Multilingual object by ID.
+ *
+ * Parameters:
+ * $id - The ID.
+ *
+ * Returns:
+ * An Multilingual object.
+ */
+ public static function by_id($id)
+ {
+ $obj = new self;
+ $result = qdb("SELECT `id` FROM `PREFIX_multilingual` WHERE `id` = %d", $id);
+ $sqlrow = mysql_fetch_assoc($result);
+ if($sqlrow == False)
+ throw new DoesNotExistError();
+ $obj->id = $id;
+
+ $result = qdb("SELECT `language`, `text`, `texttype` FROM `PREFIX_translations` WHERE `multilingual` = %d", $id);
+ while($sqlrow = mysql_fetch_assoc($result))
+ $obj->translations[$sqlrow["language"]] = new Translation($sqlrow["text"], $sqlrow["texttype"]);
+
+ return $obj;
+ }
+
+ /*
+ * Function: save
+ * Saves the translations to database.
+ */
+ public function save()
+ {
+ foreach($this->to_be_deleted as $deletelang)
+ qdb("DELETE FROM `PREFIX_translations` WHERE `multilingual` = %d AND `language` = '%s'", $this->id, $deletelang);
+ $this->to_be_deleted = array();
+
+ foreach($this->to_be_created as $lang)
+ qdb("INSERT INTO `PREFIX_translations` (`multilingual`, `language`, `text`, `texttype`) VALUES (%d, '%s', '%s', '%s')",
+ $this->id, $lang, $this->translations[$lang]->text, $this->translations[$lang]->texttype);
+
+ foreach($this->translations as $lang => $translation)
+ {
+ if(!in_array($lang, $this->to_be_created))
+ qdb("UPDATE `PREFIX_translations` SET `text` = '%s', `texttype` = '%s' WHERE `multilingual` = %d AND `language` = '%s'",
+ $translation->text, $translation->texttype, $this->id, $lang);
+ }
+
+ $this->to_be_created = array();
+ }
+
+ /*
+ * Function: delete
+ * Deletes the data from database.
+ */
+ public function delete()
+ {
+ qdb("DELETE FROM `PREFIX_translations` WHERE `multilingual` = %d", $this->id);
+ qdb("DELETE FROM `PREFIX_multilingual` WHERE `id` = %d", $this->id);
+ }
+
+ /* Countable interface implementation */
+ public function count() { return count($this->languages); }
+
+ /* ArrayAccess interface implementation */
+ public function offsetExists($offset) { return isset($this->translations[$offset]); }
+ public function offsetGet($offset)
+ {
+ if(isset($this->translations[$offset]))
+ return $this->translations[$offset];
+ else
+ throw new DoesNotExistError();
+ }
+ public function offsetUnset($offset)
+ {
+ unset($this->translations[$offset]);
+ if(in_array($offset, $this->to_be_created))
+ unset($this->to_be_created[array_search($offset, $this->to_be_created)]);
+ else
+ $this->to_be_deleted[] = $offset;
+ }
+ public function offsetSet($offset, $value)
+ {
+ if(!isset($this->translations[$offset]))
+ {
+ if(in_array($offset, $this->to_be_deleted))
+ unset($this->to_be_deleted[array_search($offset, $this->to_be_deleted)]);
+ else
+ $this->to_be_created[] = $offset;
+ }
+ $this->translations[$offset] = $value;
+ }
+
+ /* IteratorAggregate interface implementation */
+ public function getIterator() { return new ArrayIterator($this->translations); }
+}
+
+/*
+ * Variable: $global_settings_keys_buffer
+ * Buffer for settings key.
+ * NEVER(!) MODIFY DIRECTLY!
+ */
+$global_settings_keys_buffer = NULL;
+
+/* DO NOT CONSTRUCT THIS YOURSELF! */
+class SettingsIterator implements Iterator
+{
+ private $iter_keys_buffer;
+ private $settings_obj;
+ private $position = 0;
+
+ public function __construct($settings_obj)
+ {
+ global $global_settings_keys_buffer;
+ $this->settings_obj = $settings_obj;
+ $this->iter_keys_buffer = array_slice($global_settings_keys_buffer, 0); /* a.k.a. copying */
+ }
+
+ function rewind() { return $this->position = 0; }
+ function current() { return $this->settings_obj->offsetGet($this->iter_keys_buffer[$this->position]); }
+ function key() { return $this->iter_keys_buffer[$this->position]; }
+ function next() { ++$this->position; }
+ function valid() { return isset($this->iter_keys_buffer[$this->position]); }
+}
+
+/*
+ * Class: Settings
+ * Representing the settings.
+ * You can access them like an array.
+ */
+class Settings implements Countable, ArrayAccess, IteratorAggregate
+{
+ private $rw;
+
+ /*
+ * Constructor: __construct
+ * Creates a new Settings object.
+ *
+ * Parameters:
+ * $mode - "rw" for read-write access, "r" for read-only access (default)
+ */
+ public function __construct($mode="r")
+ {
+ global $global_settings_keys_buffer;
+ if($global_settings_keys_buffer === NULL)
+ {
+ $global_settings_keys_buffer = array();
+ $result = qdb("SELECT `key` FROM `PREFIX_settings_kvstorage` WHERE 1");
+ while($sqlrow = mysql_fetch_assoc($result))
+ $global_settings_keys_buffer[] = $sqlrow["key"];
+ }
+ $this->rw = ($mode == "rw");
+ }
+
+ /* Countable interface implementation */
+ public function count() { global $global_settings_keys_buffer; return count($global_settings_keys_buffer); }
+
+ /* ArrayAccess interface implementation */
+ public function offsetExists($offset) { global $global_settings_keys_buffer; return in_array($offset, $global_settings_keys_buffer); }
+ public function offsetGet($offset)
+ {
+ global $global_settings_keys_buffer;
+ if($this->offsetExists($offset))
+ {
+ $result = qdb("SELECT `value` FROM `PREFIX_settings_kvstorage` WHERE `key` = '%s'", $offset);
+ $sqlrow = mysql_fetch_assoc($result);
+ return unserialize(base64_decode($sqlrow["value"]));
+ }
+ else
+ throw new DoesNotExistError();
+ }
+ public function offsetUnset($offset)
+ {
+ global $global_settings_keys_buffer;
+ if(!$this->rw)
+ throw new NotAllowedError();
+ unset($global_settings_keys_buffer[array_search($offset, $global_settings_keys_buffer)]);
+ qdb("DELETE FROM `PREFIX_settings_kvstorage` WHERE `key` = '%s'", $offset);
+ }
+ public function offsetSet($offset, $value)
+ {
+ global $global_settings_keys_buffer;
+ if(!$this->rw)
+ throw new NotAllowedError();
+ if(in_array($offset, $global_settings_keys_buffer))
+ qdb("UPDATE `PREFIX_settings_kvstorage` SET `value` = '%s' WHERE `key` = '%s'", base64_encode(serialize($value)), $offset);
+ else
+ {
+ $global_settings_keys_buffer[] = $offset;
+ qdb("INSERT INTO `PREFIX_settings_kvstorage` (`key`, `value`) VALUES ('%s', '%s')", $offset, base64_encode(serialize($value)));
+ }
+ }
+
+ /* IteratorAggregate interface implementation */
+ public function getIterator() { return new SettingsIterator($this); }
+}
+
+/*
+ * Variable: $ratatoeskr_settings
+ * The global <Settings> object. For internal use.
+ */
+$ratatoeskr_settings = new Settings("rw");
+
+/*
+ * Class: PluginKVStorage
+ * A Key-Value-Storage for Plugins
+ * Can be accessed like an array.
+ * Keys are strings and Values can be everything serialize() can process.
+ */
+class PluginKVStorage implements Countable, ArrayAccess, Iterator
+{
+ private $plugin_id;
+ private $keybuffer;
+ private $counter;
+
+ /*
+ * Constructor: __construct
+ *
+ * Parameters:
+ * $plugin_id - The ID of the Plugin.
+ */
+ public function __construct($plugin_id)
+ {
+ $this->keybuffer = array();
+ $this->plugin_id = $plugin_id;
+
+ $result = qdb("SELECT `key` FROM `PREFIX_plugin_kvstorage` WHERE `plugin` = %d", $plugin_id);
+ while($sqlrow = mysql_fetch_assoc($result))
+ $this->keybuffer[] = $sqlrow["key"];
+
+ $this->counter = 0;
+ }
+
+ /* Countable interface implementation */
+ public function count() { return count($this->keybuffer); }
+
+ /* ArrayAccess interface implementation */
+ public function offsetExists($offset) { return in_array($offset, $this->keybuffer); }
+ public function offsetGet($offset)
+ {
+ if($this->offsetExists($offset))
+ {
+ $result = qdb("SELECT `value` FROM `PREFIX_plugin_kvstorage` WHERE `key` = '%s' AND `plugin` = %d", $offset, $this->plugin_id);
+ $sqlrow = mysql_fetch_assoc($result);
+ return unserialize(base64_decode($sqlrow["value"]));
+ }
+ else
+ throw new DoesNotExistError();
+ }
+ public function offsetUnset($offset)
+ {
+ if($this->offsetExists($offset))
+ {
+ unset($this->keybuffer[array_search($offset, $this->keybuffer)]);
+ $this->keybuffer = array_merge($this->keybuffer);
+ qdb("DELETE FROM `PREFIX_plugin_kvstorage` WHERE `key` = '%s' AND `plugin` = %d", $offset, $this->plugin_id);
+ }
+ }
+ public function offsetSet($offset, $value)
+ {
+ if($this->offsetExists($offset))
+ qdb("UPDATE `PREFIX_plugin_kvstorage` SET `value` = '%s' WHERE `key` = '%s' AND `plugin` = %d",
+ base64_encode(serialize($value)), $offset, $this->plugin_id);
+ else
+ {
+ qdb("INSERT INTO `PREFIX_plugin_kvstorage` (`plugin`, `key`, `value`) VALUES (%d, '%s', '%s')",
+ $this->plugin_id, $offset, base64_encode(serialize($value)));
+ $this->keybuffer[] = $offset;
+ }
+ }
+
+ /* Iterator interface implementation */
+ function rewind() { return $this->position = 0; }
+ function current() { return $this->offsetGet($this->keybuffer[$this->position]); }
+ function key() { return $this->keybuffer[$this->position]; }
+ function next() { ++$this->position; }
+ function valid() { return isset($this->keybuffer[$this->position]); }
+}
+
+/*
+ * Class: Comment
+ * Representing a user comment
+ */
+class Comment
+{
+ private $id;
+ private $article;
+ private $language;
+ private $timestamp;
+
+ /*
+ * Variables: Public class variables.
+ *
+ * $author_name - Name of comment author.
+ * $author_mail - E-Mail of comment author.
+ * $text - Comment text.
+ * $visible - Should the comment be visible?
+ */
+ public $author_name;
+ public $author_mail;
+ public $text;
+ public $visible;
+
+ /* Should not be constructed manually. */
+ private function __construct() { }
+
+ /*
+ * Functions: Getters
+ *
+ * get_id - Gets the comment ID.
+ * get_article - Gets the article.
+ * get_language - Gets the language.
+ * get_timestamp - Gets the timestamp.
+ */
+ public function get_id() { return $this->id; }
+ public function get_article() { return $this->article; }
+ public function get_language() { return $this->language; }
+ public function get_timestamp() { return $this->timestamp; }
+
+ /*
+ * Constructor: create
+ * Creates a new comment.
+ * Automatically sets the $timestamp and $visible (default form setting "comment_visible_default").
+ *
+ * Parameters:
+ * $article - An <Article> Object.
+ * $language - Which language? (see <languages.php>)
+ */
+ public static function create($article, $language)
+ {
+ global $ratatoeskr_settings;
+ $obj = new self;
+
+ qdb("INSERT INTO `PREFIX_comments` (`article`, `language`, `author_name`, `author_mail`, `text`, `timestamp`, `visible`) VALUES (%d, '%s', '', '', '', UNIX_TIMESTAMP(NOW()), %d)",
+ $article->id, $language, $ratatoeskr_settings["comment_visible_default"] ? 1 : 0);
+
+ $obj->id = mysql_insert_id();
+ $obj->article = $article;
+ $obj->language = $language;
+ $obj->author_name = "";
+ $obj->author_mail = "";
+ $obj->text = "";
+ $obj->timestamp = time();
+ $obj->visible = $ratatoeskr_settings["comment_visible_default"];
+ }
+
+ /*
+ * Constructor: by_id
+ * Gets a Comment by ID.
+ *
+ * Parameters:
+ * $id - The comments ID.
+ */
+ public static function by_id($id)
+ {
+ $obj = new self;
+
+ $result = qdb("SELECT `id`, `article`, `language`, `author_name`, `author_mail`, `text`, `timestamp`, visible` FROM `PREFIX_comments` WHERE `id` = %d",
+ $id);
+ $sqlrow = mysql_fetch_assoc($result);
+ if($sqlrow === False)
+ throw new DoesNotExistError();
+
+ $obj->id = $sqlrow["id"];
+ $obj->article = Article::by_id($sqlrow["article"]);
+ $obj->language = $sqlrow["language"];
+ $obj->author_name = $sqlrow["author_name"];
+ $obj->author_mail = $sqlrow["author_mail"];
+ $obj->text = $sqlrow["text"];
+ $obj->timestamp = $sqlrow["timestamp"];
+ $obj->visible = $sqlrow["visible"] == 1;
+
+ return $obj;
+ }
+
+ /*
+ * Function: save
+ * Save changes to database.
+ */
+ public function save()
+ {
+ qdb("UPDATE `PREFIX_comments` SET `author_name` = '%s', `author_mail` = '%s', `text` = '%s', `visible` = %d` WHERE `id` = %d`",
+ $this->author_name, $this->author_mail, $this->text, ($this->visible ? 1 : 0), $this->id);
+ }
+
+ /*
+ * Function: delete
+ */
+ public function delete()
+ {
+ qdb("DELETE FROM `PREFIX_comments` WHERE `id` = %d", $this->id);
+ }
+}
+
+/*
+ * Class: Style
+ * Represents a Style
+ */
+class Style
+{
+ private $id;
+
+ /*
+ * Variables: Public class variables.
+ *
+ * $name - The name of the style.
+ * $code - The CSS code.
+ * $acl - An <ACL> object.
+ */
+ public $name;
+ public $code;
+ public $acl;
+
+ /* Should not be constructed manually */
+ private function __construct() { }
+
+ private function populate_by_sqlresult($result)
+ {
+ $sqlrow = mysql_fetch_assoc($result);
+ if($sqlrow === False)
+ throw new DoesNotExistError();
+
+ $this->id = $sqlrow["id"];
+ $this->name = $sqlrow["name"];
+ $this->code = $sqlrow["code"];
+ $this->acl = ACL::by_id($sqlrow["acl"]);
+ }
+
+ /*
+ * Function: get_id
+ */
+ public function get_id() { return $this->id; }
+
+ /*
+ * Constructor: create
+ * Create a new style.
+ *
+ * Parameters:
+ * $name - A name for the new style.
+ */
+ public static function create($name)
+ {
+ $obj = new self;
+ $obj->acl = ACL::create(True);
+ $obj->name = $name;
+ $obj->code = "";
+
+ qdb("INSERT INTO `PREFIX_styles` (`name`, `code`, `acl`) VALUES ('%s', '', %d)",
+ $name, $this->acl->get_id());
+
+ $obj->id = mysql_insert_id();
+ return $obj;
+ }
+
+ /*
+ * Constructor: by_id
+ * Gets a style object by ID.
+ *
+ * Parameters:
+ * $id - The ID
+ */
+ public static function by_id($id)
+ {
+ $obj = new seld;
+ $obj->populate_by_sqlresult(qdb("SELECT `id`, `acl`, `name`, `code` FROM `PREFIX_styles` WHERE `id` = %d", $id));
+ return $obj;
+ }
+
+ /*
+ * Constructor: by_name
+ * Gets a style object by name.
+ *
+ * Parameters:
+ * $name - The name.
+ */
+ public static function by_name($id)
+ {
+ $obj = new seld;
+ $obj->populate_by_sqlresult(qdb("SELECT `id`, `acl`, `name`, `code` FROM `PREFIX_styles` WHERE `name` = '%s'", $name));
+ return $obj;
+ }
+
+ /*
+ * Function: save
+ * Save changes to database.
+ */
+ public function save()
+ {
+ $this->acl->save();
+ qdb("UPDATE `PREFIX_styles` SET `name` = '%s', `code` = '%s', `acl` = %d WHERE `id` = %d",
+ $this->name, $this->code, $this->acl, $this->id);
+ }
+
+ /*
+ * Function: delete
+ */
+ public function delete()
+ {
+ $this->acl->delete();
+ qdb("DELETE FROM `PREFIX_styles` WHERE `id` = %d", $this->id);
+ }
+}
+
+/*
+ * Class: PluginDB
+ * The representation of a plugin in the database.
+ * See <plugin.php> for loader functions and higher-level plugin access.
+ */
+class PluginDB
+{
+ private $id;
+
+ /*
+ * Variables: Public class variables.
+ *
+ * $name - Plugin name
+ * $class - Main class of the plugin
+ * $version - Plugin version
+ * $author - Plugin author
+ * $author_url - Website of author
+ * $description - Description of plugin
+ * $help - Help page (HTML)
+ * $phpcode - The plugin code
+ * $active - Is the plugin active?
+ */
+
+ public $name = "";
+ public $class = "";
+ public $version = "";
+ public $author = "";
+ public $author_url = "";
+ public $description = "";
+ public $help = "";
+ public $phpcode = "";
+ public $active = False;
+
+ private function __construct() { }
+
+ /*
+ * Function: get_id
+ */
+ public function get_id() { return $this->id; }
+
+ /*
+ * Constructor: create
+ * Creates a new, empty plugin database entry
+ */
+ public static function create()
+ {
+ $obj = new self;
+ qdb("INSERT INTO `PREFIX_plugins` () VALUES ()");
+ $obj->id = mysql_insert_id();
+ return $obj;
+ }
+
+ /*
+ * Constructor: by_id
+ * Gets plugin by ID.
+ *
+ * Parameters:
+ * $id - The ID
+ */
+ public static function by_id($id)
+ {
+ $obj = new self;
+
+ $result = qdb("SELECT `name`, `class`, `version`, `author`, `author_url`, `description`, `help`, `phpcode`, `active` FROM `PREFIX_plugins` WHERE `id` = %d", $id);
+ $sqlrow = mysql_fetch_assoc($result);
+ if($sqlrow === False)
+ throw new DoesNotExistError();
+
+ $obj->id = $id;
+ $obj->name = $sqlrow["name"];
+ $obj->class = $sqlrow["class"];
+ $obj->version = $sqlrow["version"];
+ $obj->author = $sqlrow["author"];
+ $obj->author_url = $sqlrow["author_url"];
+ $obj->description = $sqlrow["description"];
+ $obj->help = $sqlrow["help"];
+ $obj->phpcode = $sqlrow["phpcode"];
+ $obj->active = ($sqlrow["active"] == 1);
+
+ return $obj;
+ }
+
+ /*
+ * Constructor: all
+ * Gets all Plugins
+ *
+ * Returns:
+ * List of <PluginDB> objects.
+ */
+ public static function all()
+ {
+ $rv = array();
+ $result = qdb("SELECT `id` FROM `PREFIX_plugins` WHERE 1");
+ while($sqlrow = mysql_fetch_assoc($result))
+ $rv[] = self::by_id($sqlrow["id"]);
+ return $rv;
+ }
+
+ /*
+ * Function: save
+ */
+ public function save()
+ {
+ qdb("UPDATE `PREFIX_plugins` SET `name` = '%s', `class` = '%s', `version` = '%s', `author` = '%s', `author_url` = '%s', `description` = '%s', `help` = '%s', `phpcode` = '%s', `active` = %d WHERE `id` = %d`",
+ $this->name, $this->class, $this->version, $this->author, $this->author_url, $this->description, $this->help, $this->phpcode, $this->active ? 1 : 0, $this->id);
+ }
+
+ /*
+ * Function: delete
+ */
+ public function delete()
+ {
+ qdb("DELETE FROM `PREFIX_plugins` WHERE `id` = %d", $this->id);
+ }
+
+ /*
+ * Function get_kvstorage
+ * Get the KeyValue Storage for the plugin.
+ *
+ * Returns:
+ * An <PluginKVStorage> object.
+ */
+ public function get_kvstorage()
+ {
+ return new PluginKVStorage($this->id);
+ }
+}
+
+/*
+ * Class: Section
+ * Representing a section
+ */
+class Section
+{
+ private $id;
+
+ /*
+ * Variables: Public class variables
+ *
+ * $name - The name of the section.
+ * $title - The title of the section (a <Multilingual> object).
+ * $template - Name of the template.
+ * $styles - List of <Style> objects.
+ */
+ public $name;
+ public $title;
+ public $template;
+ public $styles;
+
+ private function __construct() {}
+
+ private function populate_by_sqlresult($result)
+ {
+ $sqlrow = mysql_fetch_assoc($result);
+ if($sqlrow === False)
+ throw new DoesNotExistError();
+
+ $this->id = $sqlrow["id"];
+ $this->name = $sqlrow["name"];
+ $this->title = Multilingual::by_id($sqlrow["title"]);
+ $this->template = $sqlrow["template"];
+ $this->styles = array_filter_empty(array_map(
+ function($id) { try{return Style::by_id($id);}catch(DoesNotExistError $e){ return "";} },
+ array_filter_empty(explode("+", $sqlrow["styles"]))));
+ }
+
+ /*
+ * Function: get_id
+ */
+ public function get_id() { return $this->id; }
+
+ /*
+ * Constructor: create
+ * Creates a new section.
+ *
+ * Parameters:
+ * $name - The name of the new section.
+ */
+ public static function create($name)
+ {
+ try
+ {
+ $obj = self::by_name($name);
+ }
+ catch(DoesNotExistError $e)
+ {
+ $obj = new self;
+ $obj->name = $name;
+ $obj->title = Multilingual::create();
+ $obj->template = "";
+ $obj->styles = array();
+
+ $result = qdb("INSERT INTO `PREFIX_sections` (`name`, `title`, `template`, `styles`) VALUES ('%s', %d, '', '')",
+ $name, $obj->title->get_id());
+
+ $obj->id = mysql_insert_id();
+
+ return $obj;
+ }
+
+ throw new AlreadyExistsError();
+ }
+
+ /*
+ * Constructor: by_id
+ * Gets section by ID.
+ *
+ * Parameters:
+ * $id - The ID.
+ */
+ public static function by_id($id)
+ {
+ $obj = new self;
+ $obj->populate_by_sqlresult(qdb("SELECT `id`, `name`, `title`, `template`, `styles` FROM `PREFIX_sections` WHERE `id` = %d", $id));
+ return $obj;
+ }
+
+ /*
+ * Constructor: by_name
+ * Gets section by name.
+ *
+ * Parameters:
+ * $name - The name.
+ */
+ public static function by_name($name)
+ {
+ $obj = new self;
+ $obj->populate_by_sqlresult(qdb("SELECT `id`, `name`, `title`, `template`, `styles` FROM `PREFIX_sections` WHERE `name` = '%s'", $name));
+ return $obj;
+ }
+
+ /*
+ * Constructor: all
+ * Gets all sections.
+ *
+ * Returns:
+ * Array of Section objects.
+ */
+ public static function all()
+ {
+ $rv = array();
+ $result = qdb("SELECT `id` FROM `PREFIX_sections` WHERE 1");
+ while($sqlrow = mysql_fetch_assoc($result))
+ $rv[] = self::by_id($sqlrow["id"]);
+ return $rv;
+ }
+
+ /*
+ * Function: save
+ */
+ public function save()
+ {
+ $styles = "+";
+ foreach($this->styles as $style)
+ {
+ $style->save();
+ $styles .= $style->get_id() . "+";
+ }
+ if($styles == "+")
+ $styles = "";
+
+ $this->title->save();
+ qdb("UPDATE `PREFIX_sections` SET `name` = '%s', `title` = %d, `template` = '%s', `styles` = '%s' WHERE `id` = %d",
+ $this->name, $this->title->get_id(), $this->template, $styles);
+ }
+
+ /*
+ * Function: delete
+ */
+ public function delete()
+ {
+ $this->title->delete();
+ qdb("DELETE FROM `PREFIX_sections` WHERE `id` = %d", $this->id);
+ }
+
+ /*
+ * Function: get_articles
+ * Get all articles in this section.
+ *
+ * Returns:
+ * Array of <Article> objects
+ */
+ public function get_articles()
+ {
+ $rv = array();
+ $result = qdb("SELECT `id` FROM `PREFIX_articles` WHERE `section` = %d", $this->id);
+ while($sqlrow = mysql_fetch_assoc($result))
+ $rv[] = Article::by_id($sqlrow["id"]);
+ return $rv;
+ }
+}
+
+/*
+ * Class: Tag
+ * Representation of a tag
+ */
+class Tag
+{
+ private $id;
+
+ /*
+ * Variables: Public class variables
+ *
+ * $name - The name of the tag
+ * $title - The title (an <Multilingual> object)
+ */
+ public $name;
+ public $title;
+
+ /*
+ * Function: get_id
+ */
+ public function get_id() { return $this->id; }
+
+ private function __construct() {}
+
+ private function populate_by_sqlresult($result)
+ {
+ $sqlrow = mysql_fetch_assoc($result);
+ if($sqlrow === False)
+ throw new DoesNotExistError();
+
+ $this->id = $sqlrow["id"];
+ $this->name = $sqlrow["name"];
+ $this->title = Multilingual::by_id($sqlrow["title"]);
+ }
+
+ /*
+ * Constructor: create
+ * Create a new tag.
+ *
+ * Parameters:
+ * $name - The name
+ */
+ public static function create($name)
+ {
+ try
+ {
+ $obj = self::by_name($name);
+ }
+ catch(DoesNotExistError $e)
+ {
+ $obj = new self;
+
+ $obj->name = $name;
+ $obj->title = Multilingual::create();
+
+ qdb("INSERT INTO `PREFIX_tags` (`name`, `title`) VALUES ('%s', %d)",
+ $name, $obj->title->get_id());
+ $obj->id = mysql_insert_id();
+
+ return $obj;
+ }
+ throw new AlreadyExistsError();
+ }
+
+ /*
+ * Constructor: by_id
+ * Get tag by ID
+ *
+ * Parameters:
+ * $id - The ID
+ */
+ public static function by_id($id)
+ {
+ $obj = new self;
+ $obj->populate_by_sqlresult(qdb("SELECT `id`, `name`, `title` FROM `PREFIX_tags` WHERE `id` = %d", $id));
+ return $obj;
+ }
+
+ /*
+ * Constructor: by_name
+ * Get tag by name
+ *
+ * Parameters:
+ * $name - The name
+ */
+ public static function by_name($name)
+ {
+ $obj = new self;
+ $obj->populate_by_sqlresult(qdb("SELECT `id`, `name`, `title` FROM `PREFIX_tags` WHERE `name` = '%s'", $name));
+ return $obj;
+ }
+
+ /*
+ * Constructor: all
+ * Get all tags
+ *
+ * Returns:
+ * Array of Tag objects.
+ */
+ public static function all()
+ {
+ $rv = array();
+ $result = qdb("SELECT `id` FROM `PREFIX_tags` WHERE 1");
+ while($sqlrow = mysql_fetch_assoc($result))
+ $rv[] = self::by_id($result["id"]);
+ return $rv;
+ }
+
+ /*
+ * Function: get_articles
+ * Get all articles that are tagged with this tag
+ *
+ * Returns:
+ * Array of <Article> objects
+ */
+ public function get_articles()
+ {
+ $rv = array();
+ $result = qdb("SELECT `article` FROM `PREFIX_article_tag_relations` WHERE `tag` = %d", $this->id);
+ while($sqlrow = mysql_fetch_assoc($result))
+ $rv[] = Article::by_id($sqlrow["id"]);
+ return $rv;
+ }
+
+ /*
+ * Function: count_articles
+ *
+ * Retutrns:
+ * The number of articles that are tagged with this tag.
+ */
+ public function count_articles()
+ {
+ $result = qdb("SELECT COUNT(*) AS `num` FROM `PREFIX_article_tag_relations` WHERE `tag` = %d", $this->id);
+ $sqlrow = mysql_fetch_assoc($result);
+ return $sqlrow["num"];
+ }
+
+ /*
+ * Function: save
+ */
+ public function save()
+ {
+ $this->title->save();
+ qdb("UPDATE `PREFIX_tags` SET `name` = '%s', `title` = %d` WHERE `id` = %d",
+ $this->name, $this->title->get_id(), $this->id);
+ }
+
+ /*
+ * Function: delete
+ */
+ public function delete()
+ {
+ $this->title->delete();
+ qdb("DELETE FROM `PREFIX_article_tag_relations` WHERE `tag` = %d", $this->id);
+ qdb("DELETE FROM `PREFIX_tags` WHERE `id` = %d", $this->id);
+ }
+}
+
+/*
+ * Class: UnknownFileFormat
+ * Exception that will be thrown, if a input file has an unsupported file format.
+ */
+class UnknownFileFormat extends Exception { }
+
+/*
+ * Class: IOError
+ * This Exception is thrown, if a IO-Error occurs (file not available, no read/write acccess...).
+ */
+class IOError extends Exception { }
+
+/*
+ * Array: $imagetype_file_extensions
+ * Array of default file extensions for most IMAGETYPE_* constants
+ */
+$imagetype_file_extensions = array(
+ IMAGETYPE_GIF => "gif",
+ IMAGETYPE_JPEG => "jpg",
+ IMAGETYPE_PNG => "png",
+ IMAGETYPE_BMP => "bmp",
+ IMAGETYPE_TIFF_II => "tif",
+ IMAGETYPE_TIFF_MM => "tif",
+);
+
+/*
+ * Class: Image
+ * Representation of an image entry.
+ */
+class Image
+{
+ private $id;
+ private $filename;
+
+ /*
+ * Variables: Public class variables
+ *
+ * $name - The image name
+ * $alt - The alternative text (a <Multilingual> object)
+ * $acl - An <ACL> object
+ */
+ public $name;
+ public $alt;
+ public $acl;
+
+ private function __construct() { }
+
+ private function populate_by_sqlresult($result)
+ {
+ $sqlrow = mysql_fetch_assoc($result);
+ if($sqlrow === False)
+ throw new DoesNotExistError();
+
+ $this->name = $sqlrow["name"];
+ $this->alt = Multilingual::by_id($sqlrow["alt"]);
+ $this->file = $sqlrow["file"];
+ $this->acl = ACL::by_id($sqlrow["acl"]);
+ }
+
+ /*
+ * Functions: Getters
+ *
+ * get_id - Get the ID
+ * get_filename - Get the filename
+ */
+ public function get_id() { return $this->id; }
+ public function get_filename() { return $this->file; }
+
+ /*
+ * Constructor: create
+ * Create a new image
+ *
+ * Parameters:
+ * $name - The name for the image
+ * $file - A uploaded image file (move_uploaded_file must be able to move the file!).
+ */
+ public static function create($name, $file)
+ {
+ $obj = new self;
+ $obj->name = $name;
+ $obj->alt = Multilingual::create();
+ $obj->acl = ACL::create();
+ $obj->file = "0";
+
+ qdb("INSERT INTO `PREFIX_images` (`name`, `alt`, `file`, `acl`) VALUES ('%s', %d, '0', %d)",
+ $name, $obj->alt->get_id(), $obj->acl->get_id());
+
+ $obj->id = mysql_insert_id();
+ try
+ {
+ $obj->exchange_image($file);
+ }
+ catch(Exception $e)
+ {
+ $obj->delete();
+ throw $e;
+ }
+ return $obj;
+ }
+
+ /*
+ * Constructor: by_id
+ * Get iimage by ID.
+ *
+ * Parameters:
+ * $id - The ID
+ */
+ public static function by_id($id)
+ {
+ $obj = new self;
+ $obj->populate_by_sqlresult(qdb("SELECT `id`, `name`, `alt`, `file`, `acl` FROM `PREFIX_images` WHERE `id` = %d", $id));
+ return $obj;
+ }
+
+ /*
+ * Constructor: all
+ * Gets all images.
+ *
+ * Returns:
+ * Array of <Image> objects.
+ */
+ public function all()
+ {
+ $rv = array();
+ $result = qdb("SELECT `id` FROM `PREFIX_images` WHERE 1");
+ while($sqlrow = mysql_fetch_assoc($result))
+ $rv[] = self::by_id($sqlrow["id"]);
+ return $rv;
+ }
+
+ /*
+ * Function: exchange_image
+ * Exchanges image file. Also saves object to database.
+ *
+ * Parameters:
+ * $file - Location of new image.(move_uploaded_file must be able to move the file!)
+ */
+ public function exchange_image($file)
+ {
+ global $imagetype_file_extensions;
+ if(!is_file($file))
+ throw new IOError("\"$file\" is not available");
+ $imageinfo = getimagesize($file);
+ if($imageinfo === False)
+ throw new UnknownFileFormat();
+ if(!isset($imagetype_file_extensions[$imageinfo[2]]))
+ throw new UnknownFileFormat();
+ if(is_file(SITE_BASE_PATH . "/images/" . $this->file))
+ unlink(SITE_BASE_PATH . "/images/" . $this->file);
+ $new_fn = $this->id . $imagetype_file_extensions[$imageinfo[2]];
+ move_uploaded_file($file, SITE_BASE_PATH . "/images/" . $new_fn);
+ $this->file = $new_fn;
+ $this->save();
+ }
+
+ /*
+ * Function: save
+ */
+ public function save()
+ {
+ $this->acl->save();
+ $this->alt->save();
+ qdb("UPDATE `PREFIX_images` SET `name` = '%s', `alt` = %d, `file` = '%s', `acl` = %d WHERE `id` = %d",
+ $this->name, $this->alt->get_id(), $this->file, $this->acl->get_id(), $this->id);
+ }
+
+ /*
+ * Function: delete
+ */
+ public function delete()
+ {
+ $this->acl->delete();
+ $this->alt->delete();
+ if(is_file(SITE_BASE_PATH . "/images/" . $this->file))
+ unlink(SITE_BASE_PATH . "/images/" . $this->file);
+ qdb("DELETE FROM `PREFIX_images` WHERE `id` = %d", $this->id);
+ }
+}
+
+/*
+ * Constants: Possible <Article>::$status values.
+ *
+ * ARTICLE_STATUS_HIDDEN - Article is hidden
+ * ARTICLE_STATUS_LIVE - Article is visible / live
+ * ARTICLE_STATUS_STICKY - Article is sticky
+ */
+define("ARTICLE_STATUS_HIDDEN", 0);
+define("ARTICLE_STATUS_LIVE", 1);
+define("ARTICLE_STATUS_STICKY", 2);
+
+/*
+ * Class: Article
+ * Representation of an article
+ */
+class Article
+{
+ private $id;
+
+ /*
+ * Variables: Public class variables
+ *
+ * $urltitle - URL title
+ * $title - Title (an <Multilingual> object)
+ * $text - The text (an <Multilingual> object)
+ * $excerpt - Excerpt (an <Multilingual> object)
+ * $meta - Keywords, comma seperated
+ * $custom - Custom fields, is an array
+ * $acl - an <ACL> object
+ * $article_image - The article <Image>. If none: NULL
+ * $status - One of the ARTICLE_STATUS_* constants
+ * $section - <Section>
+ * $timestamp - Timestamp
+ * $allow_comments - Are comments allowed?
+ * $tags - Arrray of <Tag> objects
+ */
+ public $urltitle;
+ public $title;
+ public $text;
+ public $excerpt;
+ public $meta;
+ public $custom;
+ public $acl;
+ public $article_image;
+ public $status;
+ public $section;
+ public $timestamp;
+ public $allow_comments;
+ public $tags;
+
+ private function __construct()
+ {
+ $this->tags = array();
+ }
+
+ private function populate_by_sqlresult($result)
+ {
+ $sqlrow = mysql_fetch_assoc($result);
+ if($sqlrow === False)
+ throw new DoesNotExistError();
+
+ $this->id = $sqlrow["id"];
+ $this->urltitle = $sqlrow["urltitle"];
+ $this->title = Multilingual::by_id($sqlrow["title"]);
+ $this->text = Multilingual::by_id($sqlrow["text"]);
+ $this->excerpt = Multilingual::by_id($sqlrow["excerpt"]);
+ $this->meta = $sqlrow["meta"];
+ $this->custom = unserialize(base64_decode($sqlrow["custom"]));
+ $this->acl = ACL::by_id($sqlrow["acl"]);
+ $this->article_image = $sqlrow["article_image"] == 0 ? NULL : Image::by_id($sqlrow["article_image"]);
+ $this->status = $sqlrow["status"];
+ $this->section = Section::by_id($sqlrow["section"]);
+ $this->timestamp = $sqlrow["timestamp"];
+ $this->allow_comments = $sqlrow["allow_comments"] == 1;
+
+ $result = qdb("SELECT `tag` FROM `PREFIX_article_tag_relations` WHERE `article` = %d", $this->id);
+ while($sqlrow = mysql_fetch_assoc($result))
+ $this->tags[] = Tag::by_id($sqlrow["tag"]);
+ }
+
+ /*
+ * Function: get_id
+ */
+ public function get_id() { return $this->id; }
+
+ /*
+ * Constructor: create
+ * Create a new Article object
+ */
+ public static function create()
+ {
+ global $ratatoeskr_settings;
+ $obj = new self;
+ $obj->urltitle = "";
+ $obj->title = Multilingual::create();
+ $obj->text = Multilingual::create();
+ $obj->excerpt = Multilingual::create();
+ $obj->meta = "";
+ $obj->custom = array();
+ $obj->acl = ACL::create();
+ $obj->article_image = NULL;
+ $obj->status = ARTICLE_STATUS_HIDDEN;
+ $obj->section = Section::by_id($ratatoeskr_settings["default_section"]);
+ $obj->timestamp = time();
+ $obj->allow_comments = $ratatoeskr_settings["allow_comments_default"];
+
+ qdb("INSERT INTO `PREFIX_articles` (`urltitle`, `title`, `text`, `excerpt`, `meta`, `custom`, `acl`, `article_image`, `status`, `section`, `timestamp`, `allow_comments`) VALUES ('', %d, %d, %d, '', '%s', %d, 0, %d, %d, %d, %d)",
+ $obj->title->get_id(),
+ $obj->text->get_id(),
+ $obj->excerpt->get_id(),
+ base64_encode(serialize($obj->custom)),
+ $obj->acl->get_id(),
+ $obj->status,
+ $obj->section->get_id(),
+ $obj->timestamp,
+ $obj->allow_comments ? 1 : 0);
+ $obj->id = mysql_insert_id();
+ return $obj;
+ }
+
+ /*
+ * Constructor: by_id
+ * Get by ID.
+ *
+ * Parameters:
+ * $id - The ID.
+ */
+ public static function by_id($id)
+ {
+ $obj = new self;
+ $obj ->populate_by_sqlresult(qdb(
+ "SELECT `id`, `urltitle`, `title`, `text`, `excerpt`, `meta`, `acl`, `custom`, `article_image`, `status`, `section`, `timestamp`, `allow_comments` FROM `PREFIX_articles` WHERE `id` = %d", $id
+ ));
+ return $obj;
+ }
+
+ /*
+ * Constructor: by_urlname
+ * Get by urlname
+ *
+ * Parameters:
+ * $urlname - The urlname
+ */
+ public static function by_urlname($id)
+ {
+ $obj = new self;
+ $obj ->populate_by_sqlresult(qdb(
+ "SELECT `id`, `urltitle`, `title`, `text`, `excerpt`, `meta`, `custom`, `acl`, `article_image`, `status`, `section`, `timestamp`, `allow_comments` FROM `PREFIX_articles` WHERE `urlname` = '%s'", $urlname
+ ));
+ return $obj;
+ }
+
+ /*
+ * Constructor: all
+ * Get all articles
+ *
+ * Returns:
+ * Array of Article objects
+ */
+ public static function all()
+ {
+ $rv = array();
+ $result = qdb("SELECT `id` FROM `PREFIX_articles` WHERE 1");
+ while($sqlrow = mysql_fetch_assoc($result))
+ $rv[] = self::by_id($sqlrow["id"]);
+ return $rv;
+ }
+
+ /*
+ * Function: get_comments
+ * Getting comments for this article.
+ *
+ * Returns:
+ * Array of <Comment> objects.
+ */
+ public function get_comments()
+ {
+ $rv = array();
+ $result = qdb("SELECT `id` FROM `PREFIX_comments` WHERE `article` = %d", $this->id);
+ while($sqlrow = mysql_fetch_assoc($result))
+ $rv[] = Comment::by_id($sqlrow["id"]);
+ return $rv;
+ }
+
+ /*
+ * Function: save
+ */
+ public function save()
+ {
+ $this->title->save();
+ $this->text->save();
+ $this->excerpt->save();
+ $this->acl->save();
+
+ qdb("DELETE FROM `PREFIX_article_tag_relations` WHERE `article`= %d", $this->id);
+
+ $articleid = $this->id;
+ /* So we just need to fire one query instead of count($this->tags) queries. */
+ if(!empty($this->tags))
+ qdb(
+ "INSERT INTO `PREFIX_article_tag_relations` (`article`, `tag`) VALUES " .
+ implode(",",
+ array_map(function($tag) use ($articleid){ return qdb_fmt("(%d, %d)", $articleid, $tag->get_id()); },
+ $this->tags)
+ )
+ );
+
+ qdb("UPDATE `PREFIX_articles` SET `urltitle` = '%s', `title` = %d, `text` = %d, `excerpt` = %d, `meta` = '%s', `custom` = '%s', `acl` = %d, `article_image` = %d, `status` = %d, `section` = %d, `timestamp` = %d, `allow_comments` = %d WHERE `id` = %d",
+ $this->urltitle,
+ $this->title->get_id(),
+ $this->text->get_id(),
+ $this->excerpt->get_id(),
+ $this->meta,
+ base64_encode(serialize($this->custom)),
+ $this->acl->get_id(),
+ $this->article_image === NULL ? 0 : $this->article_image->get_id(),
+ $this->status,
+ $this->section->get_id(),
+ $this->timestamp,
+ $this->allow_comments ? 1 : 0,
+ $this->id
+ );
+ }
+
+ /*
+ * Function: delete
+ */
+ public function delete()
+ {
+ $this->title->delete();
+ $this->text->delete();
+ $this->excerpt->delete();
+ $this->acl->delete();
+
+ foreach($this->get_comments() as $comment)
+ $comment->delete();
+
+ qdb("DELETE FROM `PREFIX_article_tag_relations` WHERE `article` = %d", $this->id);
+ qdb("DELETE FROM `PREFIX_articles` WHERE `id` = %d", $this->id);
+ }
+}
+
+?>
diff --git a/ratatoeskr/sys/utils.php b/ratatoeskr/sys/utils.php
new file mode 100644
index 0000000..de673aa
--- /dev/null
+++ b/ratatoeskr/sys/utils.php
@@ -0,0 +1,164 @@
+<?php
+/*
+ * File: utils.php
+ *
+ * Various useful helper functions.
+ *
+ * This file is part of Ratatöskr.
+ * Ratatöskr is licensed unter the MIT / X11 License.
+ * See "ratatoeskr/licenses/ratatoeskr" for more information.
+ */
+
+/*
+ * Function: array_repeat
+ *
+ * Parameters:
+ *
+ * $val -
+ * $n -
+ *
+ * Returns:
+ *
+ * An array with $val $n-times repeated.
+ */
+function array_repeat($val, $n)
+{
+ $rv = array();
+ for($i = 1; $i < $n; ++$i)
+ array_push($rv, $val);
+ return $rv;
+}
+
+/*
+ * Function: array_blend
+ *
+ * Blend multiple arrays together.
+ *
+ * Example:
+ *
+ * array_blend(array(1,2,3), array(4,5,6), array(7,8,9));
+ * will return array(1,4,7,2,5,8,3,6,9)
+ */
+function array_blend()
+{
+ $arrays = array_filter(func_get_args(), "is_array");
+
+ switch(count($arrays))
+ {
+ case 0: return array(); break;
+ case 1: return $arrays[0]; break;
+ default:
+ $rv = array();
+ while(array_sum(array_map("count", $arrays)) > 0)
+ {
+ for($i = 0; $i < count($arrays); ++$i)
+ {
+ $val = array_shift($arrays[$i]);
+ if($val === NULL)
+ continue;
+ array_push($rv, $val);
+ }
+ }
+ return $rv;
+ break;
+ }
+}
+
+/*
+ * Function: array_filter_empty
+ *
+ * Filters all empty elements out of an array.
+ *
+ * Parameters:
+ *
+ * $input - The input array
+ *
+ * Returns:
+ *
+ * The $input without its empty elements.
+ */
+function array_filter_empty($input)
+{
+ return array_filter($input, function($x){return !empty($x);});
+}
+
+/*
+ * Function: array_filter_keys
+ *
+ * Like PHPs `array_filter`, but callback will get the key, not the value of the array element.
+ */
+function array_filter_keys($input, $callback)
+{
+ if(!is_array($input))
+ throw new InvalidArgumentException("Argument 1 must be an array");
+ if(empty($input))
+ return array();
+ $delete_keys = array_filter(array_keys($input), function ($x) use ($callback) { return !$callback($x);});
+ foreach($delete_keys as $key)
+ unset($input[$key]);
+ return $input;
+}
+
+/*
+ * Function: ucount
+ *
+ * Count elements of an array matching unser-defined rules.
+ *
+ * Parameters:
+ * $array - The input array.
+ * $callback - A callback function. It will be called with the current value as the only parameter. The value is counted, if callback returns TRUE.
+ *
+ * Returns:
+ *
+ * Number of elements where $callback returned TRUE.
+ */
+function ucount($array, $callback)
+{
+ return count(array_filter($array, $callback));
+}
+
+/*
+ * Function: vcount
+ *
+ * Counts how often $value appears in $array.
+ *
+ * Parameters:
+ *
+ * $array -
+ * $value -
+ *
+ * Returns:
+ *
+ * How often $value appears in $array.
+ */
+function vcount($array, $value)
+{
+ return ucount($array, function($x){return $x===$value;});
+}
+
+/*
+ * Function: self_url
+ *
+ * Gets current URL.
+ *
+ * From: http://dev.kanngard.net/Permalinks/ID_20050507183447.html
+ */
+function self_url() {
+ $s = empty($_SERVER["HTTPS"]) ? ''
+ : ($_SERVER["HTTPS"] == "on") ? "s"
+ : "";
+ $protocol = strleft(strtolower($_SERVER["SERVER_PROTOCOL"]), "/").$s;
+ $port = ($_SERVER["SERVER_PORT"] == "80") ? ""
+ : (":".$_SERVER["SERVER_PORT"]);
+ return $protocol."://".$_SERVER['SERVER_NAME'].$port.$_SERVER['REQUEST_URI'];
+}
+function strleft($s1, $s2) {
+ return substr($s1, 0, strpos($s1, $s2));
+}
+
+/*
+ * Constant: SITE_BASE_PATH
+ * The Base path of this ratatoeskr site.
+ */
+define(SITE_BASE_PATH, dirname(dirname(dirname(__FILE__))));
+?>
diff --git a/ratatoeskr/templates/usertemplates/foo.tpl b/ratatoeskr/templates/usertemplates/foo.tpl
new file mode 100644
index 0000000..af1564c
--- /dev/null
+++ b/ratatoeskr/templates/usertemplates/foo.tpl
@@ -0,0 +1,14 @@
+<{*HEADER
+Ratatoeskr template
+DO NOT REMOVE THIS COMMENT!
+-----BEGIN META-----
+{
+ "Content-Type": "text/html",
+ "ACL": {
+ "users": ["foo"],
+ "groups": [],
+ "rights": {"users": ["read", "write", "delete"], "groups": ["read"], "others": ["read"]}
+ }, "author": "Kevin Chabowski"
+}
+-----END META-----
+/HEADER*}>
diff --git a/ratatoeskr/translations/de.php b/ratatoeskr/translations/de.php
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ratatoeskr/translations/de.php
diff --git a/ratatoeskr/translations/en.php b/ratatoeskr/translations/en.php
new file mode 100644
index 0000000..c7bcf06
--- /dev/null
+++ b/ratatoeskr/translations/en.php
@@ -0,0 +1,7 @@
+<?php
+
+$translation = array(
+
+);
+
+?>