Location: PHPKode > scripts > ZeroBin > zerobin/index.php
<?php
$VERSION='Alpha 0.11';
/*
ZeroBin - a zero-knowledge paste bin
Please see project page: http://sebsauvage.net/wiki/doku.php?id=php:zerobin
*/

if (version_compare(PHP_VERSION, '5.2.6') < 0) die('ZeroBin requires php 5.2.6 or above to work.');

/* Convert paste id to storage path.
   eg. 'e3570978f9e4aa90' --> 'data/e3/57/'
*/
function dataid2path($dataid)
{
    return 'data/'.substr($dataid,0,2).'/'.substr($dataid,2,2).'/';
}

// In case stupid admin has left magic_quotes enabled in php.ini:
if (get_magic_quotes_gpc())
{
    function stripslashes_deep($value) { $value = is_array($value) ? array_map('stripslashes_deep', $value) : stripslashes($value); return $value; }
    $_POST = array_map('stripslashes_deep', $_POST);
    $_GET = array_map('stripslashes_deep', $_GET);
    $_COOKIE = array_map('stripslashes_deep', $_COOKIE);
}

if (!empty($_POST['data'])) // Create new paste
{
    header('Content-type: application/json');

    // Create storage directory if it does not exist.
    if (!is_dir('data'))
    { 
        mkdir('data',0705); 
        chmod('data',0705); 
        file_put_contents('data/.htaccess',"Allow from none\nDeny from all\n"); 
    }

    // Make sure last paste from the IP address was more than 10 seconds ago. 
    $tfilename='trafic_limiter.php';
    if (!is_file($tfilename))
    { 
        file_put_contents($tfilename,"<?php\n\$GLOBALS['trafic_limiter']=array();\n?>"); 
        chmod($tfilename,0705); 
    }
    include $tfilename;
    $tl=$GLOBALS['trafic_limiter'];
    $ip=$_SERVER['REMOTE_ADDR'];
    if (!empty($tl[$ip]) && ($tl[$ip]+10>=time()))
    {        
        echo json_encode(array('status'=>1,'message'=>'Please wait 10 seconds between each paste.'));
        exit;
    }
    $tl[$ip]=time();
    file_put_contents($tfilename, "<?php\n\$GLOBALS['trafic_limiter']=".var_export($tl,true).";\n?>");

    $data = $_POST['data'];
    
    // Make sure content is not too big.
    if (strlen($data)>2000000)
    {
        echo json_encode(array('status'=>1,'message'=>'Paste is limited to 2 Mb of encrypted data.'));
        exit;
    }
    
    // Make sure content is valid json
    $decoded = json_decode($data);
    if ($decoded==null)
    {
        echo json_encode(array('status'=>1,'message'=>'Data is not in json format.'));
        exit;
    }
    $decoded = (array)$decoded;

    // Make sure required fields are present and that they are base64 data.  
    $error = false;
    foreach(array('iv','salt','ct') as $k)
    {
        if (!array_key_exists($k,$decoded))  { $error=true; }
        if (base64_decode($decoded[$k],$strict=true)==null) { $error=true; }
    }
    if ($error)
    {
        echo json_encode(array('status'=>1,'message'=>'Invalid data.'));
        exit;    
    }
    
    // FIXME: Reject data if entropy is too low ?
    
    // We want a small hash and avoid collisions: Truncated MD5 will do the trick:
    $dataid = substr(hash('md5',$data),0,16);
    // The $prefixdir system creates subdirectories in order to limit the number of files per directory.
    // (A high number of files in a single directory can slow things down.)
    // eg. "f468483c313401e8" will be stored in "data/f4/68/f468483c313401e8"
    // High-trafic websites may want to deepen the directory structure (like Squid does).
    $storagedir = dataid2path($dataid);
    if (!is_dir($storagedir)) mkdir($storagedir,$mode=0705,$recursive=true); 

    if (is_file($storagedir.$dataid)) // Oups... improbable collision.
    {
        echo json_encode(array('status'=>1,'message'=>'You are unlucky. Try again.'));
        exit;
    }
    
    // Write expiration date if required
    if (!empty($_POST['expire']))
    {
        $expire=$_POST['expire'];
        $d = null;
        if ($expire=='10min') $d=time()+10*60;
        elseif ($expire=='1hour') $d=time()+60*60;
        elseif ($expire=='1day') $d=time()+24*60*60;
        elseif ($expire=='1month') $d=time()+30*24*60*60; // Well this is not *exactly* one month, it's 30 days.
        elseif ($expire=='1year') $d=time()+365*24*60*60;
        if ($d!=null) file_put_contents($storagedir.$dataid.'.expire',$d);
    }
        
    file_put_contents($storagedir.$dataid,$data);
    echo json_encode(array('status'=>0,'id'=>$dataid)); // 0 = no error
    exit;
}

$CIPHERDATA='';
$ERRORMESSAGE='';
if (!empty($_SERVER['QUERY_STRING']))  // Display an existing paste.
{
    $dataid = $_SERVER['QUERY_STRING'];
    if (preg_match('/[a-z\d]{16}/',$dataid))  // Is this a valid paste identifier ?
    {
        $filename = dataid2path($dataid).$dataid;
        if (is_file($filename)) // Check that paste exists.
        {
            // If expiration data is present, check if paste has expired.
            $expire_filename=$filename.'.expire';
            if (is_file($expire_filename))
            {
                $expire=intval(file_get_contents($expire_filename));
                if ($expire<time())
                {
                    unlink($filename); // Delete the files
                    unlink($expire_filename);
                    $ERRORMESSAGE='Paste does not exist or has expired.';
                }
            }
            if ($ERRORMESSAGE=='') // If no error, return the paste.
            {
                $CIPHERDATA = file_get_contents($filename);
            }
        }
        else
        {
            $ERRORMESSAGE='Paste does not exist or has expired.';
        }
    }
}
include "lib/rain.tpl.class.php";
header('Content-Type: text/html; charset=utf-8');
$page = new RainTPL;    
$page->assign('CIPHERDATA',$CIPHERDATA);
$page->assign('VERSION',$VERSION);
$page->assign('ERRORMESSAGE',$ERRORMESSAGE);
$page->draw('page');
?>
Return current item: ZeroBin