#!/usr/bin/env php 
<?php 
 
 
/* Check that the memcache library is enabled. */ 
if(!class_exists('Memcache')) { 
    echo("Error: the memcache library appears to be unavailable.\n"); 
    echo("\n"); 
    echo("This is most likely because PHP doesn't load it for the command line\n"); 
    echo("version. You probably need to enable it somehow.\n"); 
    echo("\n"); 
    if(is_dir('/etc/php5/cli/conf.d')) { 
        echo("It is possible that running the following command as root will fix it:\n"); 
        echo(" echo 'extension=memcache.so' >/etc/php5/cli/conf.d/memcache.ini\n"); 
    } 
 
    exit(1); 
} 
 
/* This is the base directory of the simpleSAMLphp installation. */ 
$baseDir = dirname(dirname(__FILE__)); 
 
/* Add library autoloader. */ 
require_once($baseDir . '/lib/_autoload.php'); 
 
/* Initialize the configuration. */ 
$configdir = $baseDir . '/config'; 
SimpleSAML_Configuration::setConfigDir($configdir); 
 
/* Things we should warn the user about. */ 
$warnServerDown = 0; 
$warnBigSlab = 0; 
 
/* We use the stats interface to determine which servers exists. */ 
$stats = SimpleSAML_Memcache::getRawStats(); 
 
$keys = array(); 
foreach($stats as $group) { 
    foreach($group as $server => $state) { 
 
        if($state === FALSE) { 
            echo("WARNING: Server " . $server . " is down.\n"); 
            $warnServerDown++; 
            continue; 
        } 
 
        $items = $state['curr_items']; 
        echo("Server " . $server . " has " . $items . " items.\n"); 
        $serverKeys = getServerKeys($server); 
        $keys = array_merge($keys, $serverKeys); 
    } 
} 
 
echo("Total number of keys: " . count($keys) . "\n"); 
$keys = array_unique($keys); 
echo("Total number of unique keys: " . count($keys) . "\n"); 
 
echo("Starting synchronization.\n"); 
 
$skipped = 0; 
$sync = 0; 
foreach($keys as $key) { 
    $res = SimpleSAML_Memcache::get($key); 
    if($res === NULL) { 
        $skipped += 1; 
    } else { 
        $sync += 1; 
    } 
} 
 
 
echo("Synchronization done.\n"); 
echo($sync . " keys in sync.\n"); 
if($skipped > 0) { 
    echo($skipped . " keys skipped.\n"); 
    echo("Keys are skipped because they are either expired, or are of a type unknown\n"); 
    echo("to simpleSAMLphp.\n"); 
} 
 
if($warnServerDown > 0) { 
    echo("WARNING: " . $warnServerDown . " server(s) down. Not all servers are synchronized.\n"); 
} 
 
if($warnBigSlab > 0) { 
    echo("WARNING: " . $warnBigSlab . " slab(s) may have contained more keys than we were told about.\n"); 
} 
 
/** 
 * Fetch all keys available in an server. 
 * 
 * @param $server  The server, as a string with <hostname>:<port>. 
 * @return  An array with all the keys available on the server. 
 */ 
function getServerKeys($server) { 
    $server = explode(':', $server); 
    $host = $server[0]; 
    $port = (int)$server[1]; 
 
    echo("Connecting to: " . $host . ":" . $port . "\n"); 
    $socket = fsockopen($host, $port); 
    echo("Connected. Finding keys.\n"); 
 
    if(fwrite($socket, "stats slabs\r\n") === FALSE) { 
        echo("Error requesting slab dump from server.\n"); 
        exit(1); 
    } 
 
    /* Read list of slabs. */ 
    $slabs = array(); 
    while( ($line = fgets($socket)) !== FALSE) { 
        $line = rtrim($line); 
        if($line === 'END') { 
            break; 
        } 
 
        if(preg_match('/^STAT (\d+):/', $line, $matches)) { 
            $slab = (int)$matches[1]; 
            if(!in_array($slab, $slabs, TRUE)) { 
                $slabs[] = $slab; 
            } 
        } 
    } 
 
    /* Dump keys in slabs. */ 
    $keys = array(); 
    foreach($slabs as $slab) { 
 
        if(fwrite($socket, "stats cachedump " . $slab . " 1000000\r\n") === FALSE) { 
            echo("Error requesting cache dump from server.\n"); 
            exit(1); 
        } 
 
        /* We keep track of the result size, to be able to warn the user if it is 
         * so big that keys may have been lost. 
         */ 
        $resultSize = 0; 
 
        while( ($line = fgets($socket)) !== FALSE) { 
            $resultSize += strlen($line); 
 
            $line = rtrim($line); 
            if($line === 'END') { 
                break; 
            } 
 
            if(preg_match('/^ITEM (.*) \[\d+ b; \d+ s\]/', $line, $matches)) { 
                $keys[] = $matches[1]; 
            } else { 
                echo("Unknown result from cache dump: " . $line . "\n"); 
            } 
        } 
        if($resultSize > 1900000 || count($keys) >= 1000000) { 
            echo("WARNING: Slab " . $slab . " on server " . $host . ":" . $port . 
                " may have contained more keys than we were told about.\n"); 
            $GLOBALS['warnBigSlab'] += 1; 
        } 
    } 
 
    echo("Found " . count($keys) . " key(s).\n"); 
    fclose($socket); 
 
    return $keys; 
} 
 
?>
 
 |