add('name', PLUGIN_GUESTBOOK_TITLE); $propbag->add('description', PLUGIN_GUESTBOOK_TITLE_BLAHBLAH); $propbag->add('event_hooks', array ( 'frontend_configure' => true, 'entries_header' => true, 'external_plugin' => true, 'genpage' => true, 'backend_sidebar_entries' => true, 'backend_sidebar_admin_appearance' => true, 'backend_sidebar_entries_event_display_guestbook' => true, 'css' => true, 'css_backend' => true, 'entry_display' => true )); $propbag->add('configuration', array( 'permalink', 'pagetitle', 'headline', 'intro', 'formorder', 'numberitems', 'maxitems', 'wordwrap', 'markup', 'emailadmin', 'targetmail', 'showemail', 'showcaptcha', 'showpage', 'showapp', 'automoderate', 'entrychecks', 'dateformat' )); $propbag->add('author', 'Ian'); $propbag->add('version', '3.61.2'); $propbag->add('requirements', array( 'serendipity' => '1.7.0', 'smarty' => '3.1.0', 'php' => '5.2.0' )); $propbag->add('stackable', false); $propbag->add('groups', array('FRONTEND_FEATURES', 'BACKEND_FEATURES')); $this->filter_defaults = array('words' => '\[link(.*?)\];http://'); } /** * serendipity_plugin::example method * */ function example() { return "\n\n\n"; } /** * serendipity_plugin::cleanup method * * @return boolean */ function cleanup() { global $serendipity; // check possible config mismatch setting if (serendipity_db_bool($this->get_config('showapp')) === true && serendipity_db_bool($this->get_config('automoderate')) === true) { $this->set_config('automoderate', false); echo '
' . PLUGIN_GUESTBOOK_CONFIG_ERROR . '
'; return false; } // Cleanup. Remove all empty configs on SAVECONF-Submit. serendipity_plugin_api::remove_plugin_value($this->instance, array('sessionlock', 'timelock', 'version', 'targetmail', 'pageurl', 'dynamic_fields', 'dynamic_fields_desc', 'formpopup', 'getdynfield', 'showdynfield')); return true; } /** * serendipity_plugin::install method * */ function install() { $this->createTable(); } /** * Create table install * */ function createTable() { global $serendipity; $q = "CREATE TABLE IF NOT EXISTS {$serendipity['dbPrefix']}guestbook ( id {AUTOINCREMENT} {PRIMARY}, ip varchar(45) default NULL, name varchar(100), homepage varchar(100), email varchar(100), body text, approved int(1) default 1, timestamp int(10) {UNSIGNED} NULL) {UTF_8}"; serendipity_db_schema_import($q); } /** * Upgrade Alter Table * * @param string version */ function alter_db($db_config_version) { global $serendipity; if ($db_config_version == '1.0') { $q = "ALTER TABLE {$serendipity['dbPrefix']}guestbook CHANGE name name varchar(100)"; serendipity_db_schema_import($q); $q = "DELETE FROM {$serendipity['dbPrefix']}config WHERE name LIKE '%serendipity_event_guestbook%/sessionlock' AND name LIKE '%serendipity_event_guestbook%/timelock'"; serendipity_db_schema_import($q); } if ($db_config_version == '2.0') { $q = "ALTER TABLE {$serendipity['dbPrefix']}guestbook ADD COLUMN approved int(1) AFTER body DEFAULT 1"; serendipity_db_schema_import($q); $q = "DELETE FROM {$serendipity['dbPrefix']}config WHERE name LIKE '%serendipity_event_guestbook%/version'"; serendipity_db_schema_import($q); $q = "DELETE FROM {$serendipity['dbPrefix']}config WHERE name LIKE '%serendipity_event_guestbook%/dynamic_fields'"; serendipity_db_schema_import($q); $q = "DELETE FROM {$serendipity['dbPrefix']}config WHERE name LIKE '%serendipity_event_guestbook%/dynamic_fields_desc'"; serendipity_db_schema_import($q); $q = "DELETE FROM {$serendipity['dbPrefix']}config WHERE name LIKE '%serendipity_event_guestbook%/formpopup'"; serendipity_db_schema_import($q); $q = "DELETE FROM {$serendipity['dbPrefix']}config WHERE name LIKE '%serendipity_event_guestbook%/getdynfield'"; serendipity_db_schema_import($q); $q = "DELETE FROM {$serendipity['dbPrefix']}config WHERE name LIKE '%serendipity_event_guestbook%/pageurl'"; serendipity_db_schema_import($q); $q = "DELETE FROM {$serendipity['dbPrefix']}config WHERE name LIKE '%serendipity_event_guestbook%/showdynfield'"; serendipity_db_schema_import($q); $q = "DROP TABLE IF EXISTS {$serendipity['dbPrefix']}guestbook_dyn"; serendipity_db_schema_import($q); } if ($db_config_version == '3.0') { $q = "ALTER TABLE {$serendipity['dbPrefix']}guestbook CHANGE COLUMN ip ip VARCHAR(45)"; serendipity_db_schema_import($q); } // table order placement to make sure for db administration tasks if ($db_config_version == '4') { $q = "ALTER TABLE {$serendipity['dbPrefix']}guestbook CHANGE COLUMN timestamp timestamp int(10) AFTER approved"; serendipity_db_schema_import($q); } } /** * serendipity_plugin::uninstall method * * @return boolean */ function uninstall(&$propbag) { global $serendipity; if (isset($serendipity['guestbookdroptable']) === true) { $q = "DROP TABLE IF EXISTS {$serendipity['dbPrefix']}guestbook"; if (serendipity_db_schema_import($q)) return true; } else { $adminpath = $_SERVER['PHP_SELF'].'?serendipity[adminModule]=event_display&serendipity[adminAction]=guestbook&serendipity[guestbookcategory]='; $this->backend_guestbook_questionaire(PLUGIN_GUESTBOOK_ADMIN_DROP_SURE . '
' . PLUGIN_GUESTBOOK_ADMIN_DUMP_SELF, $adminpath, 'gbdb', 'droptable'); return false; } } /** * This function is a s9y plugin standard starter * sets $serendipity['GET']['subpage'] * * @return boolean */ function selected() { global $serendipity; if (!empty($serendipity['POST']['subpage'])) { $serendipity['GET']['subpage'] = $serendipity['POST']['subpage']; } if ($serendipity['GET']['subpage'] == $this->get_config('pagetitle') || preg_match('@^' . preg_quote($this->get_config('permalink')) . '@i', $serendipity['GET']['subpage'])) { return true; } return false; } /** * serendipity_plugin::generate_content * This function is used for sidebar plugins only * * @param string $title is somehow important to indicate the title of a plugin in the plugin configuration manager. */ function generate_content(&$title) { $title = PLUGIN_GUESTBOOK_TITLE.' (' . $this->get_config('pagetitle') . ')'; // do we need to set this to headline now? } /** * Generate backend configuration fields * * @param string $name field name * @param serendipity_property_bag $propbag properties * @return boolean */ function introspect_config_item($name, &$propbag) { global $serendipity; switch ($name) { case 'permalink': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_GUESTBOOK_PERMALINK); $propbag->add('description', PLUGIN_GUESTBOOK_PERMALINK_BLAHBLAH); $propbag->add('default', $serendipity['rewrite'] != 'none' ? $serendipity['serendipityHTTPPath'] . 'pages/guestbook.html' : $serendipity['serendipityHTTPPath'] . $serendipity['indexFile'] . '?/pages/guestbook.html'); break; case 'pagetitle': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_GUESTBOOK_PAGETITLE); $propbag->add('description', PLUGIN_GUESTBOOK_PAGETITLE_BLAHBLAH); $propbag->add('default', 'guestbook'); break; case 'headline': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_GUESTBOOK_HEADLINE); $propbag->add('description', PLUGIN_GUESTBOOK_HEADLINE_BLAHBLAH); $propbag->add('default', PLUGIN_GUESTBOOK_TITLE); break; case 'intro': $propbag->add('type', ($serendipity['wysiwyg'] === true ? 'html' : 'text')); $propbag->add('rows', 3); $propbag->add('name', PLUGIN_GUESTBOOK_INTRO); $propbag->add('description', ''); $propbag->add('default', ''); break; case 'formorder': $propbag->add('type', 'radio'); $propbag->add('name', PLUGIN_GUESTBOOK_FORMORDER); $propbag->add('description', PLUGIN_GUESTBOOK_FORMORDER_BLAHBLAH); $propbag->add('radio', array( 'value' => array('top', 'bottom'), 'desc' => array(PLUGIN_GUESTBOOK_FORMORDER_TOP, PLUGIN_GUESTBOOK_FORMORDER_BOTTOM, PLUGIN_GUESTBOOK_FORMORDER_POPUP) )); $propbag->add('default', 'top'); break; case 'numberitems': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_GUESTBOOK_NUMBER); $propbag->add('description', PLUGIN_GUESTBOOK_NUMBER_BLAHBLAH); $propbag->add('default', '10'); break; case 'maxitems': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_GUESTBOOK_NUMBER . ' (Backend)'); $propbag->add('description', PLUGIN_GUESTBOOK_NUMBER_BLAHBLAH); $propbag->add('default', '15'); break; case 'wordwrap': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_GUESTBOOK_WORDWRAP); $propbag->add('description', PLUGIN_GUESTBOOK_WORDWRAP_BLAHBLAH); $propbag->add('default', '120'); break; case 'markup': $propbag->add('type', 'boolean'); $propbag->add('name', PLUGIN_GUESTBOOK_ARTICLEFORMAT); $propbag->add('description', PLUGIN_GUESTBOOK_ARTICLEFORMAT_BLAHBLAH); $propbag->add('default', 'true'); break; case 'emailadmin': $propbag->add('type', 'boolean'); $propbag->add('name', PLUGIN_GUESTBOOK_EMAILADMIN); $propbag->add('description', PLUGIN_GUESTBOOK_EMAILADMIN_BLAHBLAH); $propbag->add('default', 'false'); break; case 'targetmail': $propbag->add('type', 'string'); $propbag->add('name', PLUGIN_GUESTBOOK_TARGETMAILADMIN); $propbag->add('description', PLUGIN_GUESTBOOK_TARGETMAILADMIN_BLAHBLAH); $propbag->add('default', ''); break; case 'showpage': $propbag->add('type', 'boolean'); $propbag->add('name', PLUGIN_GUESTBOOK_SHOWURL); $propbag->add('description', PLUGIN_GUESTBOOK_SHOWURL_BLAHBLAH); $propbag->add('default', 'false'); break; case 'showemail': $propbag->add('type', 'boolean'); $propbag->add('name', PLUGIN_GUESTBOOK_SHOWEMAIL); $propbag->add('description', PLUGIN_GUESTBOOK_SHOWEMAIL_BLAHBLAH); $propbag->add('default', 'true'); break; case 'showcaptcha': $propbag->add('type', 'boolean'); $propbag->add('name', PLUGIN_GUESTBOOK_SHOWCAPTCHA); $propbag->add('description', PLUGIN_GUESTBOOK_SHOWCAPTCHA_BLAHBLAH); $propbag->add('default', 'true'); break; case 'showapp': $propbag->add('type', 'boolean'); $propbag->add('name', PLUGIN_GUESTBOOK_SHOWAPP); $propbag->add('description', PLUGIN_GUESTBOOK_SHOWAPP_BLAHBLAH); $propbag->add('default', 'false'); break; case 'automoderate': $propbag->add('type', 'boolean'); $propbag->add('name', PLUGIN_GUESTBOOK_AUTOMODERATE); $propbag->add('description', PLUGIN_GUESTBOOK_AUTOMODERATE_BLAHBLAH); $propbag->add('default', 'false'); break; case 'entrychecks': $propbag->add('type', 'text'); $propbag->add('rows', 2); $propbag->add('name', PLUGIN_GUESTBOOK_FILTER_ENTRYCHECKS); $propbag->add('description', PLUGIN_GUESTBOOK_FILTER_ENTRYCHECKS_BLAHBLAH . ' ' . PLUGIN_GUESTBOOK_FILTER_ENTRYCHECKS_BYPASS); $propbag->add('default', $this->filter_defaults['words']); break; case 'dateformat': $propbag->add('type', 'string'); $propbag->add('name', GENERAL_PLUGIN_DATEFORMAT); $propbag->add('description', sprintf(GENERAL_PLUGIN_DATEFORMAT_BLAHBLAH, '%a, %m.%m.%Y %H:%M')); $propbag->add('default', '%a, %d.%m.%Y %H:%M'); break; default: break; } return true; } /** * Try to make email address printing safe (protect from spammers) * * @param string $string entry email checks * @return string */ function safeEmail($email) { global $serendipity; static $hide_email = null; if ($hide_email === null) { $hm = serendipity_db_query("SELECT * FROM {$serendipity['dbPrefix']}config WHERE name LIKE '%/hide_email'", true, 'assoc'); if (is_array($hm) && isset($hm['value'])) { $hide_email = serendipity_db_bool($hm['value']); } else { $hide_email = false; } } if ($hide_email && serendipity_userLoggedIn()) return 'nospam@example.com'; return str_replace(array('@', '.'), array(' at ', ' dot '), $email); } /** * Check if email is valid * * @param string $string entry email checks * @return mixed string/boolean */ function is_valid_email($postmail) { // Email needs to match this pattern to be a good email address if (!empty($postmail)) { return (preg_match( ":^([-!#\$%&'*+./0-9=?A-Z^_`a-z{|}~ ])+" . // the user name "@" . // the ubiquitous at-sign "([-!#\$%&'*+/0-9=?A-Z^_`a-z{|}~ ]+\\.)+" . // host, sub-, and domain names "[a-zA-Z]{2,6}\$:i", // top-level domain (TLD) trim($postmail))); // get rid of trailing whitespace } else return false; } /** * Check POST string if guestbooks content filter found something to strip * Adds match to $serendipity['messagestack']['comments'] array, if not in admin group * * @param string $string mostly entry body checks * @return boolean */ function strip_input($string) { global $serendipity; $stripped = strip_tags($string); $filter_bodys = explode(';', $this->get_config('entrychecks')); // filter string checks if not in admin group if (is_array($filter_bodys) && $serendipity['serendipityUserlevel'] < USERLEVEL_ADMIN) { foreach($filter_bodys AS $filter_body) { $filter_body = trim($filter_body); if (empty($filter_body)) { continue; } if (preg_match('@(' . $filter_body . ')@i', $stripped, $wordmatch)) { $serendipity['messagestack']['comments'][] = PLUGIN_EVENT_SPAMBLOCK_FILTER_WORDS . ': ' . $wordmatch[1]; return false; } } } else { return true; } } /** * guestbook wrapper for htmlspecialchars charset switch with PHP 5.4 * * @access public * @return string */ public static function html_specialchars($string, $flags = null, $encoding = LANG_CHARSET, $double_encode = true) { if ($flags == null) { if (defined('ENT_HTML401')) { // Added with PHP 5.4.x $flags = ENT_COMPAT | ENT_HTML401 | ENT_SUBSTITUTE; } else { // For PHP < 5.4 compatibility $flags = ENT_COMPAT; } } if ($encoding == 'LANG_CHARSET') { $encoding = 'UTF-8'; // fallback } return htmlspecialchars($string, $flags, $encoding, $double_encode); } /** * Strip and secure $serendipity['POST'] by keys and define modified array var if value has changed * No need for trim(strip_tags()) here, while this changes length and is further on done on output separately! * * @param mixed $parr array or string depending on $single * @param array $keys array of keys only * @param boolean $single loop array or return string * @param boolean $compare allow is stripped by key note * @return mixed array $serendipity['POST'] or single string */ function strip_security($parr = null, $keys = null, $single = false, $compare = true) { $authenticated_user = serendipity_userLoggedIn() ? true : false; if ($single) { return $authenticated_user ? $this->html_specialchars($parr) : $this->html_specialchars(strip_tags($parr)); } else { // POST data input check foreach ($parr AS $k => $v) { if (in_array($k, $keys)) { $valuelength = strlen($v); #$parrsec[$k] = $authenticated_user ? $this->html_specialchars($v) : $this->html_specialchars(strip_tags($v));//dont store entities $parrsec[$k] = $authenticated_user ? $v : strip_tags($v); if (!$authenticated_user && $compare && ($valuelength != strlen($parrsec[$k]))) { $parrsec['stripped'] = true; $parrsec['stripped-by-key'] = $k; } } else $parrsec[$k] = $v; } return $parrsec; } } /** * BBCode replacements * old preg_replace had issues with whitespaces * * @param string $string entry comment replacements * @return string */ function text_pattern_bbc($text) { $pattern = array('[b]', '[/b]', '[u]', '[/u]', '[i]', '[/i]', '[s]', '[/s]', '[q]', '[/q]', '[ac]', '[/ac]'); $replacement = array('', '', '', '', '', '', '', '', '', '', '

', '

'); return str_replace($pattern, $replacement, $text); } /** * BBCode reverse * * @param string $string entry comment replacements * @return string */ public static function bbc_reverse($text) { $pattern = '|[[\/]*?[^\[\]]*?]|si'; $replace = ''; return preg_replace($pattern, $replace, $text); } /** * Cut string between two other strings * * @param string $str given string * @param string $from left string for cutting * @param string $to right string for cutting * @return string cut part */ function cut_string($str, $from, $to){ $start = strpos($str,$from) + strlen($from); if (strpos($str,$from) === false) return false; $length = strpos($str,$to,$start) - $start; if (strpos($str,$to,$start) === false) return false; return substr($str,$start,$length); } /** * Set frontend pagination to global var * * @param int $c counted entries * @param boolean $ap approved yes/no = 1/0 * @param string $pname frontend Url with ? or & depending mod_rewrite settings * @param int $maxpp max entries per page * @return array $entries */ function frontend_guestbook_paginator($c, $ap, $pname, $maxpp) { global $serendipity; if (isset($serendipity['GET']['guestbooklimit'])) { $paginator = (int)$serendipity['GET']['guestbooklimit']; } else { $paginator = 1; } if (!isset($maxpp) && !is_numeric($maxpp)) $maxpp = 15; $lastpage = ceil($c/$maxpp); $paginator = (int)$paginator; if ($paginator > $lastpage) { $paginator = $lastpage; } if ($paginator < 1) { $paginator = 1; } $cp = ($paginator - 1); $rp = $maxpp; $entries = $this->getEntriesDB($cp, $rp, $ap); if (is_array($entries)) { $serendipity['guestbook']['paginator'] = ''; $serendipity['guestbook']['paginator'] .= '
'; if ($paginator == 1) { $serendipity['guestbook']['paginator'] .= ' FIRST | PREVIOUS '."\n"; } else { $prevpage = $paginator-1; $serendipity['guestbook']['paginator'] .= ''; $serendipity['guestbook']['paginator'] .= ' | '."\n"; $serendipity['guestbook']['paginator'] .= ' '."\n"; $serendipity['guestbook']['paginator'] .= ''; } $serendipity['guestbook']['paginator'] .= ' ( ' . PAGINATOR_PAGE . ' ' . $paginator . ' ' . PAGINATOR_OFFSET . ' ' . $lastpage . ' ) '."\n"; if ($paginator == $lastpage) { $serendipity['guestbook']['paginator'] .= ' NEXT | LAST '."\n"; } else { $nextpage = $paginator+1; $serendipity['guestbook']['paginator'] .= ''; $serendipity['guestbook']['paginator'] .= ' | '."\n"; $serendipity['guestbook']['paginator'] .= ' '."\n"; $serendipity['guestbook']['paginator'] .= ''; } $serendipity['guestbook']['paginator'] .= '
'; $serendipity['guestbook']['paginator'] .= "\n"; } return is_array($entries) ? $entries : false; } // function frontend paginator end /** * Generate entries checks * * @param array $entries given string * @param string $is_guestbook_ url create url * @param int $wordwrap linebreak * @param bool $backend_escape * @return array $entries for output */ function generate_EntriesArray($entries, $is_guestbook_url, $wordwrap, $backend_escape = false) { global $serendipity; // this assigns db entries output to guestbooks smarty entries.tpl if (is_array($entries)) { foreach($entries AS $i => $entry) { // entry items $entry['email'] = $this->strip_security($this->safeEmail($entry['email']), null, true); $entry['name'] = $this->strip_security($entry['name'], null, true); $entry['homepage'] = !empty($entry['homepage']) && strpos($entry['homepage'],'http://') !== 0 && strpos($entry['homepage'],'https://') !== 0 ? 'http://' . $this->strip_security($entry['homepage'], null, true) : $this->strip_security($entry['homepage'], null, true); $entry['pluginpath'] = $serendipity['serendipityHTTPPath'] . $serendipity['guestbook']['pluginpath']; $entry['timestamp'] = strftime($this->get_config('dateformat'), (int)$entry['timestamp']); // mysql would use SELECT *, FROM_UNIXTIME(timestamp) AS ts FROM `s9y_guestbook` $entry['page'] = $is_guestbook_url . (($serendipity['rewrite'] == 'rewrite') ? '?' : '&') . 'noclean=true&serendipity[adminAction]=guestbookdelete&serendipity[page]=' . (int)$serendipity['GET']['page'] . '&serendipity[gbid]=' . $entry['id']; // authenticated user admincomment is not escaped - do not wordwrap this part (since it could cause undetermined string errors, etc) $placeholder_ac = '[[$ac]]'; $replace_ac = $this->cut_string($entry['body'], '[ac]', '[/ac]'); $stripped_body = $this->strip_security($entry['body'], null, true); $search_ac = $this->cut_string($stripped_body, '[ac]', '[/ac]'); $entry['body'] = str_replace($search_ac, $placeholder_ac, $stripped_body); if (serendipity_db_bool($this->get_config('markup'))) { // parse $entry['text'] through hook events standard formatting and smilies $markup = array('body' => $entry['body']); serendipity_plugin_api::hook_event('frontend_display', $markup, 'body'); $entry['body'] = wordwrap($markup['body'], $wordwrap, "\n", 1); } else { $entry['bodywrap'] = wordwrap($entry['body'], $wordwrap, "\n", 1); $entry['body'] = nl2br($entry['bodywrap']); } if ($backend_escape) { $replace_ac = $this->html_specialchars($replace_ac); // do not allow in backend, eg unescaped scripts } $entry['body'] = str_replace($placeholder_ac, $replace_ac, $entry['body']); $entry['body'] = $this->text_pattern_bbc($entry['body']); $entries[$i] = $entry; } } return is_array($entries) ? $entries : false; } /** * Insert guestbook entry into database and send mail * * @param int $id * @param string $ip * @param string $name * @param string $url * @param string $email * @param string $body * @param int $app approved * @param int $ts timestamp * @param boolean $old Insert/Replace * @return boolean */ function insertEntriesDB($id=false, $ip=false, $name, $url, $email, $body, $app=false, $ts=false, $old=false) { global $serendipity; // make php to current unix timestamp to insert into db $ip = isset($ip) ? $ip : serendipity_db_escape_string($_SERVER['REMOTE_ADDR']); $app = isset($app) ? (int)$app : (serendipity_db_bool($this->get_config('showapp')) ? 0 : 1); $ts = isset($ts) ? $ts : time(); $name = serendipity_db_escape_string(substr($name, 0, 29)); $url = serendipity_db_escape_string(substr($url, 0, 99)); $email = serendipity_db_escape_string(substr($email, 0, 99)); $body = serendipity_db_escape_string($body); if ($old === false) { // normal setting $sql = sprintf("INSERT INTO %sguestbook ( ip, name, homepage, email, body, approved, timestamp ) VALUES ( '%s', '%s', '%s', '%s', '%s', %s, %s)", $serendipity['dbPrefix'], $ip, $name, $url, $email, $body, $app, $ts ); } else { // replace settings $sql = "REPLACE {$serendipity['dbPrefix']}guestbook SET id=$id, ip='$ip', name='$name', homepage='$url', email='$email', body='$body', approved='$app', timestamp='$ts'"; } $dbdone = serendipity_db_query($sql, true, 'both', true); if ($dbdone) { // if set, send an Email to the Admin $serendipity['email'] if (!serendipity_db_bool($this->get_config('emailadmin'))) { return false; } elseif (!$this->get_config('targetmail') || $this->get_config('targetmail') != '') { $headers[] = 'X-SentBy: Serendipity Guestbook'; $headers[] = 'X-Priority: 2'; // prevent sent emails $headers[] = 'X-MSmail-Priority: high'; // treated as junk mails $body = str_replace(array('\r\n','\n'), "\n", $body); // without search = single and replace = double quotes, this won't work!!! // does $serendipity['csuccess'] ever return to be moderate? if (serendipity_db_bool($this->get_config('showapp')) === false && ($app == 0 || $serendipity['csuccess'] == 'moderate')) { $body = $body . sprintf(TEXT_EMAILMODERATE, $serendipity['moderate_reason']); } return @serendipity_sendMail($this->get_config('targetmail'), TEXT_EMAILSUBJECT, sprintf(TEXT_EMAILTEXT,$name, $body, TEXT_EMAILFOOTER), $email, $headers, $name); } return true; } } /** * Guestbook entries count db * * @param int $ap approved * @return mixed boolean/int */ function countEntriesDB($ap) { global $serendipity; $whe = (serendipity_db_bool($this->get_config('showapp')) || serendipity_db_bool($this->get_config('automoderate'))) ? "WHERE approved=$ap" : ''; // count guestbook entries to make entries paging $sql = "SELECT count(*) AS counter FROM {$serendipity['dbPrefix']}guestbook $whe"; $maxres = serendipity_db_query($sql, true); return is_array($maxres) ? $maxres : false; } /** * Guestbook Select entries * * @param int $cp limit from * @param int $rp limit to * @param int $ap approved * @return mixed boolean/array $entries */ function getEntriesDB($cp, $rp, $ap) { global $serendipity; $whe = (serendipity_db_bool($this->get_config('showapp')) || serendipity_db_bool($this->get_config('automoderate'))) ? "WHERE approved=$ap" : ''; // generate guestbook entries and send them to entries template $sql = "SELECT * FROM {$serendipity['dbPrefix']}guestbook $whe ORDER BY timestamp DESC "; $entries = serendipity_db_query($sql . serendipity_db_limit_sql( serendipity_db_limit( $cp * $rp, $rp ) ), false, 'assoc' ); return is_array($entries) ? $entries : false; } /** * Guestbook form submit POST checks, validate & insert into db * * @return boolean on error */ function checkSubmit() { global $serendipity; global $messages; if (!is_array($messages)) { $messages = array(); } $valid['captcha'] = FALSE; $valid['data_length'] = FALSE; $valid['data_email'] = FALSE; $valid['message'] = FALSE; $serendipity['guestbook_message_header'] = FALSE; $authenticated_user = serendipity_userLoggedIn() ? true : false; $gb_automoderate = serendipity_db_bool($this->get_config('automoderate'), false); if (empty($serendipity['POST']['guestbookform'])) { return false; } if (!isset($serendipity['POST']['email']) || empty($serendipity['POST']['email'])) { $serendipity['POST']['email'] = 'nospam@example.com'; } if (empty($serendipity['POST']['name']) && empty($serendipity['POST']['email']) && empty($serendipity['POST']['comment'])) { array_push($messages, PLUGIN_GUESTBOOK_MESSAGE . ': ' . PLUGIN_GUESTBOOK_ERROR_DATA . ' - ' . ERROR_NOINPUT); return false; } if (!$serendipity['POST']['email'] || !$serendipity['POST']['name'] || !$serendipity['POST']['comment']) { array_push($messages, ERROR_NOINPUT); return false; } // do not allow non logged-in manual BBCode in comments if (!$authenticated_user) { $serendipity['POST']['comment'] = $this->bbc_reverse($serendipity['POST']['comment']); } // find Spamblock global set force auto moderation if ($hit = preg_grep("|/forcemoderation_treat|i", array_keys($serendipity))) { $forcemoderate = array_values($hit); } // if force moderate is set to moderate, advice security to not support 'stripped' or 'stripped-by-key' POST mark // this does only happen true, if not automoderate is set in both plugins and strip tags really removed some tags. if (isset($serendipity[$forcemoderate[0]]) == 'moderate' && $gb_automoderate === true) { $serendipity['POST'] = $this->strip_security($serendipity['POST'], array('name', 'email', 'comment', 'admincomment', 'url'), false, false); } else { $serendipity['POST'] = $this->strip_security($serendipity['POST'], array('name', 'email', 'comment', 'admincomment', 'url')); } if ($serendipity['POST']['stripped'] === true) { array_push($messages, ERROR_OCCURRED . '
' . ERROR_DATASTRIPPED); return false; } // Fake call to spamblock and other comment plugins, if not in backend. $ca = array( 'id' => 0, 'allow_comments' => true, /* 'moderate_comments' => true, dont use here, while it overrides spamblock option setting */ 'last_modified' => time(), 'timestamp' => strtotime("-8 day" ,time()) // remember captchas_ttl using 7 days as normal setting, just 10 sec. throws Moderation after X days ); if (!is_numeric($_POST['guestbook']['id'])) { $commentInfo = array( 'type' => 'NORMAL', 'source' => 'guestbookform', 'name' => $serendipity['POST']['name'], 'email' => $serendipity['POST']['email'], 'url' => $serendipity['POST']['url'], 'comment' => $serendipity['POST']['comment'] ); serendipity_plugin_api::hook_event('frontend_saveComment', $ca, $commentInfo); } // End of fake call. // listen to Spamblock Plugin and do some specific guestbook checks, if captcha and entry were allowed if (serendipity_db_bool($ca['allow_comments']) === true) { if (trim($serendipity['POST']['name']) == '') { array_push($messages, ERROR_NAMEEMPTY); } if (isset($serendipity['POST']['url'])) { $serendipity['POST']['url'] = trim($serendipity['POST']['url']); } if (trim($serendipity['POST']['comment']) == '') { array_push($messages, ERROR_TEXTEMPTY); } if (trim($serendipity['POST']['email']) == '') { array_push($messages, ERROR_EMAILEMPTY); } if (strlen(trim($serendipity['POST']['name'])) < 3 || strlen(trim($serendipity['POST']['comment'])) < 10) { array_push($messages, ERROR_DATATOSHORT); } else { $valid['data_length'] = TRUE; } if ($this->strip_input($serendipity['POST']['comment']) === false) { array_push($messages, ERROR_DATANOTAGS . ' ' . $serendipity['messagestack']['comments'][0]); if (!empty($serendipity['messagestack']['comments'][0])) { unset($serendipity['messagestack']['comments']); } } if (isset($serendipity['POST']['email']) && !empty($serendipity['POST']['email']) && trim($serendipity['POST']['email']) != '') { if (!$this->is_valid_email($serendipity['POST']['email'])) { array_push($messages, ERROR_NOVALIDEMAIL . ' ' . $this->html_specialchars($serendipity['POST']['email']) . ''); } else { $valid['data_email'] = TRUE; } } if (isset($serendipity['POST']['captcha']) && !empty($serendipity['POST']['captcha'])) { if (serendipity_db_bool($ca['allow_comments']) === true || strtolower($serendipity['POST']['captcha']) == strtolower($_SESSION['spamblock']['captcha'])) { $valid['captcha'] = TRUE; } elseif (!$authenticated_user) { if ($serendipity['csuccess'] != 'moderate') { array_push($messages, ERROR_ISFALSECAPTCHA); }/* else { array_push($messages, $serendipity['moderate_reason'] . PLUGIN_GUESTBOOK_AUTOMODERATE_ERROR . PLUGIN_GUESTBOOK_DBDONE_APP); }*/ } } // Captcha checking - if set to FALSE in guestbook config and spamblock plugin catchas is set to no, follow db insert procedure if (!serendipity_db_bool($this->get_config('showcaptcha'))) { if (!isset($_SESSION['spamblock']['captcha']) || !isset($serendipity['POST']['captcha']) || strtolower($serendipity['POST']['captcha']) != strtolower($_SESSION['spamblock']['captcha'])) { $valid['captcha'] = TRUE; } } if ($authenticated_user && $_SESSION['serendipityAuthedUser'] === true) { $valid['captcha'] = TRUE; $valid['data_length'] = TRUE; $valid['data_email'] = TRUE; } // spamblock allows comments end } else { // drop entry back to form - beware 'allow_comments' return value is empty, not false, if false array_push($messages, PLUGIN_GUESTBOOK_MESSAGE . ': ' . PLUGIN_GUESTBOOK_ERROR_DATA); } // set valid messages to true, if no errors occured $valid['message'] = (count($messages) < 1) ? TRUE : FALSE; // no errors and messages if ($valid['message'] === true) { // set var, if not set by backend form if (!is_numeric($_POST['guestbook']['approved'])) $_POST['guestbook']['approved'] = ''; if (is_numeric($_POST['guestbook']['id'])) $_POST['guestbook']['approved'] = 1; /*** Allow the spamblock plugin wordfilter to set an entry as non-approved, accordingly to stopwords and content filter set to 'moderation' in spamblock plugin. Extends new auto-moderate option setting to true in guestbooks config ***/ // keep this for future finetuning via SPAMBLOCK plugin if (array_key_exists('moderate_comments', $ca)) { if (serendipity_db_bool($ca['moderate_comments']) === true && $gb_automoderate === true) { // set entries to get approved in backend, before they can appear in frontent $_POST['guestbook']['approved'] = 0; } } } // write new entry into database, if input is valid if (!empty($serendipity['POST']['guestbookform']) && $valid['captcha'] === true && $valid['data_length'] === true && $valid['data_email'] === true && $valid['message'] === true) { $admincomment = (!empty($serendipity['POST']['admincomment'])) ? '[ac] ' . $serendipity['POST']['admincomment'] . ' [/ac]' : ''; $acapp = ($authenticated_user && $_SESSION['serendipityAuthedUser'] === true) ? 1 : NULL; $acapp = is_numeric($_POST['guestbook']['approved']) ? $_POST['guestbook']['approved'] : $acapp; if (is_numeric($_POST['guestbook']['id'])) { // update validated form values into db $this->insertEntriesDB($_POST['guestbook']['id'], $_POST['guestbook']['ip'], $serendipity['POST']['name'], $serendipity['POST']['url'], $serendipity['POST']['email'], $serendipity['POST']['comment'].$admincomment, $_POST['guestbook']['approved'], $_POST['guestbook']['timestamp'], true); } else { // insert validated form values into db $this->insertEntriesDB(NULL, NULL, $serendipity['POST']['name'], $serendipity['POST']['url'], $serendipity['POST']['email'], $serendipity['POST']['comment'], $acapp, NULL, false); } // claim insertEntriesDB is true $showapp = serendipity_db_bool($this->get_config('showapp')); $showapptxt = ($showapp && !$authenticated_user) ? ' ' . PLUGIN_GUESTBOOK_DBDONE_APP : ''; if (!$authenticated_user) { // be strict here, since it could also be NULL if (($showapp === false && $acapp === 0) || $serendipity['csuccess'] == 'moderate') { if (isset($serendipity[$forcemoderate[0]]) == 'moderate') { $showapptxt = '
' . $serendipity['moderate_reason'] . '
' . PLUGIN_GUESTBOOK_AUTOMODERATE_ERROR . PLUGIN_GUESTBOOK_DBDONE_APP; } } } // this is a success msg! array_push($messages, PLUGIN_GUESTBOOK_MESSAGE . ': ' . PLUGIN_GUESTBOOK_DBDONE . $showapptxt); // flag global meassage header to have successfully checked and saved the entry $serendipity['guestbook_message_header'] = true; // reset post values unset($serendipity['POST']); unset($_POST); // set startpage back to 1 $serendipity['GET']['page'] = 1; if ($serendipity['guestbook_message_header'] === false) { array_push($messages, PLUGIN_GUESTBOOK_UNKNOWN_ERROR); return false; } } } // checkSubmit() validate & insert into db end /** * Guestbook create output page assignment and fetch template file * * @return boolean on error */ function generate_Page() { global $serendipity; global $messages; if ($this->selected()) { if (!is_array($messages)) { $messages = array(); } if (!headers_sent()) { header('HTTP/1.0 200'); header('Status: 200 OK'); } // case export mysql dump file - and send to external_plugin hook if ($_POST['guestbook']['bedownload']) { $url = $_POST['guestbook']['bedownload']; if ($url) header('Location: http://' . $_SERVER['HTTP_HOST'] . $url); } // Carl and Don wanted to access the staticpage_pagetitle $_ENV['staticpage_pagetitle'] = preg_replace('@[^a-z0-9]@i', '_',$this->get_config('pagetitle')); $_ENV['staticpage_headline'] = $this->get_config('headline'); $_ENV['staticpage_formorder'] = $this->get_config('formorder'); $serendipity['smarty']->assign( array( 'staticpage_headline' => $_ENV['staticpage_headline'], 'staticpage_pagetitle' => $_ENV['staticpage_pagetitle'], 'staticpage_formorder' => $_ENV['staticpage_formorder'] ) ); if (isset($serendipity['POST']['guestbookform']) == true) { // check form vars $this->checkSubmit(); if (count($messages) < 1 && $serendipity['guestbook_message_header'] === false) { array_push($messages, PLUGIN_GUESTBOOK_MESSAGE . ': ' . ERROR_UNKNOWN . '
' . ERROR_NOCAPTCHASET); } } // generate frontend admin header section - if user logged in and action is delete entry if (!empty ($serendipity['GET']['adminAction']) && $_SESSION['serendipityAuthedUser'] === true) { // use permalink generally instead of subpage $is_guestbook_url = ($serendipity['rewrite'] != 'errordocs') ? $this->get_config('permalink') : $serendipity['serendipityHTTPPath'] . $serendipity['indexFile'] . '?serendipity[subpage]=' . $this->get_config('pagetitle'); switch($serendipity['GET']['adminAction']) { case 'guestbookdelete': $serendipity['smarty']->assign( array( 'admin_delete' => true, 'admin_url' => $is_guestbook_url . (($serendipity['rewrite'] == 'rewrite') ? '?' : '&') . 'serendipity[page]=' . (int)$serendipity['GET']['page'], 'admin_target' => $is_guestbook_url . (($serendipity['rewrite'] == 'rewrite') ? '?' : '&') . 'serendipity[adminAction]=doDelete&serendipity[page]=' . (int)$serendipity['GET']['page'] . '&serendipity[gbid]=' . (int)$serendipity['GET']['gbid'], 'delete_sure' => sprintf(DELETE_SURE, (int)$serendipity['GET']['gbid']) ) ); break; case 'doDelete': $sql = sprintf("DELETE from %sguestbook WHERE id = %s", $serendipity['dbPrefix'], (int)$serendipity['GET']['gbid']); serendipity_db_query($sql); $url = $is_guestbook_url . (($serendipity['rewrite'] == 'rewrite') ? '?' : '&') . 'serendipity[page]=' . (int)$serendipity['GET']['page'] . '&serendipity[ripped]=' . (int)$serendipity['GET']['gbid'] . '#ripped'; header('Status: 302 Found'); header('Location: ' . $url); exit; break; default: #return false; break; } } if ((int)$serendipity['GET']['ripped']) { $serendipity['smarty']->assign( array( 'admin_dodelete' => true, 'rip_entry' => sprintf(RIP_ENTRY, (int)$serendipity['GET']['ripped']) ) ); } // call the form page output function $this->generate_EntriesPage(); $this->generate_FormPage(); // get the guestbook entries template file echo $this->parseTemplate('plugin_guestbook_entries.tpl'); } } // generate_Page end /** * Guestbook create form page assignment and fetch template file * */ function generate_FormPage() { global $serendipity; global $messages; if (serendipity_db_bool($this->get_config('showemail'))) { $serendipity['smarty']->assign('is_show_mail', true); } if (serendipity_db_bool($this->get_config('showpage'))) { $serendipity['smarty']->assign('is_show_url', true); } // assign form array entries to smarty $serendipity['smarty']->assign( array( 'plugin_guestbook_articleformat' => (serendipity_db_bool($this->get_config('markup')) ? true : false), 'plugin_guestbook_intro' => $this->get_config('intro'), 'plugin_guestbook_sent' => $this->get_config('sent', PLUGIN_GUESTBOOK_SENT_HTML), 'plugin_guestbook_action' => $serendipity['baseURL'] . $serendipity['indexFile'], 'plugin_guestbook_sname' => $this->html_specialchars($serendipity['GET']['subpage']), 'plugin_guestbook_name' => $this->html_specialchars(strip_tags($serendipity['POST']['name'])), 'plugin_guestbook_email' => $this->html_specialchars(strip_tags($serendipity['POST']['email'])), 'plugin_guestbook_emailprotect' => PLUGIN_GUESTBOOK_PROTECTION, 'plugin_guestbook_url' => $this->html_specialchars(strip_tags($serendipity['POST']['url'])), 'plugin_guestbook_comment' => $this->html_specialchars(strip_tags($serendipity['POST']['comment'])), 'plugin_guestbook_messagestack' => $serendipity['messagestack']['comments'], 'plugin_guestbook_entry' => array('timestamp' => 1) ) ); // get the form page template file $conform = $this->parseTemplate('plugin_guestbook_form.tpl'); $serendipity['smarty']->assign('GUESTBOOK_FORM', $conform); } // generate_FormPage() end /** * Guestbook generate entries page assignment * * @param int $ap approved * */ function generate_EntriesPage($ap=1) { global $serendipity; global $messages; if (!is_array($messages)) { $messages = array(); } // max entries per page $max_entries = $this->get_config('numberitems'); if (!is_numeric($max_entries)) { $max_entries = 5; } $wordwrap = $this->get_config('wordwrap'); if (!is_numeric($wordwrap)) { $wordwrap = 50; } // use permalink generally instead of subpage $is_guestbook_url = ($serendipity['rewrite'] != 'errordocs') ? $this->get_config('permalink') : $serendipity['serendipityHTTPPath'] . $serendipity['indexFile'] . '?serendipity[subpage]=' . $this->get_config('pagetitle'); // if entry send is ok OR user just views guestbook entries :: run SQL if ($serendipity['guestbook_message_header'] === true || empty($serendipity['POST']['guestbookform'])) { // count db entries as array: [$maxres] $maxres = $this->countEntriesDB($ap); $url = $is_guestbook_url . (($serendipity['rewrite'] == 'rewrite') ? '?' : '&'); // generate $entries array and frontend pagination $entries = is_array($maxres) ? $this->frontend_guestbook_paginator($maxres[0], $ap, $url, $max_entries) : false; // this assigns $entries and paging output to plugin_guestbooks_entries.tpl $serendipity['smarty']->assign(array( 'guestbook_entry_paging' => true, 'guestbook_userLoggedIn' => false, // keep var for old user templates 'guestbook_paging' => $serendipity['guestbook']['paginator'] )); } $serendipity['smarty']->assign('is_guestbook_url', $is_guestbook_url); // this assigns db entries output to guestbooks frontend smarty array: [$entries] in plugin_guestbook_entries.tpl $entries = $this->generate_EntriesArray($entries, $is_guestbook_url, $wordwrap); // Output all possible messages and errors if (is_array($messages) && count($messages) > 0) { $serendipity['smarty']->assign( array( 'is_guestbook_message' => true, 'error_occured' => ERROR_OCCURRED ) ); if ($serendipity['guestbook_message_header'] === true) { $serendipity['smarty']->assign( array( 'is_guestbook_message' => true, 'error_occured' => THANKS_FOR_ENTRY ) ); } } if ($serendipity['guestbook_message_header'] === true || empty($serendipity['POST']['guestbookform'])) { // assign entries array and good messages array to smarty - beware just using smarty {entries}, it is used by default! $serendipity['smarty']->assign( array( 'guestbook_messages' => $messages, 'guestbook_entries' => $entries ) ); } else { // assign bad messages array to smarty $serendipity['smarty']->assign( array( 'guestbook_messages' => $messages ) ); } } // function generate_EntriesPage() end /** * Hook for Serendipity events, initialize plug-in features * * @param string $event * @param serendipity_property_bag $bag * @param array $eventData * @param array $addData * @return boolean */ function event_hook($event, &$bag, &$eventData, $addData = null) { global $serendipity; $hooks = &$bag->get('event_hooks'); $serendipity['plugin_guestbook_version'] = &$bag->get('version'); // set global plugin path setting, to avoid different pluginpath '/plugins/' as plugins serendipity vars if (!isset($serendipity['guestbook']['pluginpath'])) { $pluginpath = pathinfo(dirname(__FILE__)); $serendipity['guestbook']['pluginpath'] = basename(rtrim($pluginpath['dirname'], '/')) . '/serendipity_event_guestbook/'; } if (isset($hooks[$event])) { switch($event) { case 'frontend_configure': // checking if db tables exists, otherwise install them $cur = ''; $old = $this->get_config('version', '', false); if ($old == '1.0') $cur = $old; if (empty($cur) && ( !empty($old) || ($old == '' && $old != false) )) { $cur = '2.0'; } else { $cur = $this->get_config('dbversion'); } if ($cur == '1.0') { $this->alter_db($cur); $this->set_config('dbversion', '2.0'); } elseif ($cur == '2.0') { $this->alter_db($cur); $this->set_config('dbversion', '3.0'); $this->cleanup(); } elseif ($cur == '3.0') { $this->alter_db($cur); $this->set_config('dbversion', '4'); } elseif ($cur == '4') { $this->alter_db($cur); $this->set_config('dbversion', '5'); } elseif ($cur == '5') { continue; } else { $this->install(); $this->set_config('dbversion', '5'); } break; case 'genpage': $args = implode('/', serendipity_getUriArguments($eventData, true)); if ($serendipity['rewrite'] != 'none') { $nice_url = $serendipity['serendipityHTTPPath'] . $args; } else { $nice_url = $serendipity['serendipityHTTPPath'] . $serendipity['indexFile'] . '?/' . $args; } if (empty($serendipity['GET']['subpage'])) { $serendipity['GET']['subpage'] = $nice_url; } if ($this->selected()) { $serendipity['head_title'] = $this->get_config('headline'); $serendipity['head_subtitle'] = $this->html_specialchars($serendipity['blogTitle']); } break; case 'entry_display': if ($this->selected()) { // This is important to not display an entry list! if (is_array($eventData)) { $eventData['clean_page'] = true; } else { $eventData = array('clean_page' => true); } } break; case 'entries_header': // this one really rolls up output: check form submit, generate entries and form $this->generate_Page(); break; case 'external_plugin': // [0]=guestbookdlsql; [1]=filename; $gb['export'] = explode('/', $eventData); if ($gb['export'][0] == 'guestbookdlsql') { $file = file_get_contents ($serendipity['serendipityPath'] . 'templates_c/guestbook/'.$gb['export'][1]); echo $file; header('Status: 302 Found'); header('Content-Type: application/octet-stream; charset=UTF-8'); // text/plain to see as file in browser header('Content-Disposition: inline; filename='.$gb['export'][1]); } break; // put here all you css stuff you need for frontend guestbook pages case 'css': if (stristr($eventData, '#guestbook_wrapper')) { // class exists in CSS, so a user has customized it and we don't need default return true; } $tfile = serendipity_getTemplateFile('style_guestbook_frontend.css', 'serendipityPath'); if ($tfile) { $search = array('{TEMPLATE_PATH}', '{PLUGIN_PATH}'); $replace = array('templates/' . $serendipity['template'] . '/', $serendipity['guestbook']['pluginpath']); $tfilecontent = str_replace($search, $replace, @file_get_contents($tfile)); } if (!$tfile || $tfile == 'style_guestbook_frontend.css') { $tfile = dirname(__FILE__) . '/style_guestbook_frontend.css'; $search = array('{TEMPLATE_PATH}', '{PLUGIN_PATH}'); $tfilecontent = str_replace($search, $serendipity['guestbook']['pluginpath'], @file_get_contents($tfile)); } if (!empty($tfilecontent)) { $this->cssEventData($eventData, $tfilecontent); } break; case 'backend_sidebar_entries': // forbid sidebar link if user is not in admin group level if ($serendipity['serendipityUserlevel'] < USERLEVEL_ADMIN) { return false; } if ($serendipity['version'][0] < 2) { echo "\n".' '."\n"; } break; case 'backend_sidebar_admin_appearance': // forbid sidebar link if user is not in admin group level if ($serendipity['serendipityUserlevel'] < USERLEVEL_ADMIN) { return false; } if ($serendipity['version'][0] > 1) { echo "\n".'
  • ' . PLUGIN_GUESTBOOK_ADMIN_NAME . '
  • '."\n"; } break; case 'backend_sidebar_entries_event_display_guestbook': // forbid entry access if user is not in admin group level if ($serendipity['serendipityUserlevel'] < USERLEVEL_ADMIN) { return false; } // show backend administration menu $this->gbadminpanel(); break; // put here all you css stuff you need for the backend of guestbook pages case 'css_backend': if (stristr($eventData, '#wrapGB')) { // class exists in CSS, so a user has customized it and we don't need default return true; } $tfile = serendipity_getTemplateFile('style_guestbook_backend.css', 'serendipityPath'); if ($tfile) { $search = array('{TEMPLATE_PATH}', '{PLUGIN_PATH}'); $replace = array('templates/' . $serendipity['template'] . '/', $serendipity['guestbook']['pluginpath']); $tfilecontent = str_replace($search, $replace, @file_get_contents($tfile)); } if ( (!$tfile || $tfile == 'style_guestbook_backend.css') && !$tfilecontent) { $tfile = dirname(__FILE__) . '/style_guestbook_backend.css'; $search = array('{TEMPLATE_PATH}', '{PLUGIN_PATH}'); $tfilecontent = str_replace($search, $serendipity['guestbook']['pluginpath'], @file_get_contents($tfile)); } // overwrite Serendipity 1.7 .serendipityAdminContent span !important if ($serendipity['version'][0] < '2') { ?> #wrapGB .gb_entryhead span {color: #CCDDE7 !important;} #wrapGB .gb_entrybody span {color: #222 !important;} #wrapGB .msg_error, #wrapGB .msg_success, #wrapGB .msg_notice, #wrapGB .msg_hint { display: block; margin: 1.5em 0; padding: .5em; } #wrapGB .msg_error { background: #f2dede; border: 1px solid #e4b9b9; color: #b94a48; } #wrapGB .msg_success { background: #dff0d8; border: 1px solid #c1e2b3; color: #468847; } #wrapGB .msg_notice { background: #fcf8e3; border: 1px solid #fbeed5; color: #c09853; } #wrapGB .msg_hint { background: #eee; border: 1px solid #aaa; color: #777; } cssEventData($eventData, $tfilecontent); } break; default: break; } } else { return false; } } /*************************************************** * Backend administration functions **************************************************/ /** * Add front- and backend css to serendipity(_admin).css * * @param array $eventData * @param array $addData * */ function cssEventData(&$eventData, &$becss) { $eventData .= $becss; } /** * Main admin backend function * * switch to selected navigation parts of $serendipity['GET']['guestbookcategory'] * parts: view, add, approve, admin panel * */ function gbadminpanel() { global $serendipity; global $messages; if (!is_object($serendipity['smarty'])) { serendipity_smarty_init(); } $moderate = (serendipity_db_bool($this->get_config('showapp')) || serendipity_db_bool($this->get_config('automoderate'))) ? true : false; $gbcat = !empty($serendipity['GET']['guestbookcategory']) ? $serendipity['GET']['guestbookcategory'] : $serendipity['POST']['guestbookcategory']; if (!isset($serendipity['POST']['guestbookadmin'])) { $serendipity['smarty']->assign( array( 'gb_liva' => (!isset($serendipity['GET']['guestbookcategory']) || $serendipity['GET']['guestbookcategory'] == 'gbview') ? ' id="active"' : '', 'gb_liapa' => ($serendipity['GET']['guestbookcategory'] == 'gbapp' || $serendipity['POST']['guestbook_category'] == 'gbapp') ? ' id="active"' : '', 'gb_liada' => (($serendipity['GET']['guestbookcategory'] == 'gbadd' || $serendipity['POST']['guestbookcategory'] == 'gbadd') && $serendipity['POST']['guestbook_category'] != 'gbapp') ? ' id="active"' : '', 'gb_lida' => $serendipity['GET']['guestbookcategory'] == 'gbdb' ? ' id="active"' : '', 'gb_moderate' => $moderate, 'gb_isnav' => true ) ); } // assign form array entries to smarty $serendipity['smarty']->assign( array( 'plugin_guestbook_backend_path' => $_SERVER['PHP_SELF'] . '?serendipity[adminModule]=event_display&serendipity[adminAction]=guestbook&serendipity[guestbookcategory]=gbadd', 'is_guestbook_admin_noapp' => true ) ); // check for REQUESTS, approve, re-edit, remove from database table switch($gbcat) { case 'gbview': default: $serendipity['smarty']->assign('gb_view', true); // view all approved(1) entries in a table $ve = $this->backend_guestbook_view(1, 'gbview'); if ($ve === false) { $serendipity['smarty']->assign('is_gbadmin_noviewresult', true); } break; case 'gbapp': if ($moderate === true) { $serendipity['smarty']->assign('gb_app', true); // view all unapproved(0) entries in a table $this->backend_guestbook_moderate(); } break; case 'gbadd': $entry = $this->backend_request_checks(); if (!isset($serendipity['guestbook_message_header']) && isset($serendipity['POST']['guestbookform']) !== true) { $serendipity['smarty']->assign('gb_add', true); } if (isset($serendipity['POST']['guestbookform']) === true) { // set a guestbook backend header to submit without frontend checks $serendipity['guestbook_backend_header'] = true; // check form vars $this->checkSubmit(); } // HÄH????? if ($serendipity['guestbook_message_header'] === true) { if (count($messages) < 1 && $serendipity['guestbook_message_header'] === false) { array_push($messages, PLUGIN_GUESTBOOK_MESSAGE . ': ' . ERROR_UNKNOWN . '
    ' . ERROR_NOCAPTCHASET); } $error_occured = ($serendipity['guestbook_message_header'] === true) ? THANKS_FOR_ENTRY : ERROR_OCCURRED; if ($moderate === true && $serendipity['POST']['guestbook_category'] == 'gbapp') { $serendipity['smarty']->assign(array('gb_gbadd_approve' => true, 'msg_header' => $error_occured, 'guestbook_messages' => $messages)); // came from moderation table view and goes back $this->backend_guestbook_moderate(); } else { $serendipity['smarty']->assign(array('gb_gbadd_view' => true, 'msg_header' => $error_occured, 'guestbook_messages' => $messages)); // view all approved entries in a table $ve = $this->backend_guestbook_view(1, 'gbview'); if ($ve === false) $serendipity['smarty']->assign('is_gbadmin_noviewresult', true); } } else { // fallback to new ENTRY FORM, since there was an error - no need to escape if ($serendipity['guestbook_message_header'] === false ) { foreach($serendipity['POST'] as $sk => $sv) { $entry[$sk] = $sv; } foreach($_POST['guestbook'] as $gk => $gv) { $entry[$gk] = $gv; } $entry['body'] = $entry['comment']; $serendipity['smarty']->assign(array('gb_gbadd_add' => true, 'msg_header' => $error_occured, 'guestbook_messages' => $messages)); } if (serendipity_db_bool($this->get_config('showemail'))) { $serendipity['smarty']->assign('is_show_mail', true); } if (serendipity_db_bool($this->get_config('showpage'))) { $serendipity['smarty']->assign('is_show_url', true); } // extract entry bodys admincomment to var preg_match_all("/\[ac\](.*?)\[\/ac\]/", $entry['body'], $match); $entry['acbody'] = $match[1][0]; $entry['body'] = preg_replace("/\[ac\](.*?)\[\/ac\]/","", $entry['body']); // assign form array entries to smarty $serendipity['smarty']->assign( array( 'plugin_guestbook_sent' => $this->get_config('sent', PLUGIN_GUESTBOOK_SENT_HTML), 'plugin_guestbook_id' => $entry['id'], 'plugin_guestbook_ip' => $entry['ip'], 'plugin_guestbook_app' => $entry['approved'], 'plugin_guestbook_ts' => $entry['timestamp'], 'plugin_guestbook_name' => $entry['name'], 'plugin_guestbook_email' => $entry['email'], 'plugin_guestbook_url' => $entry['homepage'], 'plugin_guestbook_comment' => trim($entry['body']), 'plugin_guestbook_ac_comment' => isset($entry['admincomment']) ? trim($entry['admincomment']) : trim($entry['acbody']), 'guestbook_messages' => $messages, 'plugin_guestbook_messagestack' => $serendipity['messagestack']['comments'] ) ); // get the guestbook entries template file echo $this->parseTemplate('plugin_guestbook_backend_form.tpl'); } break; case 'gbdb': $serendipity['smarty']->assign('gb_db', true); // check if table exists, so there is nothing to do, except some insert stuff :: result is a single row array if (is_string($this->check_isdb())) { $serendipity['smarty']->assign('is_gbadmin_nodbcdb', true); } else { // add event form $this->backend_guestbook_dbclean(); } break; case 'droptable': $serendipity['guestbookdroptable'] = true; $this->uninstall($bag); $serendipity['GET']['guestbookdbclean'] = 'dberase'; $this->backend_guestbook_dbclean($reqbuild['month'], $reqbuild['year']); break; } } // gbadminpanel() end /** * Fake call to check if database is set and ready * * @return mixed string/array */ function check_isdb() { global $serendipity; if ($serendipity['dbType'] == 'mysql' || $serendipity['dbType'] == 'mysqli') { return serendipity_db_query("SHOW TABLES LIKE '{$serendipity['dbPrefix']}eventcal'", true, 'num', true); } else { $sql = "SELECT count(id) FROM {$serendipity['dbPrefix']}guestbook"; return count(serendipity_db_query($sql, true, 'num', true)) > 0; } } /** * Get sql results and assign them to smarty * * @param int $ap approved yes/no = 1/0 * @param string $cat serendipity[guestbookcategory] * @return boolean is_arrray($entries) */ function backend_guestbook_view($ap, $cat) { global $serendipity; global $messages; $count = $this->countEntriesDB($ap); // approved=1 if (is_array($count)) { $result = $this->backend_guestbook_paginator($count[0], $ap, $cat); } if (!is_numeric($wordwrap)) { $wordwrap = 50; } if (isset($result['paginator'])) { // slice and save last element of $result $paginator = array_pop($result); } // this assigns db entries output to guestbooks backend smarty array: {$entries} $entries = $this->generate_EntriesArray($result, $_SERVER['PHP_SELF'], $this->get_config('wordwrap'), true); // assign entries array and good messages array to smarty - do not use smarty {entries}, since used by s9y core $serendipity['smarty']->assign( array( 'guestbook_messages' => $messages, 'guestbook_entries' => $entries, 'guestbook_paginator' => $paginator, 'guestbook_message_header' => $serendipity['guestbook_message_header'] ) ); // get the guestbook entries template file echo $this->parseTemplate('plugin_guestbook_backend_entries.tpl'); return is_array($entries) ? true : false; } /** * Main backend function to generate moderation table view * */ function backend_guestbook_moderate() { global $serendipity; // assign form array entries to smarty $serendipity['smarty']->assign('is_guestbook_admin_noapp', false); // view all unapproved(0) entries in a table $va = $this->backend_guestbook_view(0, 'gbapp'); if ($va === false) $serendipity['smarty']->assign('is_gbadmin_noappresult', true); } /** * Main backend function navigation number 4 * plugins panel administration * switch into dump, insert, erase, download * * @return boolean */ function backend_guestbook_dbclean() { global $serendipity; $adminpath = $_SERVER['PHP_SELF'] . '?serendipity[adminModule]=event_display&serendipity[adminAction]=guestbook&serendipity[guestbookcategory]=gbdb'; $dbclean = !empty($serendipity['GET']['guestbookdbclean']) ? $serendipity['GET']['guestbookdbclean'] : 'start'; // check if table exists, so there is nothing to do except some insert stuff :: result is a single row array if (is_string($this->check_isdb()) && $dbclean != 'dbinsert' && $dbclean != 'dbicallog') $dbclean = 'dbnixda'; if (!empty($dbclean)) { switch($dbclean) { case 'dbdump': if ($serendipity['dbType'] == 'mysql' || $serendipity['dbType'] == 'mysqli') { if ($this->backend_guestbook_backup()) { $serendipity['smarty']->assign('is_guestbook_admin_backup', true); } else { $serendipity['smarty']->assign('is_guestbook_admin_backup', false); } } break; case 'dbinsert': $serendipity['smarty']->assign('is_guestbook_admin_insert', true); break; case 'dberase': $serendipity['smarty']->assign('is_guestbook_admin_erase', true); $isTable = $this->uninstall($bag) ? true : false; // ok, questionaire // give back ok if (isset($serendipity['guestbookdroptable']) === true && $isTable) { $serendipity['smarty']->assign(array('is_guestbook_admin_erase_msg' => true, 'plugin_gb_dbc_message' => sprintf(PLUGIN_GUESTBOOK_ADMIN_DROP_OK, $serendipity['dbPrefix'].'guestbook'))); } break; case 'dbdownload': $serendipity['smarty']->assign('is_guestbook_admin_download', true); if (is_dir('templates_c/guestbook')) { $str = $this->backend_read_backup_dir('templates_c/guestbook/', $adminpath.'&serendipity[guestbookdbclean]=dbdelfile&serendipity[guestbookdbcleanfilename]='); $serendipity['smarty']->assign(array('is_guestbook_admin_download_msg' => true, 'gb_read_backup_dir' => $str)); } else { $serendipity['smarty']->assign('is_guestbook_admin_download_msg', false); } break; case 'dbinsfile': $insfile = false; if (isset($serendipity['GET']['guestbookdbinsertfilename'])) { $old = getcwd(); // Save the current directory @chdir('templates_c/guestbook/'); if (is_file($serendipity['GET']['guestbookdbinsertfilename'])) { @unlink($serendipity['GET']['guestbookdbinsertfilename']); } @chdir($old); // Restore the old working directory $serendipity['smarty']->assign(array('is_guestbook_admin_insfile_msg' => true, 'plugin_gb_dbc_message' => sprintf(PLUGIN_GUESTBOOK_ADMIN_DBC_DELFILE_MSG, $serendipity['GET']['guestbookdbcleanfilename']))); } break; case 'dbdelfile': $delfile = false; if (isset($serendipity['GET']['guestbookdbcleanfilename'])) { $old = getcwd(); // Save the current directory @chdir('templates_c/guestbook/'); if (is_file($serendipity['GET']['guestbookdbcleanfilename'])) { @unlink($serendipity['GET']['guestbookdbcleanfilename']); } @chdir($old); // Restore the old working directory $serendipity['smarty']->assign(array('is_guestbook_admin_delfile_msg' => true, 'plugin_gb_dbc_message' => sprintf(PLUGIN_GUESTBOOK_ADMIN_DBC_DELFILE_MSG, $serendipity['GET']['guestbookdbcleanfilename']))); } break; case 'dbnixda': $serendipity['smarty']->assign('is_guestbook_admin_dbempty', true); break; default: break; } } if ($serendipity['dbType'] == 'mysql' || $serendipity['dbType'] == 'mysqli') { // assign form array entries to smarty $serendipity['smarty']->assign( array( 'plugin_gb_dump' => @$serendipity['GET']['guestbookdbclean'] == 'dbdump' ? ' id="active"' : '', 'plugin_gb_insert' => @$serendipity['GET']['guestbookdbclean'] == 'dbinsert' ? ' id="active"' : '', 'plugin_gb_erase' => @$serendipity['GET']['guestbookdbclean'] == 'dberase' ? ' id="active"' : '', 'plugin_gb_download' => @$serendipity['GET']['guestbookdbclean'] == 'dbdownload' ? ' id="active"' : '', 'plugin_gb_adminpath' => $adminpath, 'plugin_gb_ilogerror' => $serendipity['guestbook']['ilogerror'], 'plugin_gb_dropmsg' => $serendipity['guestbookdroptable'] ) ); // get the guestbook db administration template file echo $this->parseTemplate('plugin_guestbook_backend_dbc.tpl'); } } // backend_guestbook_dbclean() end /** * Read the sqldump backup directory - function scanDir() >= php5 * * @param string $dpath relative path * @param string $delpath url path */ function backend_read_backup_dir($dpath, $delpath) { global $serendipity; $dir = array_slice(@scanDir($dpath), 2); $url = $serendipity['serendipityHTTPPath'] . 'plugin/guestbookdlsql/'; if (is_array($dir) && !empty($dir)) { $str = ''; foreach ($dir as $e) { $str .= ''."\n"; } $str .= '
    '; $str .= $e.'
    '; return $str; } } /** * Create prettified questionaire buttons string * * @param string text - the question text string * @param string url - the url string to pass * @param string addno - the add to url string in case of no proceed * @param string addyes - the add to url string in case of YES * @return string */ function backend_guestbook_questionaire($text, $url, $addno, $addyes) { global $serendipity; if (!is_object($serendipity['smarty'])) { serendipity_smarty_init(); } $serendipity['smarty']->assign( array( 'is_plugin_gb_questionaire' => true, 'plugin_gb_questionaire_text' => $text, 'plugin_gb_questionaire_url' => $url, 'plugin_gb_questionaire_addno' => $addno, 'plugin_gb_questionaire_addyes' => $addyes ) ); return; } /** * Guestbook backup table and dir/file voodoo * Currently only MySql(i) layers supported * @return boolean */ function backend_guestbook_backup() { global $serendipity; set_time_limit(360); $date = date('Y-m-d_H-i-s'); $directory = "guestbook"; if (!is_dir('templates_c/' . $directory)) { @mkdir('templates_c/' . $directory, 0777); } $file = $serendipity['serendipityPath'] . 'templates_c/guestbook/'.$date.'_guestbook.sql'; $fp = fopen($file, 'w'); if ($fp) { $create = serendipity_db_query("SHOW CREATE TABLE {$serendipity['dbPrefix']}guestbook", true, 'num', true); if (is_array($create)) { $create[1] .= ";"; $tablesyntax = str_replace('CREATE TABLE', 'CREATE TABLE IF NOT EXISTS', $create[1]); $line = str_replace("\n", "", $tablesyntax); fwrite($fp, $line."\n"); if ($serendipity['dbType'] == 'mysql') { $data = mysql_query("SELECT * FROM {$serendipity['dbPrefix']}guestbook"); $num = mysql_num_fields($data); while ($row = mysql_fetch_array($data)){ $line = "INSERT INTO {$serendipity['dbPrefix']}guestbook VALUES("; for ($i=1; $i<=$num; $i++) { $line .= "'".serendipity_db_escape_string($row[$i-1])."', "; } $line = substr($line,0,-2); fwrite($fp, $line.");\n"); } } else if ($serendipity['dbType'] == 'mysqli') { $data = mysqli_query($serendipity['dbConn'], "SELECT * FROM {$serendipity['dbPrefix']}guestbook"); $num = mysqli_num_fields($data); while ($row = mysqli_fetch_array($data, MYSQLI_NUM)){ $line = "INSERT INTO {$serendipity['dbPrefix']}guestbook VALUES("; for ($i=1; $i<=$num; $i++) { $line .= "'".serendipity_db_escape_string($row[$i-1])."', "; } $line = substr($line,0,-2); fwrite($fp, $line.");\n"); } } } fclose($fp); return true; } else return false; } /** * Create backend entries paginator * * @param int $c = count entries * @param int $ap = approved yes/no = 1/0 * @param string $cat = serendipity[guestbookcategory] * * @return mixed array/boolean $result */ function backend_guestbook_paginator($c, $ap, $cat) { global $serendipity; if (isset($serendipity['POST']['guestbooklimit'])) $serendipity['GET']['guestbooklimit'] = $serendipity['POST']['guestbooklimit']; if (isset($serendipity['GET']['guestbooklimit'])) { $paginator = $serendipity['GET']['guestbooklimit']; } else { $paginator = 1; } // max rows per page $rows_per_page = $this->get_config('maxitems'); if (!is_numeric($rows_per_page)) { $rows_per_page = 15; } $lastpage = ceil($c/$rows_per_page); $paginator = (int)$paginator; if ($paginator > $lastpage) { $paginator = $lastpage; } if ($paginator < 1) { $paginator = 1; } $cp = ($paginator - 1); $rp = $rows_per_page; $result = $this->getEntriesDB($cp, $rp, $ap); ob_start(); if (is_array($result)) { if ($paginator == 1) { echo ' FIRST | PREVIOUS '."\n"; } else { $prevpage = $paginator-1; echo ''; echo ' | '."\n"; echo ' '."\n"; echo ''; } echo ' ( Page '.$paginator.' of '.$lastpage.' ) '."\n"; if ($paginator == $lastpage) { echo ' NEXT | LAST '."\n"; } else { $nextpage = $paginator+1; echo ''; echo ' | '."\n"; echo ' '."\n"; echo ''; } } $result['paginator'] = ob_get_contents(); ob_end_clean(); return is_array($result) ? $result : false; } // function backend paginator end /** * set global $serendipity['guestbook_message_header'] to true in case of approve or erase entry * * @return array $entry to re-edit and change */ function backend_request_checks() { global $serendipity; global $messages; if (!is_array($messages)) { $messages = array(); } $id = (int)$_POST['guestbook']['id']; // approve events if ( ( isset($_POST['Approve_Selected']) || isset($_POST['Approve_Selected_x']) || isset($_POST['Approve_Selected_y']) ) && isset($id)) { $sql = "UPDATE {$serendipity['dbPrefix']}guestbook SET approved=1 WHERE id=$id"; $result = serendipity_db_query($sql, true, 'both', true); if ($result) { array_push($messages, sprintf(PLUGIN_GUESTBOOK_APP_ENTRY, $id)); $serendipity['guestbook_message_header'] = true; } } // reject events if ( ( isset($_POST['Reject_Selected']) || isset($_POST['Reject_Selected_x']) || isset($_POST['Reject_Selected_y']) ) && isset($id)) { $sql = "DELETE FROM {$serendipity['dbPrefix']}guestbook WHERE id=$id"; $result = serendipity_db_query($sql, true, 'both', true); if ($result) { array_push($messages, sprintf(RIP_ENTRY, $id)); $serendipity['guestbook_message_header'] = true; } } // an authenticated logged-in user tries to change an anapproved event via app form if ( ( isset($_POST['Change_Selected']) || isset($_POST['Change_Selected_x']) || isset($_POST['Change_Selected_y']) ) && isset($id)) { // select a specific entry by id $sql = "SELECT * FROM {$serendipity['dbPrefix']}guestbook WHERE id=$id"; // show single entry to re-edit :: result is a single row array $entry = serendipity_db_query($sql, true, 'assoc', true); } // an authenticated logged-in user tries to change a single entry if (isset($entry) && is_array($entry)) return $entry; } } /* vim: set sts=4 ts=4 expandtab : */