diff options
-rw-r--r-- | ratatoeskr/config.php | 11 | ||||
-rw-r--r-- | ratatoeskr/languages.php | 189 | ||||
-rw-r--r-- | ratatoeskr/setup/create_tables.php | 139 | ||||
-rw-r--r-- | ratatoeskr/sys/db.php | 103 | ||||
-rw-r--r-- | ratatoeskr/sys/default_settings.php | 10 | ||||
-rw-r--r-- | ratatoeskr/sys/models.php | 2071 | ||||
-rw-r--r-- | ratatoeskr/sys/utils.php | 164 | ||||
-rw-r--r-- | ratatoeskr/templates/usertemplates/foo.tpl | 14 | ||||
-rw-r--r-- | ratatoeskr/translations/de.php | 0 | ||||
-rw-r--r-- | ratatoeskr/translations/en.php | 7 |
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( + +); + +?> |