function do_rss_rc($formatter, $options) { global $DBInfo, $Config; // get members to hide log $members = $DBInfo->members; $days = !empty($DBInfo->rc_days) ? $DBInfo->rc_days : RSS_DEFAULT_DAYS; $options['quick'] = 1; if (!empty($options['c'])) { $options['items'] = $options['c']; } $lines = $DBInfo->editlog_raw_lines($days, $options); if (!empty($DBInfo->rss_rc_options)) { $opts = $DBInfo->rss_rc_options; $opts = explode(',', $opts); foreach ($opts as $opt) { $options[$opt] = 1; // FIXME } } // HTTP conditional get $mtime = $DBInfo->mtime(); $lastmod = gmdate('D, d M Y H:i:s \\G\\M\\T', $mtime); $cache_ttl = !empty($DBInfo->rss_rc_ttl) ? $DBInfo->rss_rc_ttl : 60; /* 60 seconds */ // make etag based on some options and mtime. $check_opts = array('quick', 'items', 'oe', 'diffs', 'raw', 'nomsg', 'summary'); $check = array(); foreach ($check_opts as $c) { if (isset($options[$c])) { $check[$c] = $options[$c]; } } $etag = md5($mtime . $DBInfo->logo_img . serialize($check) . $cache_ttl . $options['id']); $headers = array(); $headers[] = 'Pragma: cache'; $maxage = $cache_ttl; $public = 'public'; if ($options['id'] != 'Anonymous') { $public = 'private'; } $headers[] = 'Cache-Control: ' . $public . ', max-age=' . $maxage; $headers[] = 'Last-Modified: ' . $lastmod; $headers[] = 'ETag: "' . $etag . '"'; $need = http_need_cond_request($mtime, $lastmod, $etag); if (!$need) { $headers[] = 'HTTP/1.0 304 Not Modified'; } foreach ($headers as $h) { header($h); } if (!$need) { @ob_end_clean(); return; } $cache = new Cache_Text('rss_rc'); $cache_delay = min($cache_ttl, 30); $mtime = $cache->mtime($etag); $val = false; if (empty($formatter->refresh)) { if (($val = $cache->fetch($etag)) !== false and $DBInfo->checkUpdated($mtime, $cache_delay)) { header("Content-Type: text/xml"); echo $val; return; } } // need to update cache if ($val !== false and $cache->exists($etag . '.lock')) { header("Content-Type: text/xml"); echo $val . '<!-- cached at ' . date('Y-m-d H:i:s', $mtime) . ' -->'; return; } if ($cache->exists($etag . '.lock')) { header("Content-Type: text/xml"); echo ''; return; } $cache->update($etag . '.lock', array('lock'), 5); // 5s lock $time_current = time(); # $secs_per_day= 60*60*24; # $days_to_show= 30; # $time_cutoff= $time_current - ($days_to_show * $secs_per_day); $URL = qualifiedURL($formatter->prefix); $img_url = qualifiedURL($DBInfo->logo_img); $url = qualifiedUrl($formatter->link_url("RecentChanges")); $channel = <<<CHANNEL <channel rdf:about="{$URL}"> <title>{$DBInfo->sitename}</title> <link>{$url}</link> <description>RecentChanges at {$DBInfo->sitename}</description> <image rdf:resource="{$img_url}"></image> <items> <rdf:Seq> CHANNEL; $items = ""; $ratchet_day = FALSE; if (!$lines) { $lines = array(); } foreach ($lines as $line) { $parts = explode("\t", $line); $page_name = $DBInfo->keyToPagename($parts[0]); // hide log if (!empty($members) && !in_array($options['id'], $members) && !empty($Config['ruleset']['hidelog'])) { if (in_array($page_name, $Config['ruleset']['hidelog'])) { continue; } } $addr = $parts[1]; $ed_time = $parts[2]; $user = $parts[4]; $log = _stripslashes($parts[5]); $act = rtrim($parts[6]); # if ($ed_time < $time_cutoff) # break; $url = qualifiedUrl($formatter->link_url(_rawurlencode($page_name))); $diff_url = qualifiedUrl($formatter->link_url(_rawurlencode($page_name), '?action=diff')); $extra = "<br /><a href='{$diff_url}'>" . _("show changes") . "</a>\n"; if (!$DBInfo->hasPage($page_name)) { $status = 'deleted'; $html = '<![CDATA[' . "<a href='{$url}'>" . $page_name . "</a> is deleted" . ']]>' . "\n"; } else { $status = 'updated'; if (!empty($options['diffs'])) { $p = new WikiPage($page_name); $f = new Formatter($p); $options['raw'] = 1; $options['nomsg'] = 1; $html = $f->macro_repl('Diff', '', $options); if (!$html) { ob_start(); $f->send_page('', array('fixpath' => 1)); #$f->send_page(''); $html = ob_get_contents(); ob_end_clean(); $extra = ''; } $html = str_replace(']', ']', $html); $html = "<![CDATA[" . $html . $extra . "]]>"; #$html=strtr($html.$extra,array('&'=>'&','<'=>'<')); } else { if (!empty($options['summary'])) { $p = new WikiPage($page_name); $f = new Formatter($p); $f->section_edit = 0; $f->sister_on = 0; $f->perma_icon = ''; $options['nomsg'] = 1; $b = $p->_get_raw_body(); $chunks = preg_split('/\\n#{4,}/', $b); # summary breaker is #### ob_start(); if ($chunks) { $f->send_page($chunks[0], array('fixpath' => 1)); } else { $f->send_page('', array('fixpath' => 1)); } #$f->send_page(''); $html = ob_get_contents(); ob_end_clean(); $chunks = preg_split('/<!-- break -->/', $html); # <!-- break --> if ($chunks[0]) { $html = $chunks[0]; } $html = str_replace(']', ']', $html); $html = "<![CDATA[" . $html . "]]>"; } else { $html = str_replace('&', '&', $log); } } } $zone = "+00:00"; $date = gmdate("Y-m-d\\TH:i:s", $ed_time) . $zone; #$datetag = gmdate("YmdHis",$ed_time); $channel .= "<rdf:li rdf:resource=\"{$url}\"></rdf:li>\n"; $valid_page_name = preg_replace('/&(?!#?\\w+;)/', '&', _html_escape($page_name)); $items .= "<item rdf:about=\"{$url}\">\n"; $items .= " <title>{$valid_page_name}</title>\n"; $items .= " <link>{$url}</link>\n"; $items .= " <description>{$html}</description>\n"; $items .= " <dc:date>{$date}</dc:date>\n"; $items .= "<dc:creator>{$user}</dc:creator>\n"; $items .= "<dc:contributor>{$user}</dc:contributor>\n"; # $items.=" <dc:contributor>\n <rdf:Description>\n" # ." <rdf:value>$user</rdf:value>\n" # ." </rdf:Description>\n </dc:contributor>\n"; $items .= " <wiki:status>{$status}</wiki:status>\n"; $items .= " <wiki:diff>{$diff_url}</wiki:diff>\n"; $items .= "</item>\n"; } $url = qualifiedUrl($formatter->link_url($DBInfo->frontpage)); $channel .= <<<FOOT </rdf:Seq> </items> </channel> <image rdf:about="{$img_url}"> <title>{$DBInfo->sitename}</title> <link>{$url}</link> <url>{$img_url}</url> </image> FOOT; $url = qualifiedUrl($formatter->link_url("FindPage")); $form = <<<FORM <textinput> <title>Search</title> <link>{$url}</link> <name>goto</name> </textinput> FORM; $new = ""; if (!empty($options['oe']) and strtolower($options['oe']) != $DBInfo->charset) { $charset = $options['oe']; if (function_exists('iconv')) { $out = $head . $channel . $items . $form; $new = iconv($DBInfo->charset, $charset, $out); if (!$new) { $charset = $DBInfo->charset; } } } else { $charset = $DBInfo->charset; } $head = <<<HEAD <?xml version="1.0" encoding="{$charset}"?> <?xml-stylesheet href="{$DBInfo->url_prefix}/css/_feed.css" type="text/css"?> <rdf:RDF xmlns="http://purl.org/rss/1.0/" \txmlns:wiki="http://purl.org/rss/1.0/modules/wiki/" \txmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" \txmlns:xlink="http://www.w3.org/1999/xlink" \txmlns:dc="http://purl.org/dc/elements/1.1/"> <!-- Add "diffs=1" to add change diffs to the description of each items. Add "summary=1" to add summary to the description of each items. Add "oe=utf-8" to convert the charset of this rss to UTF-8. --> HEAD; header("Content-Type: text/xml"); if ($new) { $out = $head . $new; } else { $out = $head . $channel . $items . $form; } $out .= "</rdf:RDF>\n"; echo $out; $cache->update($etag, $out); $cache->remove($etag . '.lock'); }
function do_contributors($formatter, $options) { global $DBInfo, $Config; if (!$formatter->page->exists()) { $formatter->send_header('', $options); $title = _("Page not found."); $formatter->send_title($title, '', $options); $formatter->send_footer('', $options); return; } // get contributors $params = array(); $retval = array(); $params['retval'] =& $retval; if (!empty($DBInfo->version_class)) { $cache = new Cache_Text('infostat'); if (!$formatter->refresh and $cache->exists($formatter->page->name)) { $retval = $cache->fetch($formatter->page->name); } if (empty($retval)) { $version = $DBInfo->lazyLoad('version', $DBInfo); $out = $version->rlog($formatter->page->name, '', '', '-z'); $retval = array(); if (!isset($out[0])) { $msg = _("No older revisions available"); $info = "<h2>{$msg}</h2>"; } else { $params = array(); $params['all'] = 1; $params['id'] = $options['id']; $params['retval'] =& $retval; $ret = _stat_rlog($formatter, $out, $params); } if (!empty($retval)) { $cache->update($formatter->page->name, $retval); } } } $formatter->send_header('', $options); $title = _("Contributors of this page"); $formatter->send_title($title, '', $options); // do not check admin member users $user = $DBInfo->user; $ismember = $user->is_member; $total = count($retval['revs']); $total_lab = _("Total Revisions"); $initial = $retval['rev']; $init_lab = _("Initial Revision"); $contrib_lab = _("User"); $edit_lab = _("Edit Count"); echo <<<HEAD <div class="wikiInfo"> <table class="wiki center"> <tr> <th>{$total_lab}</th><th>{$total}</th> </tr> <tr> <th>{$init_lab}</th><th>r{$initial}</th> </tr> <tr> <th>{$contrib_lab}</th><th>{$edit_lab}</th> </tr> HEAD; $opt = intval($Config['mask_hostname']); // sort users $authors = array_keys($retval['users']); $edits = array(); foreach ($authors as $n) { if ($retval['users'][$n]['edit'] > 0) { $edits[$n] = $retval['users'][$n]['edit']; } } // sort by edits arsort($edits); foreach ($edits as $u => $c) { if (!$ismember && preg_match('/^([0-9]+\\.){3}[0-9]+$/', $u)) { $u = _mask_hostname($u, $opt); } else { $u = $formatter->link_tag($formatter->page->urlname, '?action=userinfo&q=' . $u, $u); } echo "<tr><td>", $u, "</td><td>", $c, "</td></tr>\n"; } echo "</table></div>"; $formatter->send_footer('', $options); return; }
function savePage(&$page, $comment = "", $options = array()) { if (empty($options['.force']) && !$this->_isWritable($page->name)) { return -1; } $user =& $this->user; if ($user->id == 'Anonymous' and !empty($this->anonymous_log_maxlen)) { if (strlen($comment) > $this->anonymous_log_maxlen) { $comment = ''; } } // restrict comment length for anon. if (!empty($this->use_x_forwarded_for)) { $REMOTE_ADDR = get_log_addr(); } else { $REMOTE_ADDR = $_SERVER['REMOTE_ADDR']; } $myid = $user->id; if (!empty($user->info['nick'])) { $myid .= ' ' . $user->info['nick']; $options['nick'] = $user->info['nick']; } else { if ($myid == 'Anonymous' and !empty($user->verified_email)) { $myid .= '-' . $user->verified_email; } } $options['myid'] = $myid; $keyname = $this->_getPageKey($page->name); $key = $this->text_dir . "/{$keyname}"; $body = $this->_replace_variables($page->body, $options); if (file_exists($key)) { $action = 'SAVE'; } else { $action = 'CREATE'; } if ($user->id == 'Anonymous' && $action == 'CREATE' && empty($this->anomymous_allow_create_without_backlink)) { $bc = new Cache_Text('backlinks'); if (!$bc->exists($page->name)) { $options['retval']['msg'] = _("Anonymous users can not create new pages."); return -1; } } if (!empty($options['.reverted'])) { $action = 'REVERT'; } // check abusing FIXME if (!empty($this->use_abusefilter)) { $params = array(); $params['retval'] =& $options['retval']; $params['id'] = $user->id == 'Anonymous' ? $REMOTE_ADDR : $user->id; $params['ip'] = $REMOTE_ADDR; $params['action'] = $options['action']; $params['editinfo'] = !empty($options['editinfo']) ? $options['editinfo'] : false; if (is_string($this->use_abusefilter)) { $filtername = $this->use_abusefilter; } else { $filtername = 'default'; } $ret = call_abusefilter($filtername, $action, $params); if ($ret === false) { return -1; } } if ($action == 'SAVE' && !empty($options['.minorfix'])) { $action = 'MINOR'; } $comment = trim($comment); $comment = strtr(strip_tags($options['comment']), array("\r\n" => ' ', "\r" => ' ', "\n" => ' ', "\t" => ' ')); // strip out all action flags FIXME $comment = preg_replace('@^{(SAVE|CREATE|DELETE|RENAME|REVERT|UPLOAD|ATTDRW|FORK|REVOKE|MINOR|BOTFIX)}:?@', '', $comment); if ($action != 'SAVE') { $tag = '{' . $action . '}'; if (!empty($comment)) { $comment = $tag . ': ' . $comment; } else { $comment = $tag; } } $log = $REMOTE_ADDR . ';;' . $myid . ';;' . $comment; $options['log'] = $log; $options['pagename'] = $page->name; $is_new = false; if (!file_exists($key)) { $is_new = true; } // get some edit info; $retval = array(); $options['retval'] =& $retval; $ret = $this->_savePage($page->name, $body, $options); if ($ret == -1) { return -1; } # $page->write($body); # check minor edits XXX $minor = 0; if (!empty($this->use_minorcheck) or !empty($options['minorcheck'])) { $info = $page->get_info(); if (!empty($info[0][1])) { eval('$check=' . $info[1] . ';'); if (abs($check) < 3) { $minor = 1; } } } if (empty($options['.nolog']) && empty($options['minor']) && !$minor) { $this->addLogEntry($page->name, $REMOTE_ADDR, $comment, $action); } if ($user->id != 'Anonymous' || !empty($this->use_anonymous_editcount)) { // save editing information if (!isset($user->info['edit_count'])) { $user->info['edit_count'] = 0; } $user->info['edit_count']++; // added/deleted lines if (!isset($user->info['edit_add_lines'])) { $user->info['edit_add_lines'] = 0; } if (!isset($user->info['edit_del_lines'])) { $user->info['edit_del_lines'] = 0; } if (!isset($user->info['edit_add_chars'])) { $user->info['edit_add_chars'] = 0; } if (!isset($user->info['edit_del_chars'])) { $user->info['edit_del_chars'] = 0; } // added/deleted lines $user->info['edit_add_lines'] += $retval['add']; $user->info['edit_del_lines'] += $retval['del']; // added/deleted chars $user->info['edit_add_chars'] += $retval['add_chars']; $user->info['edit_del_chars'] += $retval['del_chars']; // save user $this->udb->saveUser($user); } $indexer = $this->lazyLoad('titleindexer'); if ($is_new) { $indexer->addPage($page->name); } else { $indexer->update($page->name); } // just update mtime return 0; }
function do_atom($formatter, $options) { global $DBInfo, $Config; global $_release; define('ATOM_DEFAULT_DAYS', 7); // get members to hide log $members = $DBInfo->members; $days = $DBInfo->rc_days ? $DBInfo->rc_days : ATOM_DEFAULT_DAYS; $options['quick'] = 1; if ($options['c']) { $options['items'] = $options['c']; } $lines = $DBInfo->editlog_raw_lines($days, $options); // HTTP conditional get $mtime = $DBInfo->mtime(); $lastmod = gmdate('D, d M Y H:i:s \\G\\M\\T', $mtime); $cache_ttl = !empty($DBInfo->atom_ttl) ? $DBInfo->atom_ttl : 60 * 30; /* 30 minutes */ // make etag based on some options and mtime. $check_opts = array('quick', 'items', 'c'); $check = array(); foreach ($check_opts as $c) { if (isset($options[$c])) { $check[$c] = $options[$c]; } } $etag = md5($mtime . $DBInfo->logo_img . serialize($check) . $cache_ttl . $options['id']); $headers = array(); $headers[] = 'Pragma: cache'; $maxage = $cache_ttl; $public = 'public'; if ($options['id'] != 'Anonymous') { $public = 'private'; } $headers[] = 'Cache-Control: ' . $public . ', max-age=' . $maxage; $headers[] = 'Last-Modified: ' . $lastmod; $headers[] = 'ETag: "' . $etag . '"'; $need = http_need_cond_request($mtime, $lastmod, $etag); if (!$need) { $headers[] = 'HTTP/1.0 304 Not Modified'; } foreach ($headers as $h) { header($h); } if (!$need) { @ob_end_clean(); return; } $cache = new Cache_Text('atom'); $cache_delay = min($cache_ttl, 30); $mtime = $cache->mtime($etag); $time_current = time(); $val = false; if (empty($formatter->refresh)) { if (($val = $cache->fetch($etag)) !== false and $DBInfo->checkUpdated($mtime, $cache_delay)) { header("Content-Type: application/xml"); echo $val; return; } } // need to update cache if ($val !== false and $cache->exists($etag . '.lock')) { header("Content-Type: application/xml"); echo $val . '<!-- cached at ' . date('Y-m-d H:i:s', $mtime) . ' -->'; return; } if ($cache->exists($etag . '.lock')) { header("Content-Type: application/xml"); echo ''; return; } $cache->update($etag . '.lock', array('lock'), 30); // 30s lock $URL = qualifiedURL($formatter->prefix); $img_url = qualifiedURL($DBInfo->logo_img); $url = qualifiedUrl($formatter->link_url($DBInfo->frontpage)); $surl = qualifiedUrl($formatter->link_url($options['page'] . '?action=atom')); $channel = <<<CHANNEL <title>{$DBInfo->sitename}</title> <link href="{$url}"></link> <link rel="self" type="application/atom+xml" href="{$surl}" /> <subtitle>RecentChanges at {$DBInfo->sitename}</subtitle> <generator version="{$_release}">MoniWiki Atom feeder</generator> CHANNEL; $items = ""; $ratchet_day = FALSE; if (!$lines) { $lines = array(); } foreach ($lines as $line) { $parts = explode("\t", $line); $page_name = $DBInfo->keyToPagename($parts[0]); // hide log if (!empty($members) && !in_array($options['id'], $members) && !empty($Config['ruleset']['hidelog'])) { if (in_array($page_name, $Config['ruleset']['hidelog'])) { continue; } } $addr = $parts[1]; $ed_time = $parts[2]; $user = $parts[4]; $user_uri = ''; if ($user != 'Anonymous' && $DBInfo->hasPage($user)) { $user_uri = $formatter->link_url(_rawurlencode($user), "", $user); $user_uri = '<uri>' . $user_uri . '</uri>'; } $log = _stripslashes($parts[5]); $act = rtrim($parts[6]); $url = qualifiedUrl($formatter->link_url(_rawurlencode($page_name))); $diff_url = qualifiedUrl($formatter->link_url(_rawurlencode($page_name), '?action=diff')); $extra = "<br /><a href='{$diff_url}'>" . _("show changes") . "</a>\n"; $content = ''; if (!$DBInfo->hasPage($page_name)) { $status = 'deleted'; $content = "<content type='html'><a href='{$url}'>{$page_name}</a> is deleted</content>\n"; } else { $status = 'updated'; if ($options['diffs']) { $p = new WikiPage($page_name); $f = new Formatter($p); $options['raw'] = 1; $options['nomsg'] = 1; $html = $f->macro_repl('Diff', '', $options); if (!$html) { ob_start(); $f->send_page('', array('fixpath' => 1)); #$f->send_page(''); $html = ob_get_contents(); ob_end_clean(); $extra = ''; } $content = " <content type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>{$html}</content>\n"; } else { if ($log) { $html = str_replace('&', '&', $log); $content = "<content type='text'>" . $html . "</content>\n"; } else { $content = "<content type='text'>updated</content>\n"; } } } $zone = '+00:00'; $date = gmdate("Y-m-d\\TH:i:s", $ed_time) . $zone; if (!isset($updated)) { $updated = $date; } #$datetag = gmdate("YmdHis",$ed_time); $valid_page_name = str_replace('&', '&', $page_name); $items .= "<entry>\n"; $items .= " <title>{$valid_page_name}</title>\n"; $items .= " <link href='{$url}'></link>\n"; $items .= ' ' . $content; $items .= " <author><name>{$user}</name>{$user_uri}</author>\n"; $items .= " <updated>{$date}</updated>\n"; $items .= " <contributor><name>{$user}</name>{$user_uri}</contributor>\n"; $items .= "</entry>\n"; } $updated = " <updated>{$updated}</updated>\n"; $new = ""; if ($options['oe'] and strtolower($options['oe']) != $DBInfo->charset) { $charset = $options['oe']; if (function_exists('iconv')) { $out = $head . $channel . $items . $form; $new = iconv($DBInfo->charset, $charset, $out); if (!$new) { $charset = $DBInfo->charset; } } } else { $charset = $DBInfo->charset; } $head = <<<HEAD <?xml version="1.0" encoding="{$charset}"?> <!--<?xml-stylesheet href="{$DBInfo->url_prefix}/css/_feed.css" type="text/css"?>--> <feed xmlns="http://www.w3.org/2005/Atom"> <!-- Add "diffs=1" to add change diffs to the description of each items. Add "oe=utf-8" to convert the charset of this rss to UTF-8. --> HEAD; header("Content-Type: application/xml"); $out = ''; if ($new) { $out = $head . $new; } else { $out = $head . $channel . $updated . $items . $form; } $out .= "</feed>\n"; echo $out; $cache->update($etag, $out); $cache->remove($etag . '.lock'); }
function macro_Stat($formatter, $value, $options = array()) { global $DBInfo; if (!empty($DBInfo->version_class)) { $cache = new Cache_Text('infostat'); $retval = array(); if (!$formatter->refresh and $cache->exists($formatter->page->name)) { $retval = $cache->fetch($formatter->page->name); } if (empty($retval)) { $version = $DBInfo->lazyLoad('version', $DBInfo); $out = $version->rlog($formatter->page->name, '', '', '-z'); $retval = array(); if (!isset($out[0])) { $msg = _("No older revisions available"); $info = "<h2>{$msg}</h2>"; } else { $params = array(); $params['all'] = 1; $params['id'] = $options['id']; $params['retval'] =& $retval; $ret = _stat_rlog($formatter, $out, $params); } if (!empty($retval)) { $cache->update($formatter->page->name, $retval); } } $merge_ip = true; if (!empty($DBInfo->stat_no_merge_ip_users) && empty($options['merge_ip_users'])) { $merge_ip = false; } if ($merge_ip) { $users =& $retval['users']; foreach ($users as $k => $v) { foreach ($v['ip'] as $ip => $dummy) { $users[$k]['add'] += $users[$ip]['add']; $users[$k]['del'] += $users[$ip]['del']; $users[$k]['edit'] += $users[$ip]['edit']; $users[$k]['rev'] = array_merge($users[$k]['rev'], $users[$ip]['rev']); unset($users[$ip]); } } } if (!empty($retval)) { if (isset($options['retval'])) { $info = _render_stat($formatter, $retval, $options); return $info; } else { $info = _render_stat($formatter, $retval, $options); } $formatter->register_javascripts('js/chart/Chart.min.js'); } if (isset($options['retval'])) { return -1; } } else { $msg = _("Version info is not available in this wiki"); $info = "<h2>{$msg}</h2>"; } if (isset($options['retval'])) { return -1; } return $info; }