2017-03-21 22:11:24 +01:00
< ? php
2017-06-13 12:29:22 +02:00
require '/var/www/html/vendor/phpmailer/phpmailer/PHPMailerAutoload.php' ;
2017-03-28 01:11:24 +02:00
$timer_start = microtime ( true ); // Start counter for PHP execution time tracking
2017-03-21 22:11:24 +01:00
2017-03-22 02:01:06 +01:00
$codemod = 2138367 ; // modificator with which the confirmation ID will be obfuscated
2017-03-23 23:30:03 +01:00
$output = " " ;
2017-06-22 13:07:24 +02:00
$selfurl = " https://publiccode.eu/sign " ; // absolute URL of this PHP script
2017-06-13 11:47:33 +02:00
$db = " /usr/share/blog/data/signatures/signatures.json " ; // Signature database path
$ipdb = " /usr/share/blog/data/signatures/ips.json " ; // IP database path
$spamdb = " /usr/share/blog/data/signatures/spammer_ " . date ( 'Y-m-d' ) . " .json " ; // This day's potential spammer database
2017-03-22 00:06:08 +01:00
2017-03-28 01:24:06 +02:00
///////////////////
/// SPAM CHECKS ///
///////////////////
2017-03-23 23:56:56 +01:00
2017-03-28 01:24:06 +02:00
// Test whether visitor fell for honeypot
$honeypot = isset ( $_POST [ 'url' ]) ? $_POST [ 'url' ] : false ;
2017-03-24 01:45:16 +01:00
if ( ! empty ( $honeypot )) { // honeypot input field isn't empty
2017-03-23 23:56:56 +01:00
$output .= " Invalid input. Error code: 5|°4m " ;
show_page ( $output , 1 );
}
2017-03-28 00:33:44 +02:00
// Check whether IP submitted too often
$limit_hits = 5 ; // Max. X hits...
$limit_time = 180 ; // in X seconds
$limit_spam = 15 ; // More than X hits in $limit_time will get this IP to a special DB
$limit_exceeded = FALSE ; // Will be set TRUE if more hits with this IP in $limit_time than $limit_hits
$now = time (); // Current UNIX time
$ip = sha1 ( php_uname () . $_SERVER [ 'REMOTE_ADDR' ]); // Hashed IP of visitor
read_ips ( $ipdb );
$ip_unknown = TRUE ;
foreach ( $ips as $key => & $entry ) {
if ( $now - $limit_time > $entry [ 'time' ]) { // Delete entries that are older than $limit_time
unset ( $ips [ $key ]);
} else if ( $entry [ 'ip' ] === $ip ) { // IP matches, and entry under $limit_time
$ip_unknown = FALSE ;
if ( $entry [ 'hits' ] >= $limit_hits ) { // Try limit exceeded, iterate and set abort variable
$entry [ 'hits' ] = $entry [ 'hits' ] + 1 ;
$limit_exceeded = TRUE ;
if ( $entry [ 'hits' ] > $limit_spam ) { // IP exceeds spam limit
2017-03-28 01:40:40 +02:00
if ( ! file_exists ( $spamdb )) { touch ( $spamdb ); }
2017-03-28 00:33:44 +02:00
$realip = $_SERVER [ 'REMOTE_ADDR' ];
$spammer = file_get_contents ( $spamdb );
$pattern = preg_quote ( $realip );
if ( ! preg_match ( " / $pattern / " , $spammer , $match )) {
2017-03-28 01:40:40 +02:00
file_put_contents ( $spamdb , $realip . " \n " , FILE_APPEND | LOCK_EX );
2017-03-28 00:33:44 +02:00
}
}
} else { // Try limit not exceeded, just iterate
$entry [ 'hits' ] = $entry [ 'hits' ] + 1 ;
}
}
}
// Extend IP database if this IP was unknown
if ( $ip_unknown ) {
$ips [] = array ( " time " => $now , " ip " => $ip , " hits " => 1 );
}
// Write IP database back to file
file_put_contents ( $ipdb , json_encode ( $ips , JSON_PRETTY_PRINT ), LOCK_EX );
unset ( $ips );
// Abort if IP limit is exceeded
if ( $limit_exceeded ) {
$output .= " Too many submits with your IP. Please try again in a few minutes. " ;
show_page ( $output , 1 );
}
2017-03-28 01:24:06 +02:00
///////////////////////
/// FORM EVALUATION ///
///////////////////////
// Get basic info from form
if ( $_SERVER [ 'REQUEST_METHOD' ] === 'POST' ) {
$action = isset ( $_POST [ 'action' ]) ? $_POST [ 'action' ] : false ;
} else {
$action = isset ( $_GET [ 'action' ]) ? $_GET [ 'action' ] : false ;
}
// Continue only if action = sign/confirmation
// Depending on action, get important variables
2017-03-22 01:07:43 +01:00
if ( empty ( $action )) {
2017-03-23 23:30:03 +01:00
$output .= " No action defined. " ;
show_page ( $output , 1 );
2017-03-28 01:24:06 +02:00
} else if ( $action === " sign " ) { // sign
2017-03-24 02:21:10 +01:00
$name = isset ( $_POST [ 'name' ]) ? $_POST [ 'name' ] : false ;
$email = isset ( $_POST [ 'email' ]) ? $_POST [ 'email' ] : false ;
$country = isset ( $_POST [ 'country' ]) ? $_POST [ 'country' ] : false ;
$zip = isset ( $_POST [ 'zip' ]) ? $_POST [ 'zip' ] : false ;
2017-08-30 16:32:07 +02:00
$comment = isset ( $_POST [ 'comment' ]) ? $_POST [ 'comment' ] : false ;
2017-03-24 02:21:10 +01:00
$permPriv = isset ( $_POST [ 'permissionPriv' ]) ? $_POST [ 'permissionPriv' ] : false ;
$permNews = isset ( $_POST [ 'permissionNews' ]) ? $_POST [ 'permissionNews' ] : false ;
$permPub = isset ( $_POST [ 'permissionPub' ]) ? $_POST [ 'permissionPub' ] : false ;
2017-03-22 01:07:43 +01:00
// Check for missing required fields
2017-03-23 21:37:01 +01:00
if ( empty ( $name ) || empty ( $email ) || empty ( $permPriv )) {
2017-03-23 23:30:03 +01:00
$output .= " At least one required variable is empty. " ;
show_page ( $output , 1 );
2017-03-22 01:07:43 +01:00
}
2017-03-28 01:24:06 +02:00
} else if ( $action === " confirm " ) { // confirm
2017-03-22 02:01:06 +01:00
$confirmcode = isset ( $_GET [ 'code' ]) ? $_GET [ 'code' ] : false ;
$confirmid = isset ( $_GET [ 'id' ]) ? $_GET [ 'id' ] : false ;
2017-03-22 01:07:43 +01:00
// Check for missing required fields
2017-03-22 02:01:06 +01:00
if ( empty ( $confirmcode ) || empty ( $confirmid )) {
2017-03-23 23:30:03 +01:00
$output .= " Confirmation code or ID is missing. " ;
show_page ( $output , 1 );
2017-03-22 01:07:43 +01:00
}
2017-03-28 01:24:06 +02:00
} else { // invalid
2017-03-23 23:30:03 +01:00
$output .= " Invalid action. " ;
show_page ( $output , 1 );
2017-03-22 01:07:43 +01:00
}
2017-03-22 00:06:08 +01:00
// Validate input
2017-03-23 23:30:03 +01:00
//TODO
2017-03-22 00:06:08 +01:00
2017-03-28 01:24:06 +02:00
///////////////
2017-03-22 01:07:43 +01:00
/// SIGNING ///
2017-03-28 01:24:06 +02:00
///////////////
2017-03-22 01:07:43 +01:00
if ( $action === " sign " ) {
2017-03-23 23:39:27 +01:00
read_db ( $db );
2017-03-22 01:07:43 +01:00
// Test whether email is a duplicate
$total = count ( $data );
for ( $row = 0 ; $row < $total ; $row ++ ) {
if ( $email === $data [ $row ][ 'email' ]) {
2017-03-23 23:30:03 +01:00
$output .= " We already received a signature with this email address. " ;
show_page ( $output , 1 );
2017-03-22 01:07:43 +01:00
}
2017-03-22 00:06:08 +01:00
}
2017-03-23 23:30:03 +01:00
// Take sequential ID
$id = $total ;
// Create a random string for email verification
$code = rand ( 1000000000 , 9999999999 ) . uniqid ();
$codeid = $id + $codemod ; // this is to obfuscate the real ID of the user if we don't want to publish this number
2017-03-22 00:06:08 +01:00
2017-03-23 23:30:03 +01:00
// Append new signature to array
2017-03-24 01:51:22 +01:00
$data [] = array ( " id " => $id ,
2017-03-23 23:30:03 +01:00
" name " => $name ,
" email " => $email ,
" country " => $country ,
" zip " => $zip ,
2017-08-30 16:32:07 +02:00
" comment " => $comment ,
2017-03-23 23:30:03 +01:00
" permPriv " => $permPriv ,
" permNews " => $permNews ,
" permPub " => $permPub ,
" code " => $code ,
" confirmed " => " no " );
2017-03-22 00:06:08 +01:00
2017-03-23 23:30:03 +01:00
// Encode to JSON again and write to file
$allsig = json_encode ( $data , JSON_PRETTY_PRINT );
file_put_contents ( $db , $allsig , LOCK_EX );
unset ( $allsig );
2017-06-13 12:29:22 +02:00
$mail = new PHPMailer ;
$mail -> isSMTP ();
$mail -> Host = " mail.fsfe.org " ;
$mail -> setFrom ( 'noreply@fsfe.org' , 'Public Money, Public Code' );
2017-03-23 23:30:03 +01:00
// Send email asking for confirmation
2017-06-13 12:32:43 +02:00
$mail -> addAddress ( $email );
2017-06-13 12:29:22 +02:00
$mail -> Subject = " One step left to sign the \" Public Money - Public Code \" letter " ;
$mail -> Body = " Dear $name , \r \n \r \n " .
2017-03-24 01:45:16 +01:00
" Thank you for signing the open \" Public Money - Public Code \" letter! \r \n \r \n " .
2017-03-23 23:30:03 +01:00
" In order to confirm your signature, please visit following link: \r \n " .
" $selfurl ?action=confirm&id= $codeid &code= $code \r \n \r \n " .
" If your confirmation succeeds, your signature will appear on the website within the next few hours. " ;
2017-03-22 00:06:08 +01:00
2017-06-13 12:32:43 +02:00
$mail -> Send ();
2017-03-23 23:30:03 +01:00
$output .= " Thank you for signing our open letter! <br /><br /> " ;
$output .= " We just sent an email to your address ( $email ) for you to confirm your signature. " ;
show_page ( $output , 0 );
2017-03-22 00:06:08 +01:00
2017-03-22 02:01:06 +01:00
} else if ( $action === " confirm " ) {
2017-03-28 01:24:06 +02:00
////////////////////
/// CONFIRMATION ///
////////////////////
2017-03-22 02:01:06 +01:00
$id = $confirmid - $codemod ; // substract the obfuscation number from the given ID
2017-03-23 23:39:27 +01:00
2017-03-24 01:45:16 +01:00
if ( $id < 0 ) { // $confirmid is less than $codemod
2017-03-23 23:30:03 +01:00
$output .= " Invalid signature ID. " ;
show_page ( $output , 1 );
}
read_db ( $db );
2017-03-24 01:45:16 +01:00
if ( empty ( $data [ $id ])) { // there is no array element with this ID
2017-03-23 23:30:03 +01:00
$output .= " The signature ID does not exist. " ;
show_page ( $output , 1 );
}
2017-03-22 02:01:06 +01:00
$email = $data [ $id ][ 'email' ]; // Get the user's email in case we need it
$code = $data [ $id ][ 'code' ]; // The confirmation code according to the DB
$confirmed = $data [ $id ][ 'confirmed' ]; // The current confirmation status
// Check whether the confirmation code is what we saved in the DB
if ( $confirmed === " no " ) {
if ( $confirmcode === $code ) {
// Set the user's confirmation key to "yes"
$data [ $id ][ 'confirmed' ] = " yes " ;
// Encode to JSON again and write to file
2017-03-24 01:45:16 +01:00
$allsig = json_encode ( $data , JSON_PRETTY_PRINT ); // TODO: JSON_PRETTY_PRINT could be turned off to make file smaller
2017-03-22 02:01:06 +01:00
file_put_contents ( $db , $allsig , LOCK_EX );
unset ( $allsig );
2017-03-23 23:39:27 +01:00
$output .= " Your email address has been confirmed. <br /><br /> " ;
2017-03-24 01:45:16 +01:00
$output .= " Thank you for signing the open letter! Your signature will appear <a href='/signatures/'>in the signature list</a> within the next hours. " ;
2017-03-23 23:30:03 +01:00
show_page ( $output , 0 );
2017-03-22 02:01:06 +01:00
} else {
2017-03-23 23:39:27 +01:00
$output .= " The provided confirmation code is incorrect. " ;
2017-03-23 23:30:03 +01:00
show_page ( $output , 1 );
2017-03-22 02:01:06 +01:00
}
2017-03-23 23:30:03 +01:00
} else if ( $confirmed === " yes " ) {
2017-03-24 01:45:16 +01:00
$output .= " This email address is already confirmed. It can take a few hours until your signature appears <a href='/signatures/'>in the signature list</a>. " ;
2017-03-23 23:30:03 +01:00
show_page ( $output , 1 );
2017-03-22 02:01:06 +01:00
} else {
2017-03-23 23:30:03 +01:00
$output .= " This signature ID does not exist or the confirmation status is broken. " ;
show_page ( $output , 1 );
2017-03-22 02:01:06 +01:00
}
2017-03-23 23:30:03 +01:00
} // END confirm
2017-03-28 01:24:06 +02:00
////////////////
// FUNCTIONS ///
////////////////
// Read signatures database (should only be called if really needed)
function read_db ( $db ) {
global $data ; // declare $data a global variable to access it outside this function
if ( ! file_exists ( $db )) {
touch ( $db );
}
$file = file_get_contents ( $db , true );
$data = json_decode ( $file , true );
unset ( $file );
}
// Read IP database
function read_ips ( $ipdb ) {
global $ips ; // declare $data a global variable to access it outside this function
if ( ! file_exists ( $ipdb )) {
touch ( $ipdb );
}
$file = file_get_contents ( $ipdb , true );
$ips = json_decode ( $file , true );
unset ( $file );
}
// Replace a given placeholder in a template HTML page with given content
2017-03-23 23:30:03 +01:00
function replace_page ( $template , $placeholder , $content ){
$vars = array ( $placeholder => $content );
return str_replace ( array_keys ( $vars ), $vars , $template );
2017-03-22 00:06:08 +01:00
}
2017-03-28 01:24:06 +02:00
// Show the filled template page, depending on exit code
2017-03-23 23:30:03 +01:00
function show_page ( $output , $exit ) {
if ( $exit === 0 ) {
$headline = " Success " ;
$notice = " " ;
} else if ( $exit === 1 ) {
$headline = " Error " ;
2017-03-24 01:45:16 +01:00
$notice = " <p>This error could have happened because one or more fields contained invalid information. Please try again. If you think that you see this error by mistake, please contact us.</p> " ;
2017-03-23 23:30:03 +01:00
} else {
$headline = " Thank you " ;
}
$template = file_get_contents ( '../template/index.html' , true );
$page = replace_page ( $template , ':HEADLINE:' , $headline );
$page = replace_page ( $page , ':BODY1:' , $output );
$page = replace_page ( $page , ':BODY2:' , $notice );
echo $page ;
unset ( $data );
2017-03-28 01:11:24 +02:00
// PHP execution time tracking
global $timer_start ;
2017-03-28 01:42:45 +02:00
echo " <!-- PHP execution time: " . ( microtime ( true ) - $timer_start ) * 1000 . " ms --> \n " ;
2017-03-28 01:11:24 +02:00
2017-03-23 23:30:03 +01:00
exit ( $exit );
}
2017-03-21 22:11:24 +01:00
?>