Ejemplo n.º 1
0
function do_qr($formatter, $params = array())
{
    global $Config;
    if (isset($params['value']) && isset($params['value'][0])) {
        $value = $params['value'];
    } else {
        $encoded = _urlencode(strtr($formatter->page->name, ' ', '_'));
        $value = qualifiedUrl($formatter->link_url($encoded));
    }
    if (!empty($Config['cache_public_dir']) and !empty($Config['cache_public_url'])) {
        $fc = new Cache_text('qr', array('ext' => 'png', 'dir' => $Config['cache_public_dir']));
        $pngname = $fc->getKey($value);
        $pngfile = $Config['cache_public_dir'] . '/' . $pngname;
        $png_url = !empty($Config['cache_public_url']) ? $Config['cache_public_url'] . '/' . $pngname : $Config['url_prefix'] . '/' . $pngfile;
    } else {
        $uniq = md5($value);
        $pngfile = $cache_dir . '/' . $uniq . '.png';
        $png_url = $cache_url . '/' . $uniq . '.png';
    }
    $img_exists = file_exists($pngfile);
    if (!$img_exists || $formatter->refresh) {
        require_once dirname(__FILE__) . '/../lib/phpqrcode.php';
        QRcode::png($value, $pngfile, 'l', 3, 1);
    }
    if (!empty($Config['use_cache_url'])) {
        header("Pragma: no-cache");
        header('Cache-Control: public, max-age=0, s-maxage=0');
        header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
        header('Cache-Control: no-store, no-cache, must-revalidate', false);
        $formatter->send_header(array('Status: 302', 'Location: ' . $png_url));
        return null;
    }
    $down_mode = 'inline';
    header("Content-Type: image/png\r\n");
    $mtime = filemtime($pngfile);
    $lastmod = gmdate('D, d M Y H:i:s', $mtime) . ' GMT';
    $etag = md5($lastmod . $key);
    header('Last-Modified: ' . $lastmod);
    header('ETag: "' . $etag . '"');
    $maxage = 60 * 60 * 24 * 30;
    header('Cache-Control: public, max-age=' . $maxage);
    $need = http_need_cond_request($mtime, $lastmod, $etag);
    if (!$need) {
        header('HTTP/1.0 304 Not Modified');
        @ob_end_clean();
        return null;
    }
    @ob_clean();
    $ret = readfile($pngfile);
    return null;
}
Ejemplo n.º 2
0
function do_latex2png($formatter, $options)
{
    $retval = false;
    $opts = array();
    $opts['retval'] =& $retval;
    if (isset($options['dpi']) and $options['dpi'] > 120 and $options['dpi'] < 600) {
        $opts['dpi'] = $options['dpi'];
    }
    $my = $formatter->processor_repl('latex', $options['value'], $opts);
    if (!empty($opts['retval'])) {
        $png = $opts['retval'];
    } else {
        $png = $my;
    }
    $mtime = filemtime($png);
    $lastmod = gmdate('D, d M Y H:i:s \\G\\M\\T', $mtime);
    $etag = md5($mtime);
    $headers = array();
    $headers[] = 'Pragma: cache';
    $maxage = 60 * 60 * 24 * 7;
    $headers[] = 'Cache-Control: private, 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;
    }
    if (file_exists($png)) {
        Header("Content-type: image/png");
        readfile($png);
    } else {
        // 43byte 1x1 transparent gif
        // http://stackoverflow.com/questions/2933251/code-golf-1x1-black-pixel
        // http://www.perlmonks.org/?node_id=7974
        $gif = base64_decode('R0lGODlhAQABAJAAAAAAAAAAACH5BAUQAAAALAAAAAABAAEAAAICBAEAOw');
        Header("Content-type: image/gif");
        Header("Content-length: " . strlen($gif));
        header('Connection: Close');
        echo $gif;
        flush();
    }
}
Ejemplo n.º 3
0
function do_titleindex($formatter, $options)
{
    global $DBInfo, $Config;
    if (isset($options['q'])) {
        if (!$options['q']) {
            print '';
            return;
        }
        #if (!$options['q']) { print "<ul></ul>"; return; }
        $limit = isset($options['limit']) ? intval($options['limit']) : 100;
        $limit = min(100, $limit);
        $val = '';
        $rule = '';
        while ($DBInfo->use_hangul_search) {
            include_once "lib/unicode.php";
            $val = $options['q'];
            if (strtoupper($DBInfo->charset) != 'UTF-8' and function_exists('iconv')) {
                $val = iconv($DBInfo->charset, 'UTF-8', $options['q']);
            }
            if (!$val) {
                break;
            }
            $rule = utf8_hangul_getSearchRule($val);
            $test = @preg_match("/^{$rule}/", '');
            if ($test === false) {
                $rule = $options['q'];
            }
            break;
        }
        if (!$rule) {
            $rule = trim($options['q']);
        }
        $test = validate_needle('^' . $rule);
        if (!$test) {
            $rule = preg_quote($rule);
        }
        $indexer = $DBInfo->lazyLoad('titleindexer');
        $pages = $indexer->getLikePages($rule, $limit);
        sort($pages);
        //array_unshift($pages, $options['q']);
        $ct = "Content-Type: text/plain";
        $ct .= '; charset=' . $DBInfo->charset;
        header($ct);
        $maxage = 60 * 10;
        header('Cache-Control: public, max-age=' . $maxage . ',s-maxage=' . $maxage . ', post-check=0, pre-check=0');
        if ($pages) {
            $ret = implode("\n", $pages);
            #$ret= "<ul>\n<li>".implode("</li>\n<li>",$pages)."</li>\n</ul>\n";
        } else {
            #$ret= "<ul>\n<li>".$options['q']."</li></ul>";
            $ret = '';
            #$ret= "<ul>\n</ul>";
        }
        if (strtoupper($DBInfo->charset) != 'UTF-8' and function_exists('iconv')) {
            $val = iconv('UTF-8', $DBInfo->charset, $ret);
            if ($val) {
                print $val;
                return;
            }
        }
        #print 'x'.$rule;
        print $ret;
        return;
    } else {
        if ($options['sec'] == '') {
            if (!empty($DBInfo->no_all_titleindex)) {
                return;
            }
            $tc = new Cache_text('persist', array('depth' => 0));
            // all pages
            $mtime = $DBInfo->mtime();
            $lastmod = gmdate('D, d M Y H:i:s \\G\\M\\T', $mtime);
            $etag = md5($mtime . $DBInfo->etag_seed);
            $options['etag'] = $etag;
            $options['mtime'] = $mtime;
            // set the s-maxage for proxy
            $date = gmdate('Y-m-d-H-i-s', $mtime);
            $proxy_maxage = !empty($Config['proxy_maxage']) ? ', s-maxage=' . $Config['proxy_maxage'] : '';
            $header[] = 'Content-Type: text/plain';
            $header[] = 'Cache-Control: public' . $proxy_maxage . ', max-age=0, must-revalidate';
            $need = http_need_cond_request($mtime, $lastmod, $etag);
            if (!$need) {
                $header[] = 'HTTP/1.0 304 Not Modified';
            } else {
                $header[] = 'Content-Disposition: attachment; filename="titleindex-' . $date . '.txt"';
            }
            $formatter->send_header($header, $options);
            if (!$need) {
                @ob_end_clean();
                return;
            }
            if (($out = $tc->fetch('titleindex', 0, array('print' => 1))) === false) {
                $args = array('all' => 1);
                $pages = $DBInfo->getPageLists($args);
                sort($pages);
                $out = join("\n", $pages);
                $ttl = !empty($DBInfo->titleindex_ttl) ? $DBInfo->titleindex_ttl : 60 * 60 * 24;
                $tc->update('titleindex', $out, $ttl);
                echo $out;
            }
            return;
        }
    }
    $formatter->send_header("", $options);
    $formatter->send_title("", "", $options);
    print macro_TitleIndex($formatter, $options['sec'], $options);
    $formatter->send_footer($args, $options);
}
Ejemplo n.º 4
0
function dl_file_resume($ctype, $file, $fname, $mode = 'inline', $header = '')
{
    # from http://kr2.php.net/manual/en/function.fread.php#63893
    # ans some modification
    //Gather relevent info about file
    $size = filesize($file);
    if ($size == 0) {
        return;
    }
    //Begin writing headers
    //header("Cache-Control:");
    header("Cache-Control: public");
    if (is_array($header)) {
        foreach ($header as $h) {
            header($h);
        }
    }
    //Use the switch-generated Content-Type
    header("Content-Type: {$ctype}");
    if (strstr($_SERVER['HTTP_USER_AGENT'], "MSIE")) {
        # workaround for IE filename bug with multiple periods / multiple dots
        # in filename that adds square brackets to filename
        # - eg. setup.abc.exe becomes setup[1].abc.exe
        $fname = preg_replace('/\\./', '%2e', $fname, substr_count($fname, '.') - 1);
    }
    header("Accept-Ranges: bytes");
    //check if http_range is sent by browser (or download manager)
    $range = 0;
    if (isset($_SERVER['HTTP_RANGE'])) {
        list($a, $range) = explode("=", $_SERVER['HTTP_RANGE']);
        //if yes, download missing part
        str_replace($range, "-", $range);
        $size2 = $size - 1;
        $new_length = $size2 - $range;
        header("HTTP/1.1 206 Partial Content");
        header("Content-Range: bytes {$range}{$size2}/{$size}");
        header("Content-Length: {$new_length}");
        header("Content-Disposition: {$mode}; {$fname}");
    } else {
        $size2 = $size - 1;
        header("Pragma:");
        $maxage = 60 * 60 * 24 * 7;
        header('Cache-Control: public, max-age=' . $maxage);
        header("Content-Range: bytes 0-{$size2}/{$size}");
        header("Content-Length: " . $size);
        header("Content-Disposition: {$mode}; {$fname}");
        $mtime = filemtime($file);
        $lastmod = gmdate("D, d M Y H:i:s", $mtime) . " GMT";
        $etag = md5($lastmod);
        header("Last-Modified: " . $lastmod);
        header('ETag: "' . $etag . '"');
        $need = http_need_cond_request($mtime, $lastmod, $etag);
        if (!$need) {
            header('X-Cache-Debug: Cached OK');
            header('HTTP/1.0 304 Not Modified');
            @ob_end_clean();
            return;
        }
    }
    //open the file
    $fp = fopen("{$file}", "rb");
    if (!is_resource($fp)) {
        return;
    }
    //seek to start of missing part
    fseek($fp, $range);
    //start buffered download
    //reset time limit for big files
    set_time_limit(0);
    $chunksize = 1 * (1024 * 1024);
    // 1MB chunks
    $left = $size;
    // start output buffering
    //ob_start();
    while (!feof($fp) and $left > 0) {
        $sz = $chunksize < $left ? $chunksize : $left;
        echo fread($fp, $sz);
        flush();
        @ob_flush();
        $left -= $sz;
    }
    fclose($fp);
    //ob_end_flush();
    return;
}
Ejemplo n.º 5
0
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(']', '&#93;', $html);
                $html = "<![CDATA[" . $html . $extra . "]]>";
                #$html=strtr($html.$extra,array('&'=>'&amp;','<'=>'&lt;'));
            } 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(']', '&#93;', $html);
                    $html = "<![CDATA[" . $html . "]]>";
                } else {
                    $html = str_replace('&', '&amp;', $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+;)/', '&amp;', _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');
}
Ejemplo n.º 6
0
function macro_Fetch($formatter, $url = '', $params = array())
{
    global $DBInfo;
    if (empty($url)) {
        $params['retval']['error'] = _("Empty URL");
        return false;
    }
    // check valid url
    if (!preg_match('@^((ftp|https?)://[^/]+)/@', $url, $m)) {
        return false;
    }
    $siteurl = $m[1];
    require_once "lib/HTTPClient.php";
    $sz = 0;
    $allowed = 'png|jpeg|jpg|gif';
    if (!empty($DBInfo->fetch_exts)) {
        $allowed = $DBInfo->fetch_exts;
    }
    // urlencode()
    $url = _urlencode($url);
    // set default params
    $maxage = !empty($DBInfo->fetch_maxage) ? (int) $DBInfo->fetch_maxage : 60 * 60 * 24 * 7;
    $timeout = !empty($DBInfo->fetch_timeout) ? (int) $DBInfo->fetch_timeout : 15;
    $vartmp_dir = $DBInfo->vartmp_dir;
    $buffer_size = 2048 * 1024;
    // default buffer size
    if (!empty($DBInfo->fetch_buffer_size) and $DBInfo->fetch_buffer_size > 2048 * 1024) {
        $buffer_size = $DBInfo->fetch_buffer_size;
    }
    // set referrer
    $referer = '';
    if (!empty($DBInfo->fetch_referer_re)) {
        foreach ($DBInfo->fetch_referer_re as $re => $ref) {
            if (preg_match($re, $url)) {
                $referer = $ref;
                break;
            }
        }
    }
    // default referrer
    if (empty($referer) and !empty($DBInfo->fetch_referer)) {
        $referer = $DBInfo->fetch_referer;
    }
    // check site available
    $si = new Cache_text('siteinfo');
    if ($si->exists($siteurl)) {
        if (!empty($params['refresh'])) {
            $si->remove($siteurl);
        } else {
            if (empty($params['refresh']) && ($check = $si->fetch($siteurl)) !== false) {
                $params['retval']['status'] = $check['status'];
                $params['retval']['error'] = $check['error'];
                return false;
            }
        }
    }
    $sc = new Cache_text('fetchinfo');
    $error = null;
    if (empty($params['refresh']) and $sc->exists($url) and $sc->mtime($url) < time() + $maxage) {
        $info = $sc->fetch($url);
        $sz = $info['size'];
        $mimetype = $info['mimetype'];
        $error = !empty($info['error']) ? $info['error'] : null;
        // already retrived and found some error
        if (empty($params['refresh']) and !empty($error)) {
            $params['retval']['status'] = $info['status'];
            $params['retval']['error'] = $error;
            $params['retval']['mimetype'] = $mimetype;
            $params['retval']['size'] = $sz;
            return false;
        }
    } else {
        // check connection
        $http = new HTTPClient();
        // get file header
        $http->nobody = true;
        $http->referer = $referer;
        $http->sendRequest($url, array(), 'GET');
        //if ($http->status == 301 || $http->status == 302 ) {
        //
        //}
        if ($http->status != 200) {
            if ($http->status == 404) {
                $params['retval']['error'] = '404 File Not Found';
            } else {
                $params['retval']['error'] = !empty($http->error) ? $http->error : sprintf(_("Invalid Status %d"), $http->status);
            }
            $params['retval']['status'] = $http->status;
            // check alive site
            if ($http->status == -210) {
                $si->update($siteurl, array('status' => $http->status, 'error' => $params['retval']['error']), 60 * 60 * 24);
                return false;
            }
            $sc->update($url, array('size' => -1, 'mimetype' => '', 'error' => $params['retval']['error'], 'status' => $params['retval']['status']), 60 * 60 * 24 * 3);
            return false;
        }
        if (isset($http->resp_headers['content-length'])) {
            $sz = $http->resp_headers['content-length'];
        }
        if (isset($http->resp_headers['content-type'])) {
            $mimetype = $http->resp_headers['content-type'];
        } else {
            $mimetype = 'application/octet-stream';
        }
        $sc->update($url, array('size' => $sz, 'mimetype' => $mimetype));
    }
    // size info
    if (is_numeric($sz)) {
        $unit = array('Bytes', 'KB', 'MB', 'GB');
        $tmp = $sz;
        for ($i = 0; $i < 4; $i++) {
            if ($tmp <= 1024) {
                break;
            }
            $tmp = $tmp / 1024;
        }
        $hsz = round($tmp, 2) . ' ' . $unit[$i];
        if (empty($buffer_size) && !empty($DBInfo->fetch_max_size) and $sz > $DBInfo->fetch_max_size) {
            $params['retval']['error'] = sprintf(_("Too big file size (%s). Please contact WikiMasters to increase \$fetch_max_size"), $hsz);
            $params['retval']['mimetype'] = $mimetype;
            return false;
        }
    } else {
        $params['retval']['error'] = _("Can't get file size info");
        $params['retval']['mimetype'] = $mimetype;
        return false;
    }
    $is_image = false;
    if (preg_match('/^image\\/(jpe?g|gif|png)$/', $mimetype, $m)) {
        $ext = isset($m[1]) ? '.' . $m[1] : '';
        $is_image = true;
    } else {
        $ext = '.' . get_extension('data/mime.types', $mimetype);
    }
    if (!empty($DBInfo->fetch_images_only) and !$is_image) {
        // always check the content-type
        $params['retval']['error'] = sprintf(_("Invalid mime-type %s"), $mimetype);
        $params['retval']['mimetype'] = $mimetype;
        return false;
    }
    if (empty($params['call'])) {
        if ($is_image) {
            $img_url = $formatter->link_url('', '?action=fetch&amp;url=' . $url);
            return '<div class="externalImage"><div><img src="' . $img_url . '">' . '<div><a href="' . $url . '"><span>[' . strtoupper($m[1]) . ' ' . _("external image") . ' (' . $hsz . ')' . ']</span></a></div></div>';
        }
        return $formatter->link_to('?action=fetch&amp;url=' . $url, $mimetype . ' (' . $hsz . ')');
    }
    // cache dir/filename/cache url
    if (!empty($DBInfo->cache_public_dir) and !empty($DBInfo->cache_public_url)) {
        $fc = new Cache_text('fetchfile', array('dir' => $DBInfo->cache_public_dir));
        $fetchname = $fc->getKey($url);
        $fetchfile = $DBInfo->cache_public_dir . '/' . $fetchname . $ext;
        $fetch_url = $DBInfo->cache_public_url . '/' . $fetchname . $ext;
    } else {
        $fc = new Cache_text('fetchfile');
        $fetchname = $fc->getKey($url);
        $fetchfile = $fc->cache_dir . '/' . $fetchname;
        $fetch_url = null;
    }
    // real fetch job.
    if (!empty($params['refresh']) or !file_exists($fetchfile)) {
        $fp = fopen($fetchfile, 'w');
        if (!is_resource($fp)) {
            $params['retval']['error'] = sprintf(_("Fail to open %s"), $fetchfile);
            return false;
        }
        // retry to get all info
        $http = new HTTPClient();
        if (!empty($buffer_size)) {
            $http->max_buffer_size = $buffer_size;
        }
        $http->vartmp_dir = $vartmp_dir;
        $save = ini_get('max_execution_time');
        set_time_limit(0);
        $http->timeout = $timeout;
        $http->referer = $referer;
        $http->sendRequest($url, array(), 'GET');
        set_time_limit($save);
        if ($http->status != 200) {
            fclose($fp);
            unlink($fetchfile);
            // Error found! save error status to the info cache
            $params['retval']['status'] = $http->status;
            $params['retval']['error'] = $http->error;
            $params['retval']['mimetype'] = $mimetype;
            $params['retval']['size'] = $sz;
            $sc->update($url, array('size' => $sz, 'mimetype' => $mimetype, 'error' => $http->error, 'status' => $params['retval']['status']));
            return false;
        }
        if (!empty($http->resp_body)) {
            fwrite($fp, $http->resp_body);
            fclose($fp);
        } else {
            fclose($fp);
            if (!empty($http->resp_body_file) && file_exists($http->resp_body_file)) {
                copy($http->resp_body_file, $fetchfile);
                unlink($http->resp_body_file);
            }
        }
        // update error status.
        if (!empty($error)) {
            $sc->update($url, array('size' => $sz, 'mimetype' => $mimetype));
        }
    }
    if (!empty($fetch_url) and !empty($DBInfo->fetch_use_cache_url)) {
        $formatter->send_header(array('Status: 302', 'Location: ' . $fetch_url));
        return null;
    }
    if (!empty($params['thumbwidth'])) {
        // check allowed thumb widths.
        $thumb_widths = isset($DBInfo->thumb_widths) ? $DBInfo->thumb_widths : array('120', '240', '320', '480', '600', '800', '1024');
        $width = 320;
        // default
        if (!empty($DBInfo->default_thumb_width)) {
            $width = $DBInfo->default_thumb_width;
        }
        if (!empty($thumb_widths)) {
            if (in_array($params['thumbwidth'], $thumb_widths)) {
                $width = $params['thumbwidth'];
            } else {
                header("HTTP/1.1 404 Not Found");
                echo "Invalid thumbnail width", "<br />", "valid thumb widths are ", implode(', ', $thumb_widths);
                return;
            }
        } else {
            $width = $params['thumbwidth'];
        }
        $thumb_width = $width;
        $force_thumb = true;
    } else {
        // automatically generate thumb images to support low-bandwidth mobile version
        if (is_mobile()) {
            $force_thumb = (!isset($params['m']) or $params['m'] == 1);
        }
    }
    // generate thumb file to support low-bandwidth mobile version
    $thumbfile = '';
    while ((!empty($params['thumb']) or $force_thumb) and preg_match('/^image\\/(jpe?g|gif|png)$/', $mimetype)) {
        if (empty($thumb_width)) {
            $thumb_width = 320;
            // default
            if (!empty($DBInfo->fetch_thumb_width)) {
                $thumb_width = $DBInfo->fetch_thumb_width;
            }
        }
        $thumbfile = preg_replace('@' . $ext . '$@', '.w' . $thumb_width . $ext, $fetchfile);
        if (empty($params['refresh']) && file_exists($thumbfile)) {
            break;
        }
        list($w, $h) = getimagesize($fetchfile);
        if ($w <= $thumb_width) {
            $thumbfile = $fetchfile;
            break;
        }
        require_once 'lib/mediautils.php';
        // generate thumbnail using the gd func or the ImageMagick(convert)
        resize_image($ext, $fetchfile, $thumbfile, $w, $h, $thumb_width);
        break;
    }
    $down_mode = 'inline';
    if (!empty($thumbfile)) {
        $fetchfile = $thumbfile;
    }
    header("Content-Type: {$mimetype}\r\n");
    header("Content-Length: " . filesize($fetchfile));
    //header("Content-Disposition: $down_mode; ".$fname );
    header("Content-Description: MoniWiki PHP Fetch Downloader");
    $mtime = filemtime($fetchfile);
    $lastmod = gmdate("D, d M Y H:i:s", $mtime) . ' GMT';
    $etag = md5($lastmod . $url . $thumbfile);
    header("Last-Modified: " . $lastmod);
    header('ETag: "' . $etag . '"');
    header("Pragma:");
    header('Cache-Control: public, max-age=' . $maxage);
    $need = http_need_cond_request($mtime, $lastmod, $etag);
    if (!$need) {
        header('X-Cache-Debug: Cached OK');
        header('HTTP/1.0 304 Not Modified');
        @ob_end_clean();
        return null;
    }
    @ob_clean();
    $ret = readfile($fetchfile);
    return null;
}
Ejemplo n.º 7
0
 function identicon_build($seed = '', $img = true, $outsize = '', $random = true, $displaysize = '')
 {
     //make an identicon and return the filepath or if write=false return picture directly
     if (function_exists("gd_info")) {
         // init random seed
         if ($random) {
             $id = substr(sha1($seed), 0, 10);
             mt_srand(hexdec($id));
         } else {
             $id = $seed;
         }
         if ($outsize == '') {
             $outsize = $this->identicon_options['size'];
         }
         if ($displaysize == '') {
             $displaysize = $outsize;
         }
         // HTTP Conditional get.
         $mtime = filemtime(__FILE__);
         $lastmod = substr(gmdate('r', $mtime), 0, -5) . 'GMT';
         $etag = $mtime . $displaysize . $outsize . $id;
         $etag = md5($etag);
         $need = http_need_cond_request($mtime, $lastmod, $etag);
         $maxage = 60 * 60 * 24 * 7;
         header('Last-Modified: ' . $lastmod);
         header('ETag: "' . $etag . '"');
         header('Cache-Control: public, max-age=' . $maxage);
         header('Pragma: cache');
         if (!$need) {
             header('HTTP/1.0 304 Not Modified');
             @ob_end_clean();
             return true;
         }
         //
         $this->im = imagecreatetruecolor($this->size, $this->size);
         $this->colors = array(imagecolorallocate($this->im, 255, 255, 255));
         if ($random) {
             $this->identicon_set_randomness($id);
         } else {
             $this->colors = array(imagecolorallocate($this->im, 255, 255, 255), imagecolorallocate($this->im, 0, 0, 0));
             $this->transparent = false;
         }
         imagefill($this->im, 0, 0, $this->colors[0]);
         for ($i = 0; $i < $this->blocks; $i++) {
             for ($j = 0; $j < $this->blocks; $j++) {
                 $this->identicon_draw_shape($i, $j);
             }
         }
         $out = @imagecreatetruecolor($outsize, $outsize);
         imagesavealpha($out, true);
         imagealphablending($out, false);
         imagecopyresampled($out, $this->im, 0, 0, 0, 0, $outsize, $outsize, $this->size, $this->size);
         imagedestroy($this->im);
         header("Content-type: image/png");
         imagepng($out);
         imagedestroy($out);
         return true;
     } else {
         //php GD image manipulation is required
         return false;
         //php GD image isn't installed but don't want to mess up blog layout
     }
 }
Ejemplo n.º 8
0
function do_editstat($formatter, $params = array())
{
    global $Config;
    $opts = array();
    $opts['.oldest'] = !empty($Config['editstat_datetime_oldest']) ? $Config['editstat_datetime_oldest'] : '-1 year';
    if (!empty($params['days'])) {
        $days = intval($params['days']);
    } else {
        $days = 50;
    }
    // default 50 days
    if ($days > 200) {
        $days = 200;
    }
    $opts['.max_range'] = $days . ' day';
    // image height
    if (!empty($params['h'])) {
        $height = intval($params['h']);
    } else {
        $height = 30;
    }
    // default image height
    if ($height > 200) {
        $height = 200;
    }
    // check request paramters
    if (isset($params['type']) && $params['type'] == 'user') {
        $type = 'user_count';
    } else {
        $type = 'data';
    }
    // round timestamp
    $tmp = time();
    $tmp = date('Y-m-d 00:00:00', $tmp);
    $time = strtotime($tmp);
    // setup headers
    $lastmod = substr(gmdate('r', $time), 0, -5) . 'GMT';
    $tag = $type . ',' . $time . ',' . $days . ',' . $height;
    $etag = md5($tag);
    $need = http_need_cond_request($time, $lastmod, $etag);
    if (!$need) {
        header('HTTP/1.0 304 Not Modified');
        @ob_end_clean();
        return;
    }
    // get editlogbin
    $data = cached_editlogbin($formatter, $opts);
    // check max
    $j = 0;
    $max = 0;
    foreach ($data[$type] as $idx => $c) {
        if ($c > $max) {
            $max = $c;
        }
        if (++$j > 30) {
            break;
        }
    }
    // graph parameters
    $wpen = 3;
    // pen width
    $gap = 1;
    // margin
    // $days + today
    $width = ($days + 1) * ($wpen + $gap) + $gap;
    $nolab = false;
    // make transparent image
    $canvas = imagecreatetruecolor($width, $height + ($nolab ? 0 : 8) + $gap * 2);
    imagealphablending($canvas, false);
    $bg = imagecolorallocatealpha($canvas, 255, 255, 255, 127);
    imagefill($canvas, 0, 0, $bg);
    imagesavealpha($canvas, true);
    $pens = array();
    $r = 128;
    $g = 128;
    $b = 128;
    $pens[0] = imagecolorallocate($canvas, $r, $g, $b);
    $r = 185;
    $g = 180;
    $b = 184;
    $pens[1] = imagecolorallocate($canvas, $r, $g, $b);
    if (!$nolab) {
        $lab = $type[0] == 'u' ? 'Edit users' : 'Editstat';
        imagestring($canvas, 1, 2, $height + 1, $lab . ' ' . date('Y-m-d H:i'), $pens[0]);
    }
    $x = $gap;
    $tmp = strtotime('-' . $days . ' days');
    // week
    $time = strtotime(date('Y-m-d 00:00:00', $tmp));
    $n = date('w', $time) - 1;
    $pen = 0;
    foreach ($data[$type] as $idx => $c) {
        $h = (int) ($c / $max * $height + 0.5);
        if ($n >= 7) {
            // change pen color for each weeks
            $pen++;
            $pen = $pen % 2;
            $n = 0;
        }
        imagefilledrectangle($canvas, $x, $height, $x + $wpen - 1, $height - $h, $pens[$pen]);
        $x += $wpen + $gap;
        $n++;
    }
    // setup expires
    $time = strtotime('+1 day');
    $tmp = strtotime(date('Y-m-d 00:00:00', $time));
    $expires = gmdate("D, d M Y H:i:s", $tmp) . ' GMT';
    header('Content-Type: image/png');
    $maxage = 60 * 60 * 24;
    header('Cache-Control: public, s-maxage=' . $maxage . ', max-age=' . $maxage);
    header('Last-Modified: ' . $lastmod);
    header('Expires: ' . $expires);
    header('ETag:"' . $etag . '"');
    imagepng($canvas);
    imagedestroy($canvas);
}
Ejemplo n.º 9
0
function do_retroidenticon($formatter, $params = array())
{
    $pixeldim = 5;
    $pixelsize = 80;
    $outsize = $pixelsize * $pixeldim;
    // Please see http://writings.orangegnome.com/writes/creating-identicons/
    // Get seed
    if (!empty($params['seed'])) {
        $seed = $params['seed'];
    } else {
        $seed = md5($_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT']);
    }
    if (!empty($params['pixelsize']) and $params['pixelsize'] > 1 and $params['pixelsize'] < 80) {
        $pixelsize = $params['pixelsize'];
        $outsize = $pixelsize * $pixeldim;
    }
    // HTTP Conditional get.
    $mtime = filemtime(__FILE__);
    $lastmod = substr(gmdate('r', $mtime), 0, -5) . 'GMT';
    $etag = $mtime . $outsize . $seed;
    $etag = md5($etag);
    $need = http_need_cond_request($mtime, $lastmod, $etag);
    $maxage = 60 * 60 * 24 * 7;
    header('Last-Modified: ' . $lastmod);
    header('ETag: "' . $etag . '"');
    header('Cache-Control: public, max-age=' . $maxage);
    header('Pragma: cache');
    if (!$need) {
        header('HTTP/1.0 304 Not Modified');
        @ob_end_clean();
        return true;
    }
    // Convert seed to MD5
    $hash = md5($seed);
    // Get color from first 6 characters
    $color = substr($hash, 0, 6);
    $pixels = array();
    // make a multidimension array
    $half = round(($pixeldim - 1) / 2);
    for ($j = 0; $j < $pixeldim; $j++) {
        for ($i = 0; $i <= $half; $i++) {
            $k = 6 + $i * $pixeldim + $j;
            $pixels[$i][$j] = hexdec(substr($hash, $k, 1)) % 2 === 1;
            $pixels[$pixeldim - $i - 1][$j] = $pixels[$i][$j];
        }
    }
    // set image size
    $image = imagecreatetruecolor($outsize, $outsize);
    // forground color. The hex code we assigned earlier needs to be decoded to RGB
    $color = imagecolorallocate($image, hexdec(substr($color, 0, 2)) & 255, hexdec(substr($color, 2, 2)) & 255, hexdec(substr($color, 4, 2)) & 255);
    // FIXME background color
    $bg = imagecolorallocate($image, 238, 238, 238);
    // Color the pixels
    for ($k = 0; $k < count($pixels); $k++) {
        for ($l = 0; $l < count($pixels[$k]); $l++) {
            // default pixel color is the background color
            $pixel = $bg;
            // If the value in the $pixels array is true, make the pixel color the primary color
            if ($pixels[$k][$l]) {
                $pixel = $color;
            }
            // Color the pixel. In a 400x400 image with a 5x5 grid of "pixels", each "pixel" is 80x80
            imagefilledrectangle($image, $k * $pixelsize, $l * $pixelsize, ($k + 1) * $pixelsize, ($l + 1) * $pixelsize, $pixel);
        }
    }
    // Output the image
    header('Content-type: image/png');
    imagepng($image);
    imagedestroy($image);
    return;
}
Ejemplo n.º 10
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('&', '&amp;', $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('&', '&amp;', $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');
}
Ejemplo n.º 11
0
function wiki_main($options)
{
    global $DBInfo, $Config;
    $pagename = isset($options['pagename'][0]) ? $options['pagename'] : $DBInfo->frontpage;
    # get primary variables
    if (isset($_SERVER['REQUEST_METHOD']) and $_SERVER['REQUEST_METHOD'] == 'POST') {
        // reset some reserved variables
        if (isset($_POST['retstr'])) {
            unset($_POST['retstr']);
        }
        if (isset($_POST['header'])) {
            unset($_POST['header']);
        }
        # hack for TWiki plugin
        $action = '';
        if (!empty($_FILES['filepath']['name'])) {
            $action = 'draw';
        }
        if (isset($GLOBALS['HTTP_RAW_POST_DATA'])) {
            # hack for Oekaki: PageName----action----filename
            list($pagename, $action, $value) = explode('----', $pagename, 3);
            $options['value'] = $value;
        } else {
            $value = !empty($_POST['value']) ? $_POST['value'] : '';
            $action = !empty($_POST['action']) ? $_POST['action'] : $action;
            if (empty($action)) {
                $dum = explode('----', $pagename, 3);
                if (isset($dum[0][0]) && isset($dum[1][0])) {
                    $pagename = trim($dum[0]);
                    $action = trim($dum[1]);
                    $value = isset($dum[2][0]) ? $dum[2] : '';
                }
            }
        }
        $goto = !empty($_POST['goto']) ? $_POST['goto'] : '';
        $popup = !empty($_POST['popup']) ? 1 : 0;
        // ignore invalid POST actions
        if (empty($goto) and empty($action)) {
            header('Status: 405 Not allowed');
            return;
        }
    } else {
        // reset some reserved variables
        if (isset($_GET['retstr'])) {
            unset($_GET['retstr']);
        }
        if (isset($_GET['header'])) {
            unset($_GET['header']);
        }
        $action = !empty($_GET['action']) ? $_GET['action'] : '';
        $value = isset($_GET['value'][0]) ? $_GET['value'] : '';
        $goto = isset($_GET['goto'][0]) ? $_GET['goto'] : '';
        $rev = !empty($_GET['rev']) ? $_GET['rev'] : '';
        if ($options['id'] == 'Anonymous') {
            $refresh = 0;
        } else {
            $refresh = !empty($_GET['refresh']) ? $_GET['refresh'] : '';
        }
        $popup = !empty($_GET['popup']) ? 1 : 0;
    }
    // parse action
    // action=foobar, action=foobar/macro, action=foobar/json etc.
    $full_action = $action;
    $action_mode = '';
    if (($p = strpos($action, '/')) !== false) {
        $full_action = strtr($action, '/', '-');
        $action_mode = substr($action, $p + 1);
        $action = substr($action, 0, $p);
    }
    $options['page'] = $pagename;
    $options['action'] =& $action;
    $reserved = array('call', 'prefix');
    foreach ($reserved as $k) {
        unset($options[$k]);
    }
    // unset all reserved
    // check pagename length
    $key = $DBInfo->pageToKeyname($pagename);
    if (!empty($options['action']) && strlen($key) > 255) {
        $i = 252;
        // 252 + reserved 3 (.??) = 255
        $newname = $DBInfo->keyToPagename(substr($key, 0, 252));
        $j = mb_strlen($newname, $Config['charset']);
        $j--;
        do {
            $newname = mb_substr($pagename, 0, $j, $Config['charset']);
            $key = $DBInfo->pageToKeyname($newname);
        } while (strlen($key) > 248 && --$j > 0);
        $options['page'] = $newname;
        $options['orig_pagename'] = $pagename;
        // original page name
        $pagename = $newname;
    } else {
        $options['orig_pagename'] = '';
    }
    if (function_exists('local_pre_check')) {
        local_pre_check($action, $options);
    }
    // load ruleset
    if (!empty($Config['config_ruleset'])) {
        $ruleset_file = 'config/ruleset.' . $Config['config_ruleset'] . '.php';
        if (file_exists($ruleset_file)) {
            $ruleset = load_ruleset($ruleset_file);
            $Config['ruleset'] = $ruleset;
        }
        // is it robot ?
        if (!empty($ruleset['allowedrobot'])) {
            if (empty($_SERVER['HTTP_USER_AGENT'])) {
                $options['is_robot'] = 1;
            } else {
                $options['is_robot'] = is_allowed_robot($ruleset['allowedrobot'], $_SERVER['HTTP_USER_AGENT']);
            }
        }
        // setup staff members
        if (!empty($ruleset['staff'])) {
            $DBInfo->members = array_merge($DBInfo->members, $ruleset['staff']);
        }
    }
    $page = $DBInfo->getPage($pagename);
    $page->is_static = false;
    // FIXME
    $pis = array();
    // get PI cache
    if ($page->exists()) {
        $page->pi = $pis = $page->get_instructions('', array('refresh' => $refresh));
        // set some PIs for robot
        if (!empty($options['is_robot'])) {
            $DBInfo->use_sectionedit = 0;
            # disable section edit
            $page->is_static = true;
        } else {
            if ($_SERVER['REQUEST_METHOD'] == 'GET' or $_SERVER['REQUEST_METHOD'] == 'HEAD') {
                if (empty($action) and empty($refresh)) {
                    $page->is_static = empty($pis['#nocache']) && empty($pis['#dynamic']);
                }
            }
        }
    }
    // HEAD support for robots
    if (empty($action) and !empty($_SERVER['REQUEST_METHOD']) and $_SERVER['REQUEST_METHOD'] == 'HEAD') {
        if (!$page->exists()) {
            header("HTTP/1.1 404 Not found");
            header("Status: 404 Not found");
        } else {
            if ($page->is_static or is_static_action($options)) {
                $mtime = $page->mtime();
                $etag = $page->etag($options);
                $lastmod = gmdate('D, d M Y H:i:s \\G\\M\\T', $mtime);
                header('Last-Modified: ' . $lastmod);
                if (!empty($action)) {
                    $etag = '"' . $etag . '"';
                    header('ETag: ' . $etag);
                }
                // checksum request
                if (isset($_SERVER['HTTP_X_GET_CHECKSUM'])) {
                    header('X-Checksum: md5-' . md5($page->get_raw_body()));
                }
            }
        }
        return;
    }
    if (is_static_action($options) or !empty($DBInfo->use_conditional_get) and $page->is_static) {
        $mtime = $page->mtime();
        $etag = $page->etag($options);
        $lastmod = gmdate('D, d M Y H:i:s \\G\\M\\T', $mtime);
        $need = http_need_cond_request($mtime, $lastmod, $etag);
        if (!$need) {
            @ob_end_clean();
            $headers = array();
            $headers[] = 'HTTP/1.0 304 Not Modified';
            $headers[] = 'Last-Modified: ' . $lastmod;
            foreach ($headers as $header) {
                header($header);
            }
            return;
        }
    }
    $formatter = new Formatter($page, $options);
    $formatter->refresh = !empty($refresh) ? $refresh : '';
    $formatter->popup = !empty($popup) ? $popup : '';
    $formatter->tz_offset = $options['tz_offset'];
    // check blocklist/whitelist for block_actions
    $act = strtolower($action);
    while (!empty($DBInfo->block_actions) && !empty($ruleset) && in_array($act, $DBInfo->block_actions)) {
        require_once 'lib/checkip.php';
        // check whitelist
        if (isset($ruleset['whitelist']) && check_ip($ruleset['whitelist'], $_SERVER['REMOTE_ADDR'])) {
            break;
        }
        $res = null;
        // check blacklist
        if (isset($ruleset['blacklist']) && check_ip($ruleset['blacklist'], $_SERVER['REMOTE_ADDR']) || isset($ruleset['blacklist.ranges']) && search_network($ruleset['blacklist.ranges'], $_SERVER['REMOTE_ADDR'])) {
            $res = true;
        } else {
            if (!empty($DBInfo->use_dynamic_blacklist)) {
                require_once 'plugin/ipinfo.php';
                $blacklist = get_cached_temporary_blacklist();
                $retval = array();
                $ret = array('retval' => &$retval);
                $res = search_network($blacklist, $_SERVER['REMOTE_ADDR'], $ret);
                if ($res !== false) {
                    // retrieve found
                    $ac = new Cache_Text('ipblock');
                    $info = $ac->fetch($retval, 0, $ret);
                    if ($info !== false) {
                        if (!$info['suspended']) {
                            // whitelist IP
                            break;
                        }
                        $res = true;
                    } else {
                        $ac->remove($retval);
                        // expired IP entry.
                        $res = false;
                    }
                }
            }
        }
        // show warning message
        if ($res) {
            $options['notice'] = _("Your IP is in the blacklist");
            $options['msg'] = _("Please contact WikiMasters");
            $options['msgtype'] = 'warn';
            if (!empty($DBInfo->edit_actions) and in_array($act, $DBInfo->edit_actions)) {
                $options['action'] = $action = 'edit';
            } else {
                if ($act != 'edit') {
                    $options['action'] = $action = 'show';
                }
            }
            break;
        }
        // check kiwirian
        if (isset($ruleset['kiwirian']) && in_array($options['id'], $ruleset['kiwirian'])) {
            $options['title'] = _("You are blocked in this wiki");
            $options['msg'] = _("Please contact WikiMasters");
            do_invalid($formatter, $options);
            return false;
        }
        break;
    }
    // set robot class
    if (!empty($options['is_robot'])) {
        if (!empty($DBInfo->security_class_robot)) {
            $class = 'Security_' . $DBInfo->security_class_robot;
            include_once 'plugin/security/' . $DBInfo->security_class_robot . '.php';
        } else {
            $class = 'Security_robot';
            include_once 'plugin/security/robot.php';
        }
        $DBInfo->security = new $class($DBInfo);
        // is it allowed to robot ?
        if (!$DBInfo->security->is_allowed($action, $options)) {
            $action = 'show';
            if (!empty($action_mode)) {
                return '[]';
            }
        }
        $DBInfo->extra_macros = '';
    }
    while (empty($action) or $action == 'show') {
        if (isset($value[0])) {
            # ?value=Hello
            $options['value'] = $value;
            do_goto($formatter, $options);
            return true;
        } else {
            if (isset($goto[0])) {
                # ?goto=Hello
                $options['value'] = $goto;
                do_goto($formatter, $options);
                return true;
            }
        }
        if (!$page->exists()) {
            if (isset($options['retstr'])) {
                return false;
            }
            if (!empty($DBInfo->auto_search) && $action != 'show' && ($p = getPlugin($DBInfo->auto_search))) {
                $action = $DBInfo->auto_search;
                break;
            }
            // call notfound action
            $action = 'notfound';
            break;
        }
        # render this page
        if (isset($_GET['redirect']) and !empty($DBInfo->use_redirect_msg) and $action == 'show') {
            $redirect = $_GET['redirect'];
            $options['msg'] = '<h3>' . sprintf(_("Redirected from page \"%s\""), $formatter->link_tag(_rawurlencode($redirect), '?action=show', $redirect)) . "</h3>";
        }
        if (empty($action)) {
            $options['pi'] = 1;
        }
        # protect a recursivly called #redirect
        if (!empty($DBInfo->control_read) and !$DBInfo->security->is_allowed('read', $options)) {
            $options['action'] = 'read';
            do_invalid($formatter, $options);
            return;
        }
        $formatter->pi = $formatter->page->get_instructions();
        if (!empty($DBInfo->body_attr)) {
            $options['attr'] = $DBInfo->body_attr;
        }
        $ret = $formatter->send_header('', $options);
        if (empty($options['is_robot'])) {
            if ($DBInfo->use_counter) {
                $DBInfo->counter->incCounter($pagename, $options);
            }
            if (!empty($DBInfo->use_referer) and isset($_SERVER['HTTP_REFERER'])) {
                log_referer($_SERVER['HTTP_REFERER'], $pagename);
            }
        }
        $formatter->send_title("", "", $options);
        $formatter->write("<div id='wikiContent'>\n");
        if (isset($options['timer']) and is_object($options['timer'])) {
            $options['timer']->Check("init");
        }
        // force #nocache for #redirect pages
        if (isset($formatter->pi['#redirect'][0])) {
            $formatter->pi['#nocache'] = 1;
        }
        $extra_out = '';
        $options['pagelinks'] = 1;
        if (!empty($Config['cachetime']) and $Config['cachetime'] > 0 and empty($formatter->pi['#nocache'])) {
            $cache = new Cache_text('pages', array('ext' => 'html'));
            $mcache = new Cache_text('dynamic_macros');
            $mtime = $cache->mtime($pagename);
            $now = time();
            $check = $now - $mtime;
            $_macros = null;
            if ($cache->mtime($pagename) < $formatter->page->mtime()) {
                $formatter->refresh = 1;
            }
            // force update
            $valid = false;
            $delay = !empty($DBInfo->default_delaytime) ? $DBInfo->default_delaytime : 0;
            if (empty($formatter->refresh) and $DBInfo->checkUpdated($mtime, $delay) and $check < $Config['cachetime']) {
                if ($mcache->exists($pagename)) {
                    $_macros = $mcache->fetch($pagename);
                }
                // FIXME TODO: check postfilters
                if (0 && empty($_macros)) {
                    #$out = $cache->fetch($pagename);
                    $valid = $cache->fetch($pagename, '', array('print' => 1));
                } else {
                    $out = $cache->fetch($pagename);
                    $valid = $out !== false;
                }
                $mytime = gmdate("Y-m-d H:i:s", $mtime + $options['tz_offset']);
                $extra_out = "<!-- Cached at {$mytime} -->";
            }
            if (!$valid) {
                $formatter->_macrocache = 1;
                ob_start();
                $formatter->send_page('', $options);
                flush();
                $out = ob_get_contents();
                ob_end_clean();
                $formatter->_macrocache = 0;
                $_macros = $formatter->_dynamic_macros;
                if (!empty($_macros)) {
                    $mcache->update($pagename, $_macros);
                }
                if (isset($out[0])) {
                    $cache->update($pagename, $out);
                }
            }
            if (!empty($_macros)) {
                $mrule = array();
                $mrepl = array();
                foreach ($_macros as $m => $v) {
                    if (!is_array($v)) {
                        continue;
                    }
                    $mrule[] = '@@' . $v[0] . '@@';
                    $options['mid'] = $v[1];
                    $mrepl[] = $formatter->macro_repl($m, '', $options);
                    // XXX
                }
                echo $formatter->get_javascripts();
                $out = str_replace($mrule, $mrepl, $out);
                // no more dynamic macros found
                if (empty($formatter->_dynamic_macros)) {
                    // update contents
                    $cache->update($pagename, $out);
                    // remove dynamic macros cache
                    $mcache->remove($pagename);
                }
            }
            if ($options['id'] != 'Anonymous') {
                $args['refresh'] = 1;
            }
            // add refresh menu
        } else {
            ob_start();
            $formatter->send_page('', $options);
            flush();
            $out = ob_get_contents();
            ob_end_clean();
        }
        // fixup to use site specific thumbwidth
        if (!empty($Config['site_thumb_width']) and $Config['site_thumb_width'] != $DBInfo->thumb_width) {
            $opts = array('thumb_width' => $Config['site_thumb_width']);
            $out = $formatter->postfilter_repl('imgs_for_mobile', $out, $opts);
        }
        echo $out, $extra_out;
        // automatically set #dynamic PI
        if (empty($formatter->pi['#dynamic']) and !empty($formatter->_dynamic_macros)) {
            $pis = $formatter->pi;
            if (empty($pis['raw'])) {
                // empty PIs
                $pis = array();
            } else {
                if (isset($pis['#format']) and !preg_match('/#format\\s/', $pis['raw'])) {
                    // #format not found in PIs
                    unset($pis['#format']);
                }
            }
            $pis['#dynamic'] = 1;
            // internal instruction
            $pi_cache = new Cache_text('PI');
            $pi_cache->update($formatter->page->name, $pis);
        } else {
            if (empty($formatter->_dynamic_macros) and !empty($formatter->pi['#dynamic'])) {
                $pi_cache = new Cache_text('PI');
                $pi_cache->remove($formatter->page->name);
                // reset PI
                $mcache->remove($pagename);
                // remove macro cache
                if (isset($out[0])) {
                    $cache->update($pagename, $out);
                }
                // update cache content
            }
        }
        if (isset($options['timer']) and is_object($options['timer'])) {
            $options['timer']->Check("send_page");
        }
        $formatter->write("<!-- wikiContent --></div>\n");
        if (!empty($DBInfo->extra_macros) and $formatter->pi['#format'] == $DBInfo->default_markup) {
            if (!empty($formatter->pi['#nocomment'])) {
                $options['nocomment'] = 1;
                $options['notoolbar'] = 1;
            }
            $options['mid'] = 'dummy';
            echo '<div id="wikiExtra">' . "\n";
            $mout = '';
            $extra = array();
            if (is_array($DBInfo->extra_macros)) {
                $extra = $DBInfo->extra_macros;
            } else {
                $extra[] = $DBInfo->extra_macros;
            }
            // XXX
            if (!empty($formatter->pi['#comment'])) {
                array_unshift($extra, 'Comment');
            }
            foreach ($extra as $macro) {
                $mout .= $formatter->macro_repl($macro, '', $options);
            }
            echo $formatter->get_javascripts();
            echo $mout;
            echo '</div>' . "\n";
        }
        $args['editable'] = 1;
        $formatter->send_footer($args, $options);
        return;
    }
    $act = $action;
    if (!empty($DBInfo->myplugins) and array_key_exists($action, $DBInfo->myplugins)) {
        $act = $DBInfo->myplugins[$action];
    }
    if ($act) {
        $options['noindex'] = true;
        $options['custom'] = '';
        $options['help'] = '';
        $options['value'] = $value;
        $a_allow = $DBInfo->security->is_allowed($act, $options);
        if (!empty($action_mode)) {
            $myopt = $options;
            $myopt['explicit'] = 1;
            $f_allow = $DBInfo->security->is_allowed($full_action, $myopt);
            # check if hello/ajax is defined or not
            if ($f_allow === false && $a_allow) {
                $f_allow = $a_allow;
            }
            # follow action permission if it is not defined explicitly.
            if (!$f_allow) {
                $args = array('action' => $action);
                $args['allowed'] = $options['allowed'] = $f_allow;
                if ($f_allow === false) {
                    $title = sprintf(_("%s action is not found."), $action);
                } else {
                    $title = sprintf(_("Invalid %s action."), $action_mode);
                }
                if ($action_mode == 'ajax') {
                    $args['title'] = $title;
                    return ajax_invalid($formatter, $args);
                }
                $options['title'] = $title;
                return do_invalid($formatter, $options);
            }
        } else {
            if (!$a_allow) {
                $options['allowed'] = $a_allow;
                if ($options['custom'] != '' and method_exists($DBInfo->security, $options['custom'])) {
                    $options['action'] = $action;
                    if ($action) {
                        call_user_func(array(&$DBInfo->security, $options['custom']), $formatter, $options);
                    }
                    return;
                }
                return do_invalid($formatter, $options);
            } else {
                if ($_SERVER['REQUEST_METHOD'] == "POST" and $DBInfo->security->is_protected($act, $options) and !$DBInfo->security->is_valid_password($_POST['passwd'], $options)) {
                    # protect some POST actions and check a password
                    $title = sprintf(_("Fail to \"%s\" !"), $action);
                    $formatter->send_header("", $options);
                    $formatter->send_title($title, "", $options);
                    $formatter->send_page("== " . _("Please enter the valid password") . " ==");
                    $formatter->send_footer("", $options);
                    return;
                }
            }
        }
        $options['action_mode'] = '';
        if (!empty($action_mode) and in_array($action_mode, array('ajax', 'macro'))) {
            if ($_SERVER['REQUEST_METHOD'] == "POST") {
                $options = array_merge($_POST, $options);
            } else {
                $options = array_merge($_GET, $options);
            }
            $options['action_mode'] = $action_mode;
            if ($action_mode == 'ajax') {
                $formatter->ajax_repl($action, $options);
            } else {
                if (!empty($DBInfo->use_macro_as_action)) {
                    # XXX
                    echo $formatter->macro_repl($action, $options['value'], $options);
                } else {
                    do_invalid($formatter, $options);
                }
            }
            return;
        }
        // is it valid action ?
        $plugin = $pn = getPlugin($action);
        if ($plugin === '') {
            // action not found
            $plugin = $action;
        }
        if (!function_exists("do_post_" . $plugin) and !function_exists("do_" . $plugin) and $pn) {
            include_once "plugin/{$pn}.php";
        }
        if (function_exists("do_" . $plugin)) {
            if ($_SERVER['REQUEST_METHOD'] == "POST") {
                $options = array_merge($_POST, $options);
            } else {
                $options = array_merge($_GET, $options);
            }
            call_user_func("do_{$plugin}", $formatter, $options);
            return;
        } else {
            if (function_exists("do_post_" . $plugin)) {
                if ($_SERVER['REQUEST_METHOD'] == "POST") {
                    $options = array_merge($_POST, $options);
                } else {
                    # do_post_* set some primary variables as $options
                    $options['value'] = isset($_GET['value'][0]) ? $_GET['value'] : '';
                }
                call_user_func("do_post_{$plugin}", $formatter, $options);
                return;
            }
        }
        do_invalid($formatter, $options);
        return;
    }
}
Ejemplo n.º 12
0
function do_sitemap($formatter, $options)
{
    global $DBInfo, $Config;
    $tc = new Cache_text('persist', array('depth' => 0));
    $extra = '';
    if (!empty($formater->group)) {
        $extra = '.' . $formatter->group;
    }
    if (!empty($formatter->prefix)) {
        $extra .= qualifiedUrl($formatter->prefix);
    }
    // all pages
    $mtime = $DBInfo->mtime();
    $lastmod = gmdate('D, d M Y H:i:s \\G\\M\\T', $mtime);
    $etag = md5($mtime . $DBInfo->etag_seed . $extra);
    $options['etag'] = $etag;
    $options['mtime'] = $mtime;
    // set the s-maxage for proxy
    $date = gmdate('Y-m-d-H-i-s', $mtime);
    $proxy_maxage = !empty($Config['proxy_maxage']) ? ', s-maxage=' . $Config['proxy_maxage'] : '';
    // only xml format supported
    $format = 'text/xml';
    if (isset($options['format']) and in_array($options['format'], array('text/xml'))) {
        $format = $options['format'];
    }
    $header[] = 'Content-Type: ' . $format;
    $header[] = 'Cache-Control: public' . $proxy_maxage . ', max-age=0, must-revalidate';
    $need = http_need_cond_request($mtime, $lastmod, $etag);
    if (!$need) {
        $header[] = 'HTTP/1.0 304 Not Modified';
    } else {
        $header[] = 'Content-Disposition: attachment; filename="sitemap-' . $date . '.xml"';
    }
    $formatter->send_header($header, $options);
    if (!$need) {
        @ob_end_clean();
        return;
    }
    if (!$formatter->refresh && ($ret = $tc->fetch('sitemap' . $extra . '.mtime')) !== false) {
        if (($ret = $tc->fetch('sitemap' . $extra, 0, array('print' => 1))) !== false) {
            return;
        }
    }
    // set sitemap public cache
    $ext = $format == 'text/xml' ? 'xml' : 'txt';
    $sc = new Cache_text('sitemap', array('dir' => $DBInfo->cache_public_dir, 'ext' => $ext, 'depth' => 0));
    # get page list
    set_time_limit(0);
    if ($formater->group) {
        $group_pages = $DBInfo->getLikePages($formater->group);
        foreach ($group_pages as $page) {
            $all_pages[] = str_replace($formatter->group, '', $page);
        }
        usort($all_pages, 'strcasecmp');
    } else {
        if (!empty($Config['sitemap_sortby'])) {
            // call PageSort macro.
            $opts = array();
            $opts['sortby'] = $Config['sitemap_sortby'];
            // date or size
            $opts['.call'] = 1;
            $ret = $formatter->macro_repl('PageSort', '', $opts);
            $all_pages = array();
            if (!empty($ret['count'])) {
                $tc->fetch('pagedate.raw');
                $rawfile = $tc->cache_path . '/' . $tc->getKey('pagedate.raw');
                $fp = fopen($rawfile, 'r');
                if (is_resource($fp)) {
                    while (($line = fgets($fp, 1024)) != false) {
                        $tmp = explode("\t", $line);
                        $all_pages[] = $tmp[0];
                    }
                    fclose($fp);
                }
            }
        } else {
            $args = array('all' => 1);
            $all_pages = $DBInfo->getPageLists($args);
            usort($all_pages, 'strcasecmp');
        }
    }
    $count = sizeof($all_pages);
    $map = '';
    $zone = '+00:00';
    $ttl = !empty($DBInfo->sitemap_ttl) ? $DBInfo->sitemap_ttl : 60 * 60 * 24 * 7;
    if ($count > 50000) {
        $map = <<<HEAD
<?xml version="1.0" encoding="UTF-8"?>
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">

HEAD;
        $date = gmdate("Y-m-d\\TH:i:s", time()) . $zone;
        // W3C datetime format
        $total = intval($count / 50000) + ($count % 50000 > 0 ? 1 : 0);
        for ($i = 0; $i < $total; $i++) {
            $mapname = $sc->getKey(sprintf('sitemap' . $extra . '%03d', $i));
            $map .= "<sitemap>\n<loc>\n" . qualifiedUrl($DBInfo->cache_public_url . '/' . $mapname) . '</loc>' . "\n";
            $map .= '<lastmod>' . $date . "</lastmod>\n</sitemap>\n";
        }
        $map .= "</sitemapindex>\n";
        $tc->update('sitemap' . $extra, $map);
        $tc->update('sitemap' . $extra . '.mtime', array('dummy' => 1), $ttl);
    }
    # charset
    if ($options['oe'] and strtolower($options['oe']) != $DBInfo->charset) {
        $charset = $options['oe'];
    } else {
        $charset = $DBInfo->charset;
    }
    $head = <<<HEAD
<?xml version="1.0" encoding="{$charset}"?>
<urlset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9"
         url="http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"
         xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">

HEAD;
    $foot = <<<FOOT
</urlset>
FOOT;
    # process page list
    $i = 0;
    $ii = 0;
    $items = array();
    foreach ($all_pages as $page) {
        $ii++;
        $url = qualifiedUrl($formatter->link_url(_rawurlencode($page)));
        $p = new WikiPage($page);
        $t = $p->mtime();
        $date = gmdate("Y-m-d\\TH:i:s", $t) . $zone;
        // W3C datetime format
        $item = "<url>\n";
        $item .= "  <loc>" . $url . "</loc>\n";
        $item .= "  <lastmod>" . $date . "</lastmod>\n";
        $item .= "</url>";
        $items[] = $item;
        if ($ii >= 50000) {
            $ii = 0;
            // process output
            $out = implode("\n", $items);
            if ($options['oe'] and strtolower($options['oe']) != $DBInfo->charset) {
                $charset = $options['oe'];
                if (function_exists('iconv')) {
                    $new = iconv($DBInfo->charset, $charset, $items);
                    if (!$new) {
                        $charset = $DBInfo->charset;
                    }
                    if ($new) {
                        $out = $new;
                    }
                }
            }
            $sc->update(sprintf('sitemap' . $extra . '%03d', $i), $head . $out . $foot);
            $i++;
            $items = array();
        }
    }
    $sc->update('sitemap' . $extra . '.mtime', array('dummy' => 1), $ttl);
    // process output
    if ($count > 50000) {
        if (count($items)) {
            $out = implode("\n", $items);
            if ($options['oe'] and strtolower($options['oe']) != $DBInfo->charset) {
                $charset = $options['oe'];
                if (function_exists('iconv')) {
                    $new = iconv($DBInfo->charset, $charset, $items);
                    if (!$new) {
                        $charset = $DBInfo->charset;
                    }
                    if ($new) {
                        $out = $new;
                    }
                }
            }
            $sc->update(sprintf('sitemap' . $extra . '%03d', $i), $head . $out . $foot);
        }
    } else {
        $out = implode("\n", $items);
        if ($options['oe'] and strtolower($options['oe']) != $DBInfo->charset) {
            $charset = $options['oe'];
            if (function_exists('iconv')) {
                $new = iconv($DBInfo->charset, $charset, $items);
                if (!$new) {
                    $charset = $DBInfo->charset;
                }
                if ($new) {
                    $out = $new;
                }
            }
        }
        $map = $head . $out . $foot;
        $tc->update('sitemap' . $extra, $map);
        $tc->update('sitemap' . $extra, array('dummy' => 1), $ttl);
    }
    echo $map;
}