0, 'IP_block' => 0, 'date_log' => 0, 'date_fmt' => 'd/m/Y H:i:s', )); $FoxFilterFunctions['foxvotecsv'] = 'FoxVoteCSV'; function FoxVoteCSV ($pagename, $fx) { global $FoxVoteConfig, $FoxMsgFmt; // add ip address to vote entry for logging to check for voting abuse if ($FoxVoteConfig['IP_log'] == true) $fx['ip'] = get_ip_address(); // log the date and time, enable and add {$$date} replacement varaible to vote entry template if ($FoxVoteConfig['date_log'] == true) $fx['date'] = date($FoxVoteConfig['date_fmt'], time()); // make array for all voting options (all voting fields), provided as string from 'options' $voptions = array(); if (isset($fx['vote-options'])) { $ostr = $fx['vote-options']; unset($fx['vote-options']); //remove, it is not a vote key! $op = explode(",",$ostr); foreach($op as $i => $v) $voptions[$v] = 0; //set option key to id, and set default value of 0 } // make array for the input control groups, provided as string from 'groups' $inputs = array(); if (isset($fx['vote-inputs'])) { $gps = explode(",",$fx['vote-inputs']); unset($fx['vote-inputs']); //remove, it is not a vote key! foreach($gps as $i => $vc) $inputs[$vc] = 0; } // set target for csv vote data if (isset($fx['source']) && !isset($fx['target'])) { $fx['target'] = $fx['source']; } // make template for adding vote choices into csv as one line string // of replacement variables, use ';' as separator if (!isset($fx['template']) && !isset($fx['foxtemplate'])) { $tmpl = ""; foreach ($voptions as $id => $v) $tmpl .= "{\$\$".$id."};"; if ($FoxVoteConfig['IP_log'] == true) $tmpl .= "{\$\$IP};"; //adds {$$IP} var to template for IP logging if ($FoxVoteConfig['date_log'] == true) $tmpl .= "{\$\$date};"; //adds {$$date} var to template for date/time logging $fx['foxtemplate'] = $tmpl; } foreach($fx as $key => $val) { // treat empty comment inputs same as empty vote choices // when comment gets processed for separate target than the csv table if (substr($key, 0,12)=='vote-comment') { if ($val == "") { unset($fx[$key]); //remove key if empty val foreach ($fx[':foxtemplate'] as $i => $tmpl) { if (strstr($tmpl, $key)) $fx[':foxaction'][$i] = "skip"; //will cause particular target process to be skipped } } continue; } // flatten array input from checkboxes, and rename vote key ids to include choice if (substr($key,0,4)=='vote') { if (is_array($val)) foreach($val as $i => $vv) $fx[$key.$vv] = $vv; //the index key gets dropped and value becomes part of name else $fx[$key.$val] = $val; //for other no arry input (radio) value becomes part of name unset ($fx[$key]); } } // create new entries of the vote choices, remove the original 'vote' input in $fx foreach($fx as $k => $v) { if (strstr($k,'vote-comment')){ $new = substr($k,5); $fx['vote'][$new] = $v; //preserve the comment text } else if (substr($k,0,4)=='vote') { unset ($fx[$k]); $new = substr($k,5); $fx['vote'][$new] = 1; //choosen radio and checkbox input get value 1 } } if (!isset($fx['vote'])) FoxAbort($pagename, "%red%'''You need to select from one or more of the options!'''"); // get csv data $data = foxvote_Get_Data($pagename, $fx['target'], ';'); // check IP address against IP list of previous votes and block vote if used before if (isset($fx['ip']) && $FoxVoteConfig['IP_block'] == true) { $check = foxvote_IP_Check ($data, $fx['ip']); if ($check == true ) { $FoxMsgFmt[] = "%red%'''Notice: You are allowed to vote only once!'''"; FoxAbort($pagename, "%red%'''Voting has been blocked!'''"); //return to page without posting } } // get column sums from csv table, and total vote as number of rows $sums = array(); if (empty($data)) $FoxMsgFmt[] = "'''Warning: cannot update vote sums!'''"; $sums = foxvote_Get_Sums ($data); //make PTVs to hold sums of all options //ptv 'VOTES' to hold the vote count (number of rows of data table) //ptv TOTL_ to hold the total from a single input (like from one radio or checkbox control) //ptv SUM_ to hold the total of votes for a particular choice if (!empty($sums)) { $fx['ptv_VOTES'] = $sums['VOTES'] + 1; foreach ($inputs as $vc => $o) { $fx['ptv_TOTL_'.$vc] = 0; foreach ($sums as $id => $old) { if (substr($id,0,1)==$vc) { $new = (isset($fx['vote'][$id])) ? $fx['vote'][$id] : 0; $fx['ptv_SUM_'.$id] = $old + $new; $fx['ptv_TOTL_'.$vc] = $fx['ptv_TOTL_'.$vc] + $old + $new; } } } } //merge vote choices with vote defaults into fx array for processing the posting, //which consists of SUM and TOTL PTV updates, and adding the vote as data entry to csv table. $fx = array_merge($fx, $voptions, $fx['vote']); return $fx; } function foxvote_Get_Data($pagename, $source, $sep) { global $FoxMsgFmt; // get text rows from page section $text = RetrieveAuthSection($pagename, $source); if ($text=='') { $FoxMsgFmt[] = "Error: cannot get csv data from '''$source'''"; return;} $text = trim($text,"\r\n"); $data = explode("\n", $text); foreach ($data as $i => $row) { $data[$i] = str_getcsv($row, $sep, "\"", "`"); } if (empty($data)) { $FoxMsgFmt[] = "Error: Parsing of csv data failed!"; return; } return $data; } function foxvote_IP_Check ( $data, $ip) { $ik = array_search('ip', $data[0]); if (isset($ik)) { $ips = array_column($data, $ik); $ips = array_filter($ips); } if (in_array($ip, $ips)) return true; else return false; } function foxvote_Get_Sums ( $data ) { // create header array, remove header row from data array $header = array_shift($data); //create sums array from data columns $sums['VOTES'] = count($data); //number of rows as votes foreach($header as $i=>$val) { $sums[$val] = array_sum(array_column($data, $i)); } return $sums; } function get_ip_address() { $ip_keys = array( // Providers 'HTTP_CF_CONNECTING_IP', // Cloudflare 'HTTP_INCAP_CLIENT_IP', // Incapsula 'HTTP_X_CLUSTER_CLIENT_IP', // RackSpace 'HTTP_TRUE_CLIENT_IP', // Akamai // Proxies 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED', 'HTTP_CLIENT_IP', 'HTTP_X_REAL_IP', 'HTTP_FORWARDED', 'HTTP_FORWARDED_FOR', // Standard fallback 'REMOTE_ADDR' ); foreach ($ip_keys as $key) { if (!isset($_SERVER[$key])) continue; $value = $_SERVER[$key]; if (!empty($value) && is_string($value)) { foreach (explode(',', $value) as $ip) { // trim for safety measures $ip = trim($ip); // attempt to validate IP if ( //filter_var($ip, FILTER_VALIDATE_IP) // any valid IP address filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_RES_RANGE | // filter reserved IP addresses FILTER_FLAG_IPV4 // allow only IPv4 addresses ) ) { return $ip; } } } } return $_SERVER['REMOTE_ADDR']; }