root > WikiSense-trunk > web > WikiProxy.php

WikiProxy.php

application/x-php, 13746 bytes (load raw)
<?php

if (!@$_SERVER['REQUEST_URI']) {
    if (@$argv[1] === '--fifo') {
        define('PROXY_FIFO_MODE', true);
    }
    else if (@$argv[1] === '--tcp') {
        define('PROXY_TCP_MODE', true);
    }
    else {
        define('PROXY_CONSOLE_MODE', true);
    }
   
    define( 'WS_CONSOLE', true );
}
else {
    define('PROXY_WEB_MODE', true);
    define( 'WS_WEB', true );
}   

require_once("common/WebInit.php");

function serve($wiki, $title, $ns, $rev, $meta, $force, &$response) {
    global $requestHeaders, $wsgProxyThrottle, $wsgProxyThrottleInterval;

    if ($title===false || $title==='') $title= NULL;
    if ($rev===false || $rev==='') $rev= NULL;
   
    if (is_null($wiki) || is_null($title)) {
        $response->header('Status: 400 Bad Request',true,400);
        $response->write("Missing wiki or title field in request");
        return false;
    }
   
    if (@$wsgProxyThrottle) {
        wsfThrottle('WikiProxy', $wsgProxyThrottle, @$wsgProxyThrottleInterval ? $wsgProxyThrottleInterval : 1 );
    }
   
    #TODO: cache last wiki - in batch requests, it's likely that we use the same one x times!
    $wiki=& WikiAccess::newInstance($wiki);

    if (!$wiki) {
        $response->header('Status: 400 Bad Request',true,400);
        $response->write("Bad wiki id, use full host name");
        return false;
    }
   
    if ($ns===false || $ns===NULL || $ns==='') {
        $ns= 0;
       
        if ($idx= strpos($title,':')) {
            $ns= substr($title,0,$idx);
           
            $wiki->initTranslations();
            #print "TRY NS: $ns;\n";
            $ns= $wiki->getNsIndex($ns);
            if ($ns) {
                $title= trim(substr($title,$idx+1));
            }
        }
    }
    else if (!is_numeric($ns)) {
        $wiki->initTranslations();
        #print "TRY NS: $ns;\n";
        $ns= $wiki->getNsIndex($ns);
    }
    else $ns= (int)$ns;
   
    #FIXME: add support for asking for an article by ID
    $rec= $wiki->fetchPageRecord($title,$ns,$rev);

    if (!$rec) {
        $response->header("HTTP/1.1 404 Not Found",true,404);
        $response->header('Content-Type: text/plain; charset=utf-8',true,404);
       
        if ($meta) $response->write("Not found!");
        else $response->write("\0");
    }
    else if ($meta) {
        $response->header('Content-Type: text/plain; charset=utf-8', true, NULL);
        $response->header('Content-Length: '.strlen($rec['text']), true, NULL);
        if (isset($rec['_cache'])) {
            $response->header('X-WikiProxy: '.$rec['_cache'],true,NULL);
            wsfLogScriptComment($rec['_cache']);
        }
       
        $rec['_text_len']= strlen($rec['text']);
           
        if (!@$response->is_http) {
            foreach ($rec as $k => $v) {
                if ($k=='text' || $k{0}=='_') continue;
                $response->header("X-Wiki-$k: $v",true,NULL);
            }
           
            $response->write(''); #flush headers
        }
        else {
            foreach ($rec as $k => $v) {
                if ($k=='text') continue;
                $response->write("$k: $v\r\n");
            }
        }
    }
    else {
        $response->header('Content-Type: text/plain; charset=utf-8',true,NULL);
        $response->header('Content-Length: '.strlen($rec['text']), true, NULL);
        if (isset($rec['_cache'])) {
            $response->header('X-WikiProxy: '.$rec['_cache'],true,NULL);
            wsfLogScriptComment($rec['_cache']);
        }
       
        if (!@$response->is_http) {
            $rec['_text_len']= strlen($rec['text']);
           
            foreach ($rec as $k => $v) {
                if ($k=='text' || $k{0}=='_') continue;
                $response->header("X-Wiki-$k: $v",true,NULL);
            }
        }
       
        $doout= true;
       
        if ( $requestHeaders && isset($rec['rev_timestamp']) && isset($requestHeaders["If-Modified-Since"]) && !$force ) {
            $since= wfTimestamp(TS_MW,$requestHeaders["If-Modified-Since"]);
           
            #TODO: cheack earlier, don't load text if not neccessary!           
            if ($since>=$rec['rev_timestamp']) {
                #print "$since >= {$rec['rev_timestamp']}";
           
                $response->header("HTTP/1.1 304 Not modified",true,304);
                $doout= false;
            }
        }               
       
        if (isset($rec['rev_timestamp'])) $response->header('Last-Modified: '.wfTimestamp(TS_RFC2822,$rec['rev_timestamp']),true,NULL);

        if ($doout) {
            $response->header('Content-Length: '.strlen($rec['text']),true,NULL);
           
            #FIXME: does not seem to work...
            /*if (strlen($rec['text'])>256) {
                ini_set('zlib.output_compression','On',true,NULL);
            }
            else {
                ini_set('zlib.output_compression',0);
                $response->header('Content-Length: '.strlen($rec['text']),true,NULL);
            }*/

           
            if (@$response->is_http) $response->header("HTTP/1.1 200 OK",true,200);
            $response->write($rec['text']);
        }
    }
   
    #TODO: in daemon mode, keep it open!
    $wiki->close();
}

function httpDie($code, $msg, $text) {
    header("Content-Type: text/plain",true,$code);
    header("HTTP/1.0 $code $msg",true,$code);
    header("Status: $code $msg",true,$code);
    print "\n***************************************\n";
    print "\nERROR: $code $msg\n";
    print "\n$text\n";
    print "\n***************************************\n";
    die();
}

function checkAccess() {
    global $wgRequest, $wsgContentAccessIPWhitelist, $wsgContentAccessTokens;
   
    if ($wsgContentAccessIPWhitelist === NULL || $wsgContentAccessIPWhitelist === true) {
        #print "*** WHITELIST ALL ***\n";
        return true;
    }
    else if ($wsgContentAccessIPWhitelist === false) {
        #print "*** WHITELIST NONE ***\n";
    }
    else if (is_array($wsgContentAccessIPWhitelist)) {
        if (isset($_SERVER['REMOTE_ADDR']) && in_array($_SERVER['REMOTE_ADDR'],$wsgContentAccessIPWhitelist)) {
            #print "*** WHITELIST ARRAY (IP MATCH {$_SERVER['REMOTE_ADDR']}) ***\n";
            return true;
        }
       
        if (isset($_SERVER['REMOTE_HOST']) && in_array($_SERVER['REMOTE_HOST'],$wsgContentAccessIPWhitelist)) {
            #print "*** WHITELIST ARRAY (HOST MATCH: {$_SERVER['REMOTE_HOST']}) ***\n";
            return true;
        }
       
        #print "*** WHITELIST ARRAY (NO MATCH) ***\n";
    }
   
    if ($wsgContentAccessTokens === NULL || $wsgContentAccessTokens === true) {
            #print "*** TOKENS ALL ***\n";
    }
    else if ($wsgContentAccessTokens === false) {
            #print "*** TOKENS NONE ***\n";
            httpDie(403, 'Forbidden', 'Access denied: You have requested this page from an external address.');
    }
    else if (is_array($wsgContentAccessTokens)) {
        $tok= $wgRequest->getVal('token');
       
        if (!$tok) {
            #print "*** TOKENS (MISSING) ***\n";
           
            if (!$wsgContentAccessIPWhitelist) httpDie(403,'Forbidden','Access Denied');
            else httpDie(403, 'Forbidden',
'You have requested this page from an external address.
An access token is required for accessing this page from the outside.'

                                            );
        }
       
        if (!in_array($tok, $wsgContentAccessTokens)) {
            #print "*** TOKENS (NO MATCH) ***\n";
            httpDie(403,'Forbidden', 'Access denied: bad token!');
        }
       
        #print "*** TOKENS (MATCH) ***\n";
    }

    return true;   
}

if (defined('PROXY_WEB_MODE')) {
    $wsgLogLevel= -100;
    $wsgWikiProxy= NULL; #NOTE: force proxy off, or we may be calling this script recursively!
   
    $wiki = $wgRequest->getVal('wiki');
    $title = $wgRequest->getVal('title');
    $ns = $wgRequest->getVal('ns');
    $rev = $wgRequest->getVal('rev');
   
    $meta = $wgRequest->getVal('meta');
    $force = $wgRequest->getVal('force');
   
    if (is_null($wiki) || is_null($title)) $go= false;
    else $go= true;

    if ($go) {
        if (!$meta && defined('PROXY_WEB_MODE')) checkAccess();
   
        require_once("WikiAccess.php");
       
        class HttpResponse {
            function HttpResponse() {
                $this->is_http= true;
            }
       
            function header($h, $override=true, $code=NULL) {
                header($h, $override, $code);
            }
           
            function write($data) {
                if ($data==='' || $data===NULL || $data===false) return;
                print $data;
            }
           
            function flush() {
                flush();
            }
        }
       
        $requestHeaders= NULL;
        if (function_exists('apache_request_headers')) {
            $requestHeaders = apache_request_headers();
        }
       
        $response= new HttpResponse();
        serve($wiki, $title, $ns, $rev, $meta, $force, $response);       
    }
    else {
        header('Content-Type: text/html; charset=utf-8');
       
        ?>
        <html>
        <head>
          <title>Wiki Proxy</title>
        </head>
        <body>
          <h1>Wiki Proxy</h1>
          <form method="get" action="<?= $_SERVER['PHP_SELF']?>">
            <p>Wiki: <input type='text' size='12' name='wiki' value='<?= escapeHtml($wiki) ?>'/></p>
            <p>Title: <input type='text' size='64' name='title' value='<?= escapeHtml($title) ?>'/></p>
            <p>Revision: <input type='text' size='6' name='rev' value='<?= escapeHtml($rev) ?>'/></p>
            <p><input type='submit' name='go' value='Fetch'/> &nbsp; <input type='submit' name='meta' value='Meta'/></p>
            <? if (@$wsgContentAccessTokens): ?>
            <p>Access token: <input type='text' size='24' name='token' value='<?= $rev ?>'/> <small>(required for external access)</small></p>
            <?endif?>
          </form>
        </body>
        </html>
        <?
    }
}


if (defined('PROXY_FIFO_MODE')) {
    require_once("WikiAccess.php");
    require_once("FifoServer.php");

    if (isset($options['ll'])) $wsgLogLevel= (int)$options['ll'];
    else if (isset($options['vv'])) $wsgLogLevel= LL_DEBUG;
    else if (isset($options['v'])) $wsgLogLevel= LL_VERBOSE;
   
    class FifoProxy extends FifoServer {   
        function FifoProxy( $fifo ) {
            FifoServer::FifoServer( $fifo );
        }
       
        function handleRequest( $req, &$response ) {
            $wiki = @$req['wiki'];
            $title = @$req['title'];
            $ns = @$req['ns'];
            $rev = @$req['rev'];
           
            $meta = @$req['meta'];
            $force = @$req['force'];

            if ($title===NULL) $title = @$req['']; //path
           
            serve($wiki, $title, $ns, $rev, $meta, $force, $response);
        }
    }

    $serverFifo= @$args[0];
   
    if (!$serverFifo) $serverFifo= '/var/lib/WikiProxy.fifo';
   
    $server= new FifoProxy( $serverFifo );
    $server->runServer();
}

if (defined('PROXY_TCP_MODE')) {
    require_once("WikiAccess.php");
    require_once("TcpServer.php");

    if (isset($options['ll'])) $wsgLogLevel= (int)$options['ll'];
    else if (isset($options['vv'])) $wsgLogLevel= LL_DEBUG;
    else if (isset($options['v'])) $wsgLogLevel= LL_VERBOSE;
   
    class TcpProxy extends TcpServer {   
        function TcpProxy( $port, $bind = '127.0.0.1' ) {
            TcpServer::TcpServer( $port, $bind );
        }
       
        function handleRequest( $req, &$response ) {
            $wiki = @$req['wiki'];
            $title = @$req['title'];
            $ns = @$req['ns'];
            $rev = @$req['rev'];
           
            $meta = @$req['meta'];
            $force = @$req['force'];

            if ($title===NULL && isset($req['']) && strlen($req[''])>1) {
                $title = substr($req[''], 1);
            }
           
            serve($wiki, $title, $ns, $rev, $meta, $force, $response);
        }
    }

    $port= (int)@$args[0];
    if (!$port) $port= '4223';
   
    $bind= '127.0.0.1';
    if (isset($options['bind'])) $bind= $options['bind'];
   
    $server= new TcpProxy( $port, $bind );
    $server->runServer();
}

if (defined('PROXY_CONSOLE_MODE')) {
    $wsgLogLevel= -100;
   
    if (sizeof($args)<2) $go= false;
    else {
        $wiki = $args[0];
        $title = $args[1];
        $ns = @$options['namespace'];
        $rev = @$options['rev'];
       
        $meta = isset($options['meta']);
        $force = isset($options['force']);
       
        if (is_null($wiki) || is_null($title)) $go= false;
        else $go= true;
    }

    if ($go) {
        require_once("WikiAccess.php");
       
        class CliResponse {
            function CliResponse() {
                $this->is_http= false;
            }
       
            function header($h, $override=true, $code=NULL) {
                print "\t**** $h\n";
            }
           
            function write($data) {
                if ($data==='' || $data===NULL || $data===false) return;
                print $data;
            }
           
            function flush() {
                flush();
            }
        }
       
        $response= new CliResponse();
 
        $requestHeaders= NULL;
        if (function_exists('apache_request_headers')) {
            $requestHeaders = apache_request_headers();
        }
       
        serve($wiki, $title, $ns, $rev, $meta, $force, $response);       
    }
    else {
        print "USAGE: WikiProxy [options] <wiki> <title>\n";
        exit(1);
    }
}
?>