<?php
if (@$argv[1]==='--test=WikiSense' && !@$_SERVER['REQUEST_URI'] && !defined('WS_WEB')) {
define('WS_CONSOLE',1);
define('WS_TEST_WIKISENSE',1);
require_once('WSInit.php');
}
if (!defined('WS_WEB')) die('bad entry point!');
require_once("$wsgDatabaseIncludePath/LBFactory.php");
require_once("$wsgDatabaseIncludePath/LoadBalancer.php");
define('SPACE_CHARS','( | | |\pZ)');
function wsfLoadClass( $class ) {
if ( class_exists( $class ) ) return $class;
@include_once( "$class.php" );
if ( class_exists( $class ) ) return $class;
return NULL;
}
function wsfGetExpertClass( $base, $dbname, $domain, $family, $lang, $is_multilang ) {
$class= NULL;
if (!$class) $class = wsfLoadClass( "{$base}_".str_replace('.','_',$domain) );
if (!$class) $class = wsfLoadClass( "{$base}_{$dbname}" );
if (!$class && !$is_multilang) $class = wsfLoadClass( "{$base}_{$lang}_{$family}" );
if (!$class && !$is_multilang) $class = wsfLoadClass( "{$base}_{$lang}" );
if (!$class) $class = wsfLoadClass( "{$base}_{$family}" );
if (!$class && $is_multilang) $class = wsfLoadClass( "{$base}_{$lang}" );
if (!$class) $class= $base;
return $class;
}
function wsfLoadExpertConfig( $base, $var, $dbname, $domain, $family, $lang, $is_multilang ) {
$$var= array();
#TODO: cache values, use include_once!
wsfLog("loading expert config for {$base} - {$lang} - {$family} - {$dbname} - {$domain}",LL_DEBUG);
@include( $base.'.php' );
if ($is_multilang) @include( "{$base}_{$lang}.php" );
@include( "{$base}_{$family}.php" );
if (!$is_multilang) @include( "{$base}_{$lang}.php" );
if (!$is_multilang) @include( "{$base}_{$lang}_{$family}.php" );
@include( "{$base}_{$dbname}.php" );
@include( "{$base}_".str_replace('.','_',$domain).'.php' );
return $$var;
}
function wsfConfigureObject( &$obj, $conf, $all=false ) {
if (!$conf) return;
$vars= NULL;
if (!$all) $vars= array_keys(get_object_vars($obj));
wsfLog("configuring ".get_class($obj)." object with ".sizeof($conf)." settings",LL_DEBUG);
foreach ($conf as $k => $v) {
if ($all || in_array($k,$vars)) {
$obj->$k= $v;
#print "\n<br/>CONFIGURING: ".get_class($obj)."::$k => $v <br/>\n";
}
#else print "\n<br/>SKIPPING: ".get_class($obj)."::$k <br/>\n";
}
}
function dbFailFunction( &$db, $error ) {
print "<p class='error'><b>Database Error: ".escapeHtml($error)." on ".escapeHtml($db->getProperty('mServer'))."/".escapeHtml($db->getProperty('mDBname'))."</b></p>";
}
function & openConnection( $uri, $transactions = NULL, $usecache = true ) {
global $wsgDatabaseIncludePath;
static $concache = array();
global $wsgTransactionMode;
if (is_null($transactions)) $transactions= @$wsgTransactionMode;
if ( is_string($uri) && preg_match( '!^%(.*)$!', $uri, $matches ) ) {
$u= $GLOBALS['wsgDatabases'][$matches[1]];
if (!$u) {
trigger_error('unknown database ID: '.$matches[1], E_USER_WARNING);
print_r(array_keys($GLOBALS['wsgDatabases']));
return false;
}
$logu = preg_replace('!//(.*?:)?.*?@!','//\1************@', $u);
wsfLog("resolved DB ID $uri to $logu", LL_TRACE);
$uri= $u;
}
$cachekey = is_array($uri) ? serialize($uri) : $uri;
if ($transactions) $cachekey .= '|' . $transactions;
if ( is_array($uri) ) {
$a = $uri;
unset($a['password']);
$loguri = serialize($a);
extract($uri);
}
else {
$loguri = preg_replace('!//(.*?:)?.*?@!','//\1************@', $uri);
//pseudo-url, jdbc-style: driver://[user[:password]@]host/database
if ( !preg_match( '!^([\w\d]+):(//(([^/@:]+)(:([^/@:]+))?@)?([\w\d-.:]+)/)?([^;&\?]+)$!', $uri, $matches ) ) {
$dummy=false;
return $dummy;
}
$type= $matches[1];
$user= $matches[4];
$password= $matches[6];
$host= $matches[7];
$dbname= $matches[8];
}
if ($usecache && isset($concache[$cachekey])) {
$db = $concache[$cachekey];
$db->ping();
if ($db->isOpen()) {
wsfLog("reusing connection to DB $loguri", LL_DEBUG);
return $concache[$cachekey];
}
else {
unset($concache[$cachekey]);
unset($db);
}
}
# Get class for this database type
$type = ucfirst( $type );
if ($type == "Mysql") $type = ""; #HACK: DatabaseMysql.php seems to be gone...
$class = 'Database' . $type;
if ( !class_exists( $class ) ) {
require_once( "$wsgDatabaseIncludePath/$class.php" );
}
#print "==> connecting to $dbname on $host using $class<br/>\n";
wsfLog("connecting to DB $loguri", LL_DEBUG);
# Create object
$db= new $class( $host, $user, $password, $dbname, 'dbFailFunction', 0 );
if ( !$db->isOpen() ) {
$dummy= false;
return $dummy;
}
if ($usecache) $concache[$cachekey] = $db;
$db->setOutputPage( $dummy = NULL );
if ($transactions !== NULL) {
if ($transactions===true) $transactions= 'REPEATABLE READ';
else if ($transactions===false) $transactions= 'READ UNCOMMITTED';
$db->query("SET SESSION TRANSACTION ISOLATION LEVEL $transactions");
}
$db->ping();
return $db;
}
function & getWikiListDB() {
global $wsgWikiListDB, $wsgWikiListTable;
global $wsgWikiDB;
global $wsgWikiListDBConnection;
if (!$wsgWikiListDB && !$wsgWikiListDBConnection) {
wsfLog('no WikiList database defined!',LL_ERROR);
wfDebugDieBacktrace('no WikiList database defined!');
}
if ( !$wsgWikiListDBConnection ) {
$u= $wsgWikiListDB;
if (strpos($u,':')===false && strpos($u, '%')!==0) $u= "$wsgWikiDB/$wsgWikiListDB";
$wsgWikiListDBConnection=& openConnection($u);
if (!$wsgWikiListDBConnection) {
wsfLog('failed to connect to WikiList database ',LL_ERROR);
wfDebugDieBacktrace('failed to connect to WikiList database ');
}
}
return $wsgWikiListDBConnection;
}
function getWikiInfo( $where, $limit= NULL, $usable = true ) {
global $wsgWikiListTable, $wsgBrokenWikis;
$db=& getWikiListDB();
$w= '';
$w.= "WHERE ";
if ($where) {
$i= 0;
foreach ($where as $c => $v) {
$w.= " $c = ".$db->addQuotes($v)." AND ";
$i+= 1;
}
}
if ($usable) $w.= " is_closed = 0 AND \"domain\" is not NULL "; //NOTE: beware mysql's fuckup wrt quoting and federated tables
$sql= 'SELECT * FROM '.$wsgWikiListTable.'
'.$w;
if ($limit) $w.= " LIMIT $limit";
$res= $db->query($sql, 'getWikiInfo');
$wikis= array();
while ($w= $db->fetchObject($res)) {
@$w->baseURL= "http://{$w->domain}{$w->scipt_path}index.php";
@$w->dbURL= getWikiDB($w);
if (isset($w->is_sensitive)) $w->ucFirst= !$w->is_sensitive;
if (!isset($w->ucFirst)) {
if ($w->family === 'wiktionary') $w->ucFirst= false; #FIXME: ugly hack!
else $w->ucFirst= true;
}
if (!isset($w->root_category)) $w->root_category= NULL;
if (in_array($w->domain, $wsgBrokenWikis)) $w->is_broken= true;
else if (!isset($w->is_broken)) $w->is_broken= false;
$wikis[]= $w;
}
$db->freeResult($res);
return $wikis;
}
function getWikiDB( $info ) {
global $wsgWikiDB, $wsgWikiClusterDBs;
if (isset($info->server) && isset($wsgWikiClusterDBs[$info->server])) {
$u = $wsgWikiClusterDBs[$info->server]."/".$info->dbname;
}
else {
$u = $wsgWikiDB ? "$wsgWikiDB/{$info->dbname}" : NULL;
}
#print "getWikiDB({$info->server}|{$info->dbname}): $u\n";
return $u;
}
function compareWikiInfoByDomain( $v, $w ) {
if ($v->domain == $w->domain) return 0;
else if ($v->domain < $w->domain) return -1;
else return 1;
}
function getWikiInfoFromLang( $lang, $family = NULL ) {
global $wsgWikiListDB, $wsgBrokenWikis;
$lang= preg_replace('/wiki$/','', $lang);
if ($lang=='simple') $lang= 'en-simple';
if ($lang=='commons' && (!$family || $family=='wikimedia')) {
$lang= 'en';
$family= 'commons';
}
if (!$family) $family= 'wikipedia';
if (!$wsgWikiListDB) {
$w= new stdClass();
@$w->lang= $lang;
@$w->family= $family;
#print "FAMILY: $family; LANG: $lang\n";
if ( $family=='commons' ) @$w->domain= "commons.wikimedia.org";
else @$w->domain= "$lang.$family.org";
if ( $family=='commons' ) @$w->is_multilang= true;
else @$w->is_multilang= false;
if ( $family=='wikipedia' ) @$w->dbname= "{$lang}wiki";
else if ( $family=='commons' ) @$w->dbname= "{$family}wiki";
else @$w->dbname= "$lang$family";
@$w->script_path= "/w/";
@$w->baseURL= "http://{$w->domain}{$w->scipt_path}index.php";
@$w->dbURL= getWikiDB($w);
if ($w->family === 'wiktionary') $w->ucFirst= false; #FIXME: ugly hack!
else $w->ucFirst= true;
$w->root_category= NULL;
$w->is_sensitive= !$w->ucFirst;
if (in_array($w->domain, $wsgBrokenWikis)) $w->is_broken= true;
else $w->is_broken= false;
$w->server= 1;
return $w;
}
else {
$info= getWikiInfo( array( 'lang' => $lang, 'family' => $family ), 1 );
if (!$info) return false;
else return $info[0];
}
}
function getWikiInfoFromDomain( $domain ) {
global $wsgWikiListDB;
#compatibility hack
if (strpos($domain,'.')===false) {
return getWikiInfoFromLang($domain);
}
if (!$wsgWikiListDB) {
$match= array();
if (!preg_match('/^(\w+)\.(\w+)(\.\w+)?$/',$domain,$match)) {
return getWikiInfoFromLang($match);
}
$w= getWikiInfoFromLang($match[1], $match[2]);
@$w->domain= $domain;
return $w;
}
else {
if (!preg_match('/.*\.org$/',$domain)) $domain.= '.org';
$info= getWikiInfo( array( 'domain' => $domain ), 1 );
if (!$info) return false;
else return $info[0];
}
}
function getLargestWikis($n, $family = NULL) {
global $wsgWikiListDB, $wsgWikiDB, $wsgWikiBlacklist;
if (!$wsgWikiListDB) {
global $wsgLanguages;
if (!$n) $l= $wsgLanguages;
else $l= array_slice($wsgLanguages,0,$n);
$wikis= array();
foreach ($l as $lang) {
$info= getWikiInfoFromLang($l);
$wikis[$info['domain']]= $info;
}
return $wikis;
}
else {
global $wsgWikiListTable, $wsgBrokenWikis;
$db=& getWikiListDB();
$sql= "select * from $wsgWikiListTable";
//NOTE: mysql's federated tables require domain to be quoted using '"'
// backticks (`) do *not* work. this is completely fucked up!
$sql.= " where \"domain\" is not null";
$sql.= " and is_closed = 0";
if ($family) $sql.= " and family = ".$db->addQuotes($family);
$sql.= " order by size desc limit " . (int)$n .";";
$wikis= array();
$res= $db->query($sql,'getLargestWikis');
while ( $w= $db->fetchObject($res) ) {
if (!$w->domain) continue;
if ($wsgWikiBlacklist) {
if (in_array($w->domain,$wsgWikiBlacklist)) continue;
if (in_array($w->dbname,$wsgWikiBlacklist)) continue;
}
@$w->baseURL= "http://{$w->domain}{$w->script_path}index.php";
@$w->dbURL= getWikiDB($w);
if (isset($w->is_sensitive)) $w->ucFirst= !$w->is_sensitive;
if (!isset($w->ucFirst)) {
if ($w->family === 'wiktionary') $w->ucFirst= false; #FIXME: ugly hack!
else $w->ucFirst= true;
}
if (in_array($w->domain, $wsgBrokenWikis)) $w->is_broken= true;
else if (!isset($w->is_broken)) $w->is_broken= false;
$wikis[$w->domain]= $w;
}
$db->freeResult($res);
return $wikis;
}
}
$wsgNamespaceCache= NULL;
$wsgNamespaceCacheReverse= NULL;
$wsgNamespaceCacheComplete= false;
function getCustomNsIndex( &$wiki, $ns, $slurp = false ) {
global $wsgNamespaceCache, $wsgNamespaceCacheReverse;
if ($wiki && is_object($wiki)) {
$domain = $wiki->domain;
$ns= str_replace(' ','_',$wiki->lc(trim($ns)));
}
else {
$domain = $wiki;
$ns= str_replace(' ','_',WikiAccess::lc(trim($ns)));
}
if ($ns===false || !$domain) $k= NULL; //just load
else $k= "$domain#$ns";
#print "KEY $k;\n";
#print_r($wsgNamespaceCacheReverse);
if ($k && isset($wsgNamespaceCacheReverse[$k]) && (!$slurp || $wsgNamespaceCacheComplete)) return $wsgNamespaceCacheReverse[$k];
getCustomNsText($wiki,false,$slurp); //load
if (!$k) return NULL; //slurp only
if (!isset($wsgNamespaceCacheReverse[$k])) $wsgNamespaceCacheReverse[$k]= NULL;
return $wsgNamespaceCacheReverse[$k];
}
function getCustomNsText( &$wiki, $ns, $slurp = false ) {
global $wsgWikiListDB;
global $wsgNamespaceCache, $wsgNamespaceCacheReverse;
global $wsgNamespaceCacheComplete, $wsgCustomNamespaceTable;
if ($wiki && is_object($wiki)) $domain = $wiki->domain;
else $domain = $wiki;
if ($ns===false || !$domain) $k= NULL; //just load
else $k= "$domain#$ns";
if ($wsgNamespaceCacheReverse==NULL) $wsgNamespaceCacheReverse= array();
if ($wsgNamespaceCache==NULL) $wsgNamespaceCache= array();
if (($k && isset($wsgNamespaceCache[$k])) && (!$slurp || $wsgNamespaceCacheComplete)) return @$wsgNamespaceCache[$k];
if ($wsgWikiListDB && !$wsgNamespaceCacheComplete && $wsgCustomNamespaceTable) {
$db=& getWikiListDB();
$sql= "SELECT * from $wsgCustomNamespaceTable";
if (!$slurp) $sql.= " WHERE domain = ".$db->addQuotes($domain);
#print "LOADING NS FOR $domain: $sql<br>";
$res= $db->query($sql,'getCustomNamespaceName');
while ( $w= $db->fetchObject($res) ) {
if (!$w->domain) continue;
$nn = $w->ns_name;
if ($wiki && is_object($wiki)) {
$nn= str_replace(' ','_',$wiki->lc(trim($nn)));
}
else {
$nn= str_replace(' ','_',WikiAccess::lc(trim($nn)));
}
$wsgNamespaceCache[$w->domain.'#'.$w->ns_id]= $w->ns_name;
$wsgNamespaceCacheReverse[$w->domain.'#'.$nn]= $w->ns_id;
}
#print_r($wsgNamespaceCache);
#print_r($wsgNamespaceCacheReverse);
if ($slurp) $wsgNamespaceCacheComplete= true;
}
if (!$k) return NULL; //load only
if (!isset($wsgNamespaceCache[$k])) $wsgNamespaceCache[$k]= $ns;
return $wsgNamespaceCache[$k];
}
define('LL_MUTE', -100);
define('LL_SILENT', -4);
define('LL_QUIET', -2);
define('LL_NORMAL', 0);
define('LL_VERBOSE', 10);
define('LL_NOISY', 100);
define('LL_TRACE', LL_NOISY);
define('LL_DEBUG', LL_VERBOSE);
define('LL_INFO', LL_NORMAL);
define('LL_WARN', LL_QUIET);
define('LL_ERROR', LL_SILENT);
function wsfToString($data, $depth=-1, $exclude = NULL) {
if ($data === NULL) $data= "<null>";
else if ($data===false) $data= "<false>";
else if ($data===true) $data= "<true>";
else if (is_object($data)) $data= get_object_vars($data);
if (is_array($data)) {
if ($depth!=0) {
$s= "{";
foreach ( $data as $k => $v ) {
if ($exclude!==NULL && $exclude!==false) {
if (preg_match($exclude, $k)) continue;
}
$s.= "$k => ".wsfToString($v, $depth > 0 ? $depth-1 : $depth, $exclude).", ";
}
$s.= "}";
$data= $s;
}
else {
$data= "array(".sizeof($data).")";
}
}
return $data;
}
$wsgLogLastSupressed= NULL;
$wsgLogRepostTimestamp= NULL;
$wsgLogRepostThreashold= NULL;
$wsgLogLastTimestamp= NULL;
$wsgLogTimestampThreashold= NULL;
function wsfLog( $msg, $level = LL_NORMAL, $data='@dummy@' ) {
global $wsgLogLevel, $wsgLogHashCounter, $wsgLogSuffix, $wsgLogTag;
global $wsgLogLastSupressed, $wsgLogRepostThreashold, $wsgLogRepostTimestamp,
$wsgLogLastTimestamp, $wsgLogTimestampThreashold;
if ($wsgLogRepostThreashold) {
$now= time();
$t= $now - $wsgLogRepostTimestamp;
if ($wsgLogRepostTimestamp && $t > $wsgLogRepostThreashold && $wsgLogLastSupressed) {
if ( $wsgLogHashCounter > 0 ) {
print $wsgLogSuffix;
$wsgLogHashCounter = 0;
}
if ($wsgLogTag) print "<$wsgLogTag>";
print " - LAST MESSAGE SUPRESSED $t seconds ago: $wsgLogLastSupressed";
if ($wsgLogTag) print "</$wsgLogTag>";
print "\n";
if ($level>$wsgLogLevel) { #make sure the current message gets printed, too.
$msg= "NEXT MESSAGE FORCED: $msg";
$level= $wsgLogLevel;
}
$wsgLogLastSupressed= false;
}
$wsgLogRepostTimestamp= $now;
}
if ($level>$wsgLogLevel) {
if ($wsgLogRepostThreashold) {
if ($data!=='@dummy@') $msg.= " (".wsfToString($data).")";
$wsgLogLastSupressed= $msg;
}
if ($level>$wsgLogLevel+2) {
#print "(($level>$wsgLogLevel+2))";
return;
}
else {
if ( $wsgLogHashCounter == 0 ) {
print " ";
}
if ($level<LL_NORMAL) print "!";
else print ".";
$wsgLogHashCounter+= 1;
if ( $wsgLogHashCounter > 50 ) {
print $wsgLogSuffix;
$wsgLogHashCounter = 0;
}
}
}
else {
if ( $wsgLogHashCounter > 0 ) {
print $wsgLogSuffix;
$wsgLogHashCounter = 0;
}
if ($data!=='@dummy@') $msg.= " (".wsfToString($data).")";
if ($wsgLogTag) print "<$wsgLogTag>";
if ( $wsgLogTimestampThreashold ) {
if (!isset($now)) $now= time();
$t= $now - $wsgLogLastTimestamp;
if ($t > $wsgLogTimestampThreashold) {
if ($wsgLogTag) print "<$wsgLogTag>";
if ($wsgLogLastTimestamp) $t= "($t sec)";
else $t= '';
print " - TIME$t: ".wfTimestamp(TS_DB, $now);
print $wsgLogSuffix;
$wsgLogLastTimestamp= $now;
}
}
print " - $msg";
if ($wsgLogTag) print "</$wsgLogTag>";
print "\n";
$wsgLogLastSupressed= false;
}
flush();
}
function wsfDBTitle( $title ) {
$title= trim( $title );
$title= urldecode( $title ); #HACKish
$title= Sanitizer::decodeCharReferences( $title );
$title= preg_replace('/\s+/','_',$title);
$title= ucfirst($title); //FIXME: unicode! //FIXME: optional!
return $title;
}
function & wsfStripIntKeys( &$array ) {
if ( $array === NULL || $array===false ) return $array;
if (!is_array($array)) trigger_error("not an array: $array", E_USER_WARNING);
foreach ( $array as $k => $v ) {
if (is_int($k)) unset($array[$k]);
}
return $array;
}
function stripMarkup( $text ) {
#print "\n---> $text\n";
$text= preg_replace("!\"|'''?|<[\\w\\d]+.*?/?>|</[\\w\\d]+>!",'',$text);
$text= preg_replace('!^[\s]+|[\s]+$!','',$text); #FIXME: unicode whitespace
if (strlen($text>2)) $text= preg_replace('!^[\s"\'\]\[<>,;.:?\{\}]+|[\s"\'\]\[<>,,;.:?\{\}]+$!','',$text); #FIXME: unicode punctuation
$text= Sanitizer::decodeCharReferences( $text );
#print "===> $text\n";
#FIXME: strip punctuation
return $text;
}
function stripHTML( $text ) {
$text= preg_replace("!<[\\w\\d]+.*?/?>|</[\\w\\d]+>!",'',$text);
$text= preg_replace("/<!--.*?-->/",'',$text);
return $text;
}
function endsWith( $haystack, $needle ) {
if (strlen($haystack)<strlen($needle)) return false;
else {
$x= substr($haystack, strlen($haystack) - strlen($needle));
if ($x === $needle) return true;
else return false;
}
}
function escapeChunkCallback( $value, $prefix, &$store ) {
static $i;
if (!isset($i)) $i= 0;
$i+= 1;
$k= "@@$prefix:$i:".rand(1,1000)."@@";
$store[$k]= $value;
return $k;
}
function escapeChunks( $prefix, $preg, &$text, &$store ) {
$code= 'escapeChunkCallback(\'\0\',$prefix,$store)';
$text= preg_replace($preg.'e',$code,$text);
return $text;
}
function unescapeChunks( &$text, &$store ) {
$text= str_replace(array_keys($store),array_values($store),$text);
return $text;
}
$wscHtmlSpecial = array( '<', '>', '\'', '"', '&' );
$wscHtmlEscaped = array( '<', '>', ''', '$quot;', '&');
function escapeHtml( $text, $mode = ENT_QUOTES ) {
return htmlspecialchars($text, $mode);
}
class PseudoLoadBalancer {
var $db;
function PseudoLoadBalancer( &$db ) {
$this->db=& $db;
}
function & getConnection( $dummy1, $dummy2, $dummy3 ) {
return $this->db;
}
}
class PseudoOut {
function disable() {}
function sendCacheControl() {}
function debug() {}
}
#global $wgOut;
if (!isset($wgOut) || !$wgOut) {
$wgOut= new PseudoOut();
}
function printRadioButton($name, $value, $current= NULL, $a= '') {
$s= $value!=$current ? '' : " checked='checked' ";
print "<input type='radio' name='$name' value='$value'$s$a/>";
}
function printCheckbox($name, $value, $a= '') {
$s= $value ? " checked='checked' " : '';
print "<input type='checkbox' name='$name' $s$a/>";
}
function printOption($label, $value, $current= NULL, $a= '') {
#print "<!-- value: $value; current: $current; -->";
$s= $value!=$current ? '' : " selected='selected' ";
print "<option value='$value'$s$a>$label</option>";
}
function printSelector($name, $options, $current= NULL) {
print "\n<select name='$name'>";
foreach ($options as $v => $label) {
printOption($label, $v, $current);
}
print "\n</select>\n";
}
function addURLParam(&$url, $key, $value, $html=true) {
if (isset($value) && $value !== NULL && $value!==false && $value!=='') {
$value= urlencode($value);
if ($html) $url.= '&';
else $url.= '&';
$url.= $key;
$url.= '=';
$url.= $value;
}
return $url;
}
function joinURLParams($fields, $html=true) {
$f= '';
foreach ($fields as $k => $v) {
if ($f!=='') {
if ($html) $f.= '&';
else $f.= '&';
}
$f.= urlencode($k);
$f.= '=';
$f.= urlencode($v);
}
return $f;
}
function wsfHackingInProgress() {
?>
<p style="border:1px solid black; background-color:yellow; margin:1ex; padding: 1ex;">
<b>WARNING: <i>Hacking in Progress!</i></b><br/>
This tool is currently being modified and debugged. You can try to use it, but you may
get unexpected or wrong results. Or it may simply be broken for a while. Please try again
later if you need to use it for anything serious.
</p>
<?
}
function wsfSubtitle( $name ) {
global $wsgBugTrackerURL, $wsgToolHelpBase, $wsgToolTalkBase;
$help= $wsgToolHelpBase.urlencode($name);
$talk= $wsgToolTalkBase.urlencode($name);
$bugs= $wsgBugTrackerURL;
?>
<p style='font-size:70%;'>
<a href='<?=$help?>'><?= wsfWikiSenseMessage('help_page_label') ?></a>
<!--|
<a href='<?=$talk?>'><?= wsfWikiSenseMessage('talk_page_label') ?></a>-->
|
<a href='<?=$bugs?>'><?= wsfWikiSenseMessage('bug_page_label') ?></a>
</p>
<?
}
function wsfHeader( ) {
global $wsgHeader;
if ($wsgHeader) {
print "<div id='headerbox'>";
include($wsgHeader);
print "</div>";
}
}
function wsfFooter( ) {
global $wsgFooter;
if ($wsgFooter) {
print "<div id='footerbox'>";
include($wsgFooter);
print "</div>";
}
}
function wsfCachePut($uri, $data) {
global $wsgCacheDir;
if (!$wsgCacheDir) return false;
if (!file_exists($wsgCacheDir)) return false;
if (!is_dir($wsgCacheDir)) return false;
if (!is_writable($wsgCacheDir) || !is_readable($wsgCacheDir)) return false;
$f= $wsgCacheDir.'/'.str_replace(array('/','&','+','*','?',';',':',' '),'_',$uri).'.cache';
$ok= file_put_contents($f,$data);
return $ok;
}
function wsfCacheGet($uri, $duration, $sendLastModified=false) {
global $wsgCacheDir;
if (!$wsgCacheDir) return false;
if (!file_exists($wsgCacheDir)) return false;
if (!is_dir($wsgCacheDir)) return false;
if (!is_writable($wsgCacheDir) || !is_readable($wsgCacheDir)) return false;
$f= $wsgCacheDir.'/'.str_replace(array('/','&','+','*','?',';',':',' '),'_',$uri).'.cache';
if (!file_exists($f)) return NULL;
if (!is_file($f)) return NULL;
if (!is_readable($f)) return NULL;
$time= filemtime($f);
if (!$duration || ((time() - $time) > $duration) ) { //cache is stale
unlink($f);
return NULL;
}
$data= file_get_contents($f);
if ($data !== NULL && $data!==false && $sendLastModified && !headers_sent()) {
header('Last-Modified: '.wfTimestamp(TS_RFC2822,$time));
}
return $data;
}
function wsfCacheStart($uri, $duration) {
if ($duration===false) return false;
$data= wsfCacheGet($uri, $duration, true);
if ($data===false) return false;
if ($data !== NULL) {
if (!headers_sent()) header('X-WS-Cached: yes');
print $data;
return true;
}
ob_start();
return NULL;
}
function wsfCacheEnd($uri) {
if (!ob_get_level()) return false;
$data= ob_get_contents();
ob_end_flush();
wsfCachePut($uri, $data);
}
if (!function_exists('array_combine')) {
function array_combine( $keys, $values ) {
$keysValues = array();
foreach($keys as $indexnum => $key) {
$keyValues[$key] = $values[$indexnum];
}
return $keysValues;
}
}
if (!defined('FILE_USE_INCLUDE_PATH')) define('FILE_USE_INCLUDE_PATH', 1);
if (!defined('FILE_APPEND')) define('FILE_APPEND', 8);
if (!defined('LOCK_EX')) define('LOCK_EX', 2);
if (!function_exists('file_put_contents')) {
function file_put_contents($f, $data, $flags = 0) {
if (is_bool($flags)) $append = $flags;
else $append= ( ($flags & FILE_APPEND) == FILE_APPEND );
$fh= fopen($f,$append?'a':'w');
if (!$fh) return false;
$ok= fwrite($fh,$data);
fclose($fh);
return $ok;
}
}
global $wsgWikiSenseMessages;
$wsgWikiSenseMessages= NULL;
function wsfWikiSenseMessage($key) {
global $wsgWikiSenseMessages, $wsgUserLang;
if ($wsgUserLang && $wsgWikiSenseMessages && $wsgWikiSenseMessages->language != $wsgUserLang) {
$wsgWikiSenseMessages= NULL;
}
if (!$wsgWikiSenseMessages) {
if (!class_exists('WikiSenseLocalizer')) {
require_once('WikiSenseLocalizer.php');
}
$wsgWikiSenseMessages= WikiSenseLocalizer::load( 'WikiSense', $wsgUserLang ? $wsgUserLang : 'en' );
}
$args= func_get_args();
return call_user_func_array ( array(&$wsgWikiSenseMessages, 'msg'), $args );
}
function wsfGetDBId( $db ) {
if (is_object($db)) {
$name = $db->getProperty('mServer') . '+' . $db->getProperty('mDBname');
}
else {
$name = preg_replace('!^.*://(.*?@)?(.*?)/(.*)$!', '\2+\3', $db);
}
return $name;
}
function wsfReadStatusInfo($file) {
if (!$file) return false;
if (!file_exists($file)) return false;
#print "CHECK STATUS: $file; ";
$fh = fopen($file, 'r');
if (!$fh) return false;
$st = array();
while (true) {
$s = fgets($fh);
if ($s==='' || $s===NULL || $s===false) break;
$s = trim($s);
if ($s==='') continue;
if ($s[0] === '#') continue;
$ss = explode(';', $s, 2);
$st['status'] = strtoupper(trim($ss[0]));
$st['message'] = isset($ss[1]) ? trim($ss[1]) : '';
break;
}
fclose($fh);
if (!$st) return false;
return $st;
}
function wsfGetReplag( $db = NULL, $statusfile = NULL ) {
global $wsgReplagDB, $wsgReplagFile, $wsgReplagPattern;
if (is_string($db) && (int)$db!=0) $db = (int)$db;
if (is_int($db) && $wsgReplagDB) {
if (is_array($wsgReplagDB)) {
$db = $wsgReplagDB[$db];
if (is_array($db)) {
$db = $db['db'];
if (!$statusfile) $statusfile = $db['status-file'];
#TODO: abort, etc
}
}
else $db = $wsgReplagDB;
}
if (!$db) $db = $wsgReplagDB;
if ($db) {
if (is_array( $db )) {
$lag = array();
foreach ($db as $n => $a) {
if (is_array($a)) {
$url = $a['db'];
$abort = @$a['abort'];
if (!$statusfile) $statusfile = $a['status-file'];
} else {
$url = $a;
$abort = false;
if (!$statusfile) $statusfile = false;
}
if ($abort) { //explicitely broken
$lag[$n] = array('status' => 'ABORT', 'message' => $abort, 'lag' => false);
}
else {
$lag[$n] = wsfGetReplag($url, $statusfile);
}
}
return $lag;
}
$cachekey = 'replag-' . wsfGetDBId($db);
$s = read_from_disk_cache($cachekey, 1);
if ($s) {
#print "[$cachekey] = $s; ";
$lag = unserialize($s);
if ($lag) {
$lag['cached'] = $cachekey;
return $lag;
}
else {
trigger_error("bad serialized data: '$s'", E_USER_WARNING);
}
}
$lag = array(
'status' => 'OK',
'message' => '',
'lag' => false,
);
if ($statusfile) {
$st = wsfReadStatusInfo($statusfile);
if ($st) {
$lag['statusfile'] = $statusfile;
$lag['status'] = $st['status'];
$lag['message'] = $st['message'];
}
}
if ($lag['status']=='ERROR' || $lag['status']=='DOWN') {
write_to_disk_cache($cachekey, serialize($lag));
return $lag;
}
$t = NULL;
if (is_object($db)) $dbo = $db;
else $dbo = openConnection($db);
if ($dbo) {
$sql= 'SELECT time_to_sec(timediff(now(),rc_timestamp)) FROM recentchanges ORDER BY rc_timestamp DESC LIMIT 1;';
$retry = 5;
while (true) { //retry loop (ugly hack)
$res= $dbo->query($sql, 'wsfGetReplag');
$row = $dbo->fetchRow($res);
#if (!is_object($db)) $dbo->close();
if ($row) {
$t= (int)$row[0];
if ($t === -3020399) { //XXX: mysql date/time overflow
$retry -= 1;
if ($retry == 0) break; //give up
sleep(1);
continue; //try again (ugly hack).
}
break;
}
else break;
}
}
}
if ($t === NULL && $wsgReplagFile) {
$t= file_get_contents($wsgReplagFile);
if ($t) {
$t= trim($t);
if ($wsgReplagPattern) $t= eval($wsgReplagPattern);
}
}
wsfSetReplagStatus($t, $lag);
write_to_disk_cache($cachekey, serialize($lag));
return $lag;
}
function wsfSetReplagStatus($t, &$lag) {
$lag['lag'] = $t;
if ($t === NULL || $t===false) { $lag['status'] = 'FAILED'; $lag['message'] = 'failed'; }
else if ($t===-3020399) { $lag['status'] = 'FAILED'; $lag['message'] = 'bad lag value: '.$t; }
else if ($t<-30) { $lag['status'] = 'FAILED'; $lag['message'] = 'bad lag value: '.$t; }
}
function wsfGetReplagHTML( $lagInfo = NULL, $label = NULL ) {
global $wsgWikiClusterNames;
if ($label === NULL) $label = wsfWikiSenseMessage('estimated_database_lag');
$html = escapeHtml($label) . ': ';
if ($lagInfo===NULL) $lagInfo= wsfGetReplag();
else {
if (is_string($lagInfo) && (int)$lagInfo!=0) $lagInfo = (int)$lagInfo;
if (is_int($lagInfo)) $lagInfo = wsfGetReplag($lagInfo);
}
if ($lagInfo===NULL || $lagInfo===false) return '';
if (is_array( $lagInfo ) && !isset( $lagInfo['lag'] )) {
$s= '';
$show= false;
foreach ($lagInfo as $n => $v) {
if (is_array($v) && !isset($v['lag'])) {
$db = $v['db'];
$label = $v['label'];
} else {
if (is_int($n)) {
if (isset($wsgWikiClusterNames[$n])) $label = $wsgWikiClusterNames[$n];
else $label = "s$n";
}
$db = $v;
}
$lag = wsfGetReplagHTML($db, $label);
if ($lag) {
if ($s!=='') $s.=' | ';
$s.= $lag;
}
}
if ($s) return $html . $s;
else return false;
}
else {
if (is_array($lagInfo)) {
//noop...
} else {
$t = $lagInfo;
$lagInfo = array( 'lag' => $t, 'status' => 'OK', 'message' => '' );
wsfSetReplagStatus($t, $lagInfo);
}
}
extract($lagInfo); //$status, $message, $lag
$time = '';
$style = '';
if ($status == 'OK' && $lag < 30) return false;
if ($status=='ERRO' || $status=='DOWN' || $status=='ABORT' || $status=='FAILED')
return '<span class="error">'.$html.' '.escapeHtml($message).'</span>';
if ($lag==='0' || $lag===0 || $lag < 30) {
$style= 'color:green;';
$time = 'up to date';
}
else if ($lag===3020399) {
$style= 'font-weight:bold; color:yellow; background-color:red;';
$time = 'more than a month';
}
else {
$s= $lag;
$has = 0;
$d= floor($s / (60*60*24));
if ($d && $has < 2) {
$s-= $d * 60*60*24;
if ($time) $time.= ', ';
$time.= "$d days";
$has+= 1;
}
$h= floor($s / (60*60));
if ($h && $has < 2) {
$s-= $h * 60*60;
if ($time) $time.= ', ';
$time.= "$h hours";
$has+= 1;
}
$m= floor($s / (60));
if ($m && $has < 2) {
$s-= $m * 60;
if ($time) $time.= ', ';
$time.= "$m minutes";
$has+= 1;
}
if ($s && $has < 2) {
if ($time) $time.= ', ';
$time.= "$s seconds";
$has+= 1;
}
if ($lag > 60 * 60 * 12) $style= 'font-weight:bold; color:yellow; background-color:red;';
else if ($lag > 60 * 60) $style= 'color:black; background-color:red;';
else if ($lag > 60 * 5) $style= 'color:black; background-color:orange;';
else if ($lag > 60 * 1) $style= 'color:black; background-color:yellow;';
else $style= 'color:green;';
}
$html = "<span style='$style'>$html $time</span>";
return $html;
}
/*
function preg_replace_recursive($begin, $end, $sep, $mod, $replace, $s) {
$s= preg_replace("$sep$begin((?>.*?)(?R))*.*?$end$sep$mod",'',$s);
return $s;
}
*/
function preg_strip($exp, $s) {
while (true) {
$l= strlen($s);
#print "--> $s \n";
$s= preg_replace($exp,'',$s);
if ($l==strlen($s)) break;
}
return $s;
}
function wsfMicroTime()
{
list($usec, $sec) = explode(" ", microtime());
return ((float)$usec + (float)$sec);
}
function wsfHash($i, $n, $c) {
global $wsgLogLevel;
if ($wsgLogLevel<LL_INFO) return;
if ( (($i+1) % 50) === 0 ) print " (".($c/1024)."K)\n";
print ".";
flush();
}
function wsfCopy($src, $tgt, $chunksize = 0, $callback = NULL) {
if (is_resource($src)) $sf= $src;
else {
$sf= fopen($src,'r'.($chunksize?'b':''));
if (!$sf) return false;
}
if (is_resource($tgt)) $tf= $tgt;
else {
$tf= fopen($tgt,'w'.($chunksize?'b':''));
if (!$tf) return false;
}
$c= 0;
$i= 0;
while (true) {
if (!$chunksize) $data= fgets($sf);
else {
$data= '';
$exp= $chunksize;
#print "|";
while ($exp>0) {
$d= fread($sf, $exp);
if ($d===false || $d===NULL || $d==='') break; #TODO: handle error ($data==false)
$exp-= strlen($d);
$data.= $d;
#print "($exp)";
}
}
if ($data===false || $data===NULL || $data==='') break; #TODO: handle error ($data==false)
if (!$n= fwrite($tf,$data)) break; #FIXME: abort?! delete partial?
fflush($tf);
$c+= $n;
$i+= 1;
if ($callback) {
if (is_string($callback)) $callback($i, $n, $c);
else $callback->progress($i, $n, $c);
}
}
if ($sf !== $src) fclose($sf);
if ($tf !== $tgt) fclose($tf);
return $c;
}
function wsfThrottle($name, $rate, $interval = 1) {
global $wsgThrottleDir;
$f= "$wsgThrottleDir/$name.throttle";
if (file_exists($f)) {
$fh= fopen($f, 'r+');
flock ( $fh, LOCK_EX );
$t= fgets($fh);
}
else {
$fh= fopen($f, 'w');
flock ( $fh, LOCK_EX );
$t= false;
}
if ($t && preg_match('/(\d+)\s+(\d+)/', $t, $m)) {
$t= (int)$m[1];
$n= (int)$m[2];
$d= time() - $t;
if ($d < $interval) {
if ($n>=$rate) {
#print "seeping for ".($interval - $d)." sec\n";
sleep($interval - $d);
$t= time();
$n= 1;
}
else {
$n+= 1;
}
}
else {
#print "resetting throttle\n";
$t= time();
$n= 1;
}
}
else {
$t= time();
$n= 1;
}
#print "setting counter to $n\n";
fseek($fh, 0);
ftruncate($fh, 0);
fseek($fh, 0);
fwrite($fh, "$t $n");
flock ( $fh, LOCK_UN );
fclose( $fh );
}
function levensteinDistance($a, $b, $normalize=false, $limit=0) {
$d= array();
$ca= is_array($a) ? sizeof($a) : mb_strlen($a);
$cb= is_array($b) ? sizeof($b) : mb_strlen($b);
if ($a === $b) return 0;
if ($a==='' || $a===NULL || (is_array($a) && sizeof($a)===0)) return $cb;
if ($b==='' || $b===NULL || (is_array($b) && sizeof($b)===0)) return $ca;
$v= abs($ca-$cb);
if ($normalize) $v= $v / (float)max($ca,$cb);
if ($limit && $v > $limit) return $v;
for ($i= 0; $i<=$ca; $i+= 1) $d[$i]= array( 0 => $i );
for ($j= 0; $j<=$cb; $j+= 1) $d[0][$j]= $j;
for ($i= 1; $i<=$ca; $i+= 1) {
for ($j= 1; $j<=$cb; $j+= 1) {
$ach= is_array($a) ? $a[$i-1] : mb_substr($a,$i-1,1);
$bch= is_array($a) ? $a[$i-1] : mb_substr($b,$j-1,1);
$cost= $ach == $bch ? 0 : 1;
$d[$i][$j]= min(
$d[$i-1][$j ] + 1, //deletion
$d[$i ][$j-1] + 1, //insertion
$d[$i-1][$j-1] + $cost //substitution
);
/*
$v= $d[$i][$cb];
if ($normalize) $v= $v / (float)max($ca,$cb);
if ($limit && $v > $limit) return $v;
*/
#FIXME: abort if hopeles... how?!
}
}
if ($normalize) {
$f= (float)$d[$ca][$cb] / (float)max($ca,$cb);
return $f;
}
else return $d[$ca][$cb];
}
function isProcessAlive($pid) {
unset($dummy);
#sucks: exec("ps p ".(int)$pid, $dummy, $code);
#if ($code) return false;
#else return true;
#maybe: posix_kill($pid, 0);
return file_exists('/proc/'.$pid); //NOTE: UNIX ONLY!
}
global $wsgLogDBConnection, $wsgScriptLogId, $wsgScriptLogStart, $wsgScriptLogComment, $wsgScriptEndLogged, $wsgScriptEndLogging;
$wsgLogDBConnection= NULL;
$wsgScriptLogId= NULL;
$wsgScriptLogStart= NULL;
$wsgScriptLogComment= NULL;
$wsgScriptEndLogged = false;
$wsgScriptEndLogging = false;
function & wsfGetLogDB() {
global $wsgLogDB, $wsgLogTable, $wsgLogDBConnection;
if ( is_null($wsgLogDBConnection) ) {
if (!$wsgLogDB) {
$wsgLogDBConnection= false;
}
else {
$wsgLogDBConnection=& openConnection($wsgLogDB);
if (!$wsgLogDBConnection) {
wsfLog('failed to connect to log database ',LL_ERROR);
$wsgLogDBConnection= false;
}
}
}
return $wsgLogDBConnection;
}
function wsfScriptLogInsert( $fields = NULL ) {
global $wsgLogTable;
$db=& wsfGetLogDB();
if (!$db) return false;
if (!$fields) $fields= array();
if (!isset($fields['timestamp'])) $fields['timestamp']= wfTimestamp(TS_MW);
if (!isset($fields['status'])) $fields['status']= 'run';
if (defined('WS_CONSOLE')) {
global $argv, $args;
$client= @$_SERVER['USER'];
if (!$client) $client= @$_ENV['USER'];
if (!$client) $client= @$_SERVER['LOGNAME'];
if (!$client && isset($_SERVER['HOME'])) $client= basename($_SERVER['HOME']);
if (!$client) $client= '-/-';
if (!isset($fields['script'])) $fields['script']= $_SERVER['SCRIPT_NAME'];
if (!isset($fields['params'])) $fields['params']= wsfToString(array_slice($_SERVER['argv'],1));
if (!isset($fields['client'])) $fields['client']= $client;
}
else {
if (!isset($fields['script'])) $fields['script']= $_SERVER['PHP_SELF'];
if (!isset($fields['params'])) $fields['params']= wsfToString($_GET);
if (!isset($fields['client'])) $fields['client']= $_SERVER['REMOTE_ADDR'];
}
$names= '';
$values= '';
foreach ($fields as $k => $v) {
if ($names!=='') $names.= ', ';
if ($values!=='') $values.= ', ';
$names.= "`$k`";
if (is_null($v)) $values.= 'NULL';
else if (is_int($v)) $values.= (int)$v;
else if (is_float($v)) $values.= (float)$v;
else if (is_bool($v)) $values.= $v ? '1' : '0';
else $values.= $db->addQuotes($v);
}
$sql= "INSERT INTO $wsgLogTable ( $names ) VALUES ( $values )";
$db->query($sql, 'wsfScriptLogInsert');
$id= $db->insertId();
if (!$id) {
wsfLog('failed to insert log row (' . $db->lastError() . ')', LL_WARN);
}
return $id;
}
function wsfScriptLogUpdate( $id, $fields = NULL ) {
global $wsgLogTable;
if (!$fields) return;
$db=& wsfGetLogDB();
if (!$db) return false;
$set= '';
foreach ($fields as $k => $v) {
if ($set!=='') $set.= ', ';
$set.= "`$k` = ";
if (is_null($v)) $set.= 'NULL';
else if (is_int($v)) $set.= (int)$v;
else if (is_float($v)) $set.= (float)$v;
else if (is_bool($v)) $set.= $v ? '1' : '0';
else $set.= $db->addQuotes($v);
}
$sql= "UPDATE $wsgLogTable SET $set WHERE id = ".(int)$id;
$db->query($sql, 'wsfScriptLogUpdate');
}
function wsfLogScriptStart() {
global $wsgLogDB, $wsgScriptLogId, $wsgScriptLogStart;
if (!$wsgLogDB) return;
if ($wsgScriptLogId) {
wsfLog('script start already logged - skipping ',LL_WARN);
return false;
}
$data= array(
'status' => 'started',
);
$wsgScriptLogStart= time();
$wsgScriptLogId= wsfScriptLogInsert($data);
if (!$wsgScriptLogId) {
wsfLog('failed to log script start!',LL_WARN);
return false;
}
return $wsgScriptLogId;
}
function wsfLogScriptComment( $comment ) {
global $wsgScriptLogComment;
if ($wsgScriptLogComment) $wsgScriptLogComment.= '; '.$comment;
else $wsgScriptLogComment= $comment;
}
function wsfLogScriptEnd( $status='done', $comment = NULL ) {
global $wsgLogDB, $wsgScriptLogId, $wsgScriptLogStart, $wsgScriptLogComment, $wsgScriptEndLogged, $wsgScriptEndLogging;
if ($wsgScriptEndLogged && $status=="done") return; //end already logged
if ($comment) wsfLogScriptComment( $comment );
if (function_exists("getmypid")) wsfLogScriptComment( "PID: " . getmypid() );
if (function_exists("memory_get_usage")) wsfLogScriptComment( "MEM USE: " . memory_get_usage(true) );
if (function_exists("memory_get_peak_usage")) wsfLogScriptComment( "MEM PEEK: " . memory_get_peak_usage(true) );
if (!$wsgLogDB) return;
if ($wsgScriptEndLogging) return; //avoid recursion. NOTE: we may lose info here!
$wsgScriptEndLogging = true;
try {
if (!$wsgScriptLogId) {
wsfLog('script start not logged! logging end anyway.',LL_WARN);
return false;
}
$data= array(
'status' => $status,
'time' => $wsgScriptLogStart ? (time() - $wsgScriptLogStart) : NULL,
'comment' => $wsgScriptLogComment,
);
if ($wsgScriptLogId) wsfScriptLogUpdate($wsgScriptLogId, $data);
else wsfScriptLogInsert($data);
global $wsgLogDBConnection;
if ($wsgLogDBConnection) $wsgLogDBConnection->close();
$wsgLogDBConnection= false;
$wsgScriptEndLogged = true;
}
catch (Exception $ex) {
$wsgScriptEndLogging = false;
throw $ex;
}
$wsgScriptEndLogging = false;
}
function wsfGetWikiPassword($domain, $user) {
global $wsgWikiPasswordFile;
if (!$wsgWikiPasswordFile) return NULL;
$auth= file($wsgWikiPasswordFile);
if ($auth) {
foreach ($auth as $a) {
if (!preg_match('/^(.*?):(.*?):(.*)$/',$a,$m)) continue;
if ($m[1]==$domain && $m[2]==$user) {
return $m[3];
}
}
}
return NULL;
}
function wsfGetWikiUsers($domain) {
global $wsgWikiPasswordFile;
if (!$wsgWikiPasswordFile) return NULL;
$auth= file($wsgWikiPasswordFile);
$users= array();
if ($auth) {
foreach ($auth as $a) {
if (!preg_match('/^(.*?):(.*?):(.*)$/',$a,$m)) continue;
if ($m[1]==$domain) $users[]= $m[2];
}
}
return $users;
}
function urlencodeTitle($title) {
return str_replace(
array( '%3A', '%2F', '+' ),
array( ':', '/', '_' ),
urlencode( $title )
);
}
function httpError($code, $name, $message) {
while (ob_get_level()) ob_end_clean();
$msg= "$code $name: " . escapeHtml($message);
if (headers_sent()) {
print("<p class='error'>$code $name: " . escapeHtml($message)."</p>");
trigger_error("headers already sent!", E_USER_ERROR);
die("$msg<br/>(headers already sent!)");
return;
}
header("Status: $code $name", true, $code);
header("Content-Type: text/html; charset=utf-8", true, $code);
print "<html>
<head>
<title>$code $name</title>
</head>
<body>
<h1>$code $name</h1>
<p>".escapeHtml($message)."</p>
</body>
</html>";
exit();
}
define('WS_FLOCK_LAZYNESS', 3);
define('WS_FLOCK_TIMEOUT', 60*4);
function wsfAquireFileLock($file) {
//FIXME: this function is one big race condition :(
$lock = "$file.lock";
$t= time();
while (file_exists($lock)) {
$pid = file_get_contents($lock);
if (!$pid || !($pid = (int)trim($pid))) {
wsfLog("encountered broken lock file $lock.", LL_INFO);
break; #NOTE: not quite safe, but somethign went wrong anyway.
}
if ( !isProcessAlive( $pid ) ) {
wsfLog("found lock file $lock owned by DEAD process $pid.", LL_DEBUG);
break;
}
$usecs = WS_FLOCK_LAZYNESS * 1000000;
$usecs += mt_rand(1, 1000000); //avoid collisions
wsfLog("waiting on $lock for process $pid: usleep( $usecs ).", LL_TRACE);
usleep( $usecs );
$d= time() - $t;
if ( $d > WS_FLOCK_TIMEOUT ) { #simply die if the other process fails to terminate
trigger_error("timout while waiting on lock file $lock for process $pid",E_USER_ERROR);
throw new Exception("oops"); //can't happen
}
}
#WARNING: not quite safe, RACE CONDITION!
$ok = file_put_contents($lock, getmypid());
if ($ok) wsfLog("created lock file $lock.", LL_DEBUG);
else wsfLog("failed to create lock file $lock.", LL_WARN);
return $ok;
}
function wsfReleaseFileLock($file) {
$lock = "$file.lock";
if (!file_exists($lock)) {
wsfLog("missing lock file $lock.", LL_INFO);
return false;
}
$pid = file_get_contents($lock);
if (!$pid || !($pid = (int)trim($pid))) {
wsfLog("encountered broken lock file $lock.", LL_INFO);
return false;
}
$mypid = getmypid();
if ($pid != $mypid) {
wsfLog("lock file $lock owned by someone else! expected $mypid, found $pid.", LL_WARN);
return false;
}
$ok = unlink($lock);
if ($ok) wsfLog("removed lock file $lock.", LL_DEBUG);
else wsfLog("failed to remove lock file $lock.", LL_WARN);
return $ok;
}
function fetch_via_disk_cache($u, $maxage_minutes, $slurper = NULL) {
$f = 'cache-' . urlencode($u);
if ($slurper) $f .= '%#%' . urlencode($slurper);
$f .= '.tmp';
$f = $GLOBALS['wsgPersistentStateDir'] . '/' . $f;
$oldabort = ignore_user_abort( true );
wsfAquireFileLock($f);
$txt = NULL;
$mintime = time() - $maxage_minutes * 60;
if (file_exists($f)) {
$modtime = filemtime($f);
#print " - mintime: $mintime; modtime: $modtime; - ";
if ($modtime > $mintime) {
wsfLog("using data from cache file $f.", LL_DEBUG);
$txt = file_get_contents($f);
}
}
if ($txt===NULL || $txt===false) {
wsfLog("fetching fresh data from $u.", LL_DEBUG);
if ($slurper) $txt = $slurper($u);
else $txt = file_get_contents($u);
if ($txt!==false) {
file_put_contents($f, $txt);
wsfLog("updated cache file $f.", LL_DEBUG);
}
}
wsfReleaseFileLock($f);
ignore_user_abort( $oldabort );
return $txt;
}
function read_from_disk_cache($name, $maxage_minutes) {
$f = $GLOBALS['wsgPersistentStateDir'] . '/' . urlencode($name) . ".tmp";
$oldabort = ignore_user_abort( true );
wsfAquireFileLock($f);
$txt = NULL;
$mintime = time() - $maxage_minutes * 60;
if (file_exists($f)) {
$modtime = filemtime($f);
if ($modtime > $mintime) {
wsfLog("getting data from cache file $f.", LL_DEBUG);
$txt = file_get_contents($f);
}
}
wsfReleaseFileLock($f);
ignore_user_abort( $oldabort );
return $txt;
}
function write_to_disk_cache($name, $data) {
$f = $GLOBALS['wsgPersistentStateDir'] . '/' . urlencode($name) . ".tmp";
$oldabort = ignore_user_abort( true );
wsfAquireFileLock($f);
$ok = file_put_contents($f, $data);
wsfReleaseFileLock($f);
ignore_user_abort( $oldabort );
return $ok;
}
if (defined('WS_TEST_WIKISENSE')) {
print "getting lock\n";
wsfAquireFileLock('/tmptmp/locktest');
print "got lock\n";
file_get_contents("php://stdin");
print "releasing lock\n";
wsfReleaseFileLock('/tmptmp/locktest');
print "released lock\n";
}
?>
WikiSense.php
application/x-php, 50434 bytes (load raw)

