/** * prints the form open tag and all hidden fields * * The incoming hidden fields are merged with the default fields * * @param array $hidden array of hidden fields to print * @return null */ protected function _print_form_head($hidden = '') { $uri_components = parse_url($_SERVER['REQUEST_URI']); echo '<form method="post" enctype="multipart/form-data" autocomplete="off" action="' . $_SERVER['REQUEST_URI'] . '" >'; $default_hidden_fields = array('action' => $this->module, 'subsource' => Participants_Db::PLUGIN_NAME, 'shortcode_page' => $uri_components['path'], 'thanks_page' => $this->submission_page, 'instance_index' => Participants_Db::$instance_index, 'pdb_data_keys' => implode('.', PDb_Base::get_field_indices($this->display_columns))); if (!$this->_empty($hidden)) { $hidden_fields = $hidden + $default_hidden_fields; } else { $hidden_fields = $default_hidden_fields; } if (!$this->_empty($this->hidden_fields)) { $hidden_fields = $hidden_fields + $this->hidden_fields; } PDb_FormElement::print_hidden_fields($hidden_fields); }
/** * sets up the pdb_data_keys value * * the purpose of this value is to tell the submission processor which fields * to process. This is a security measure so that trying to spoof the submission * by adding extra fields, editing readonly fields or deleting fields in the * browser HTML won't work. * * readonly fields and hidden fields that have values set are not included in the * set because they are not processed in this context * * @return string the value for the pdb_data_keys field */ protected function _form_data_keys() { $displayed = array(); foreach ($this->display_columns as $column) { $field = $this->fields[$column]; if (!in_array($field->form_element, array('hidden')) && $field->readonly === '0' || $field->form_element === 'captcha') { $displayed[] = $field->name; } } return implode('.', PDb_Base::get_field_indices(array_unique(array_merge($displayed, array_keys($this->hidden_fields))))); // return PDb_Base::xcrypt(implode('.', PDb_Base::get_field_indices(array_unique(array_merge($displayed, array_keys($this->hidden_fields)))))); }
/** * processes a form submit * * this processes all record form submissions front-end and back- * * @global object $wpdb * * @param array $post the array of new values (typically the $_POST array) * @param string $action the db action to be performed: insert or update * @param int|bool $participant_id the id of the record to update. If it is false, it * creates a new record, if true, it creates or updates * the default record. * @param array|bool $column_names array of column names to process from the $post * array, if false, processes a preset set of columns * * @return unknown int ID of the record created or updated, bool false if * submission does not validate */ public static function process_form($post, $action, $participant_id = false, $column_names = false) { global $wpdb; if (!empty($_FILES) && !isset($_POST['csv_file_upload'])) { foreach ($_FILES as $fieldname => $attributes) { if (UPLOAD_ERR_NO_FILE == $attributes['error']) { continue; } $filepath = self::_handle_file_upload($fieldname, $attributes); if (false !== $filepath) { // place the path to the file in the field value $post[$fieldname] = $filepath; $_POST[$fieldname] = basename($filepath); } } } /* * checks for a record with a matching field so we can exercise the * duplicate record preference */ if ($action == 'insert' and self::$plugin_options['unique_email'] !== 0) { $match_field = self::$plugin_options['unique_field']; if (isset($post[$match_field]) && !empty($post[$match_field]) && self::field_value_exists($post[$match_field], $match_field)) { /* * we have found a match */ switch (self::$plugin_options['unique_email']) { case 1: // record with same field value exists...get the id and update the existing record if ('id' == strtolower($match_field)) { $participant_id = $post[$match_field]; } else { $participant_id = self::_get_participant_id_by_term($match_field, $post[$match_field]); } // get the first one if (is_array($participant_id)) { $participant_id = current($participant_id); } // mark the record as not sent so the private link will be resent PDb_Signup::update_sent_status($participant_id, false); // set the update mode $action = 'update'; // empty the private ID that signup assigned, the record will already have one $post['private_id'] = ''; break; case 2: // set the error message if (is_object(self::$validation_errors)) { self::$validation_errors->add_error($match_field, 'duplicate'); } $action = 'skip'; // go on validating the rest of the form break; } } elseif (self::$plugin_options['unique_email'] == 1 and 'id' == strtolower($match_field) and isset($post[$match_field])) { /* * if the "OVERWRITE" option is set to "id" and the record contains an id, use it to create the record */ $participant_id = intval($post[$match_field]); if (0 !== $participant_id) { $action = 'insert'; // mark the record as not sent so the private link will be resent PDb_Signup::update_sent_status($participant_id, false); } else { $participant_id = false; } } } // set the insert status value self::$insert_status = $action; switch ($action) { case 'update': $sql = 'UPDATE ' . self::$participants_table . ' SET date_updated = NOW(), '; $where = " WHERE id = " . $participant_id; break; case 'insert': $sql = 'INSERT INTO ' . self::$participants_table . ' SET '; if (self::import_timestamp(isset($post['date_recorded']) ? $post['date_recorded'] : '') === false) { $sql .= ' `date_recorded` = NOW(), '; } if (self::import_timestamp(isset($post['date_updated']) ? $post['date_updated'] : '') === false) { $sql .= ' `date_updated` = NOW(), '; } $where = ''; break; case 'skip': return false; } /* * determine the set of columns to process * */ $new_values = array(); $column_data = array(); if (isset($_POST['pdb_data_keys'])) { $column_names = PDb_Base::get_indexed_names(explode('.', $_POST['pdb_data_keys'])); } if (is_array($column_names)) { $column_set = $column_names; } else { if (isset($_POST['action']) && $_POST['action'] == 'signup') { $column_set = 'signup'; } else { $column_set = $action == 'update' ? is_admin() ? 'backend' : 'frontend' : ($participant_id ? 'all' : 'new'); } } $columns = self::get_column_atts($column_set); // gather the submit values and add them to the query foreach ($columns as $column) { // the validation object is only instantiated when this method is called // by a form submission if (is_object(self::$validation_errors)) { self::$validation_errors->validate(isset($post[$column->name]) ? $post[$column->name] : '', $column, $post); } $new_value = false; // we can process individual submit values here switch ($column->name) { case 'id': $new_value = $participant_id; break; case 'date_recorded': case 'date_updated': case 'last_accessed': // clear the value if it's a record update if ($action == 'update' && $column->name == 'date_updated') { $post['date_updated'] = ''; } /* * this func returns bool false if the timestamp is not present or is invalid, * returns the MySQL timestamp string otherwise */ $new_value = @self::import_timestamp($post[$column->name]); break; case 'private_id': if (is_string($post['private_id']) && $post['private_id'] !== '') { $new_value = $post['private_id']; } else { $new_value = $action == 'insert' ? self::generate_pid() : false; } break; default: if (!isset($post[$column->name])) { continue; } switch ($column->form_element) { case 'multi-checkbox': case 'multi-select-other': /* match the items in the comma-separated list against the preset * values of the multi-select. Any extra values are placed in an * 'other' array element */ if (isset($post[$column->name])) { if (is_array($post[$column->name])) { if ($column->form_element == 'multi-select-other' && ($i = array_search('other', $post[$column->name]))) { unset($post[$column->name][$i]); } $value_array = $post[$column->name]; } else { // build the value array from the string form used in CSV files $value_array = array(); $incoming_value = preg_split('#([ ]*,[ ]*)#', trim($post[$column->name])); $field_values = self::unserialize_array($column->values); foreach ($incoming_value as $v) { if (in_array($v, $field_values)) { $value_array[] = $v; } else { $value_array['other'][] = $v; } } if (isset($value_array['other']) && is_array($value_array['other'])) { $value_array['other'] = implode(',', $value_array['other']); } } } else { $value_array = array(); } $new_value = self::_prepare_array_mysql($value_array); break; case 'link': /* translate the link markdown used in CSV files to the array format used in the database */ if (!is_array($post[$column->name])) { $new_value = self::_prepare_array_mysql(self::get_link_array($post[$column->name])); } else { $new_value = self::_prepare_array_mysql($post[$column->name]); } break; case 'rich-text': global $allowedposttags; $new_value = wp_kses(stripslashes($post[$column->name]), $allowedposttags); break; case 'date': $date = false; if (isset($post[$column->name])) { $date = self::parse_date($post[$column->name], $column, true); } $new_value = $date ? $date : false; break; case 'captcha': $new_value = false; break; case 'password': if (!empty($post[$column->name])) { $new_value = wp_hash_password(trim($post[$column->name])); } else { $new_value = false; } break; case 'image-upload': case 'file-upload': if (isset($_POST[$column->name . '-deletefile']) and $_POST[$column->name . '-deletefile'] === 'delete') { if (self::$plugin_options['file_delete'] == 1 or is_admin()) { self::delete_file($post[$column->name]); } unset($_POST[$column->name]); $post[$column->name] = ''; } $new_value = self::_prepare_string_mysql(trim($post[$column->name])); break; default: if (!self::backend_user() && $column->readonly != '0') { $new_value = false; } elseif (is_array($post[$column->name])) { $new_value = self::_prepare_array_mysql($post[$column->name]); } else { $new_value = self::_prepare_string_mysql(trim($post[$column->name])); } } // switch column_atts->form_element } // swtich column_atts->name /* * add the column and value to the sql; if it is bool false, skip it entirely. * Nulls are added as true nulls */ if ($new_value !== false) { if ($new_value !== null) { $new_values[] = $new_value; } $column_data[] = "`" . $column->name . "` = " . ($new_value === null ? "NULL" : "%s"); } } // columns // if the validation object exists and there are errors, stop here if (is_object(self::$validation_errors) && self::$validation_errors->errors_exist()) { // error_log( __METHOD__.' errors exist; returning'); return false; } elseif (!empty(self::$admin_message) and 'error' == self::$admin_message_type) { return false; } // add in the column names $sql .= implode(', ', $column_data); // add the WHERE clause $sql .= $where; if (WP_DEBUG) { error_log(__METHOD__ . ' storing record sql=' . $sql . ' values:' . print_r($new_values, true)); } $wpdb->query($wpdb->prepare($sql, $new_values)); // is it a new record? if ($action == 'insert') { // get the new record id for the return $participant_id = $wpdb->insert_id; /* * is this record a new one created in the admin? This also applies to CSV * imported new records */ if (is_admin()) { // if in the admin hang on to the id of the last record for an hour set_transient(self::$last_record, $participant_id, 1 * 60 * 60 * 1); // set the "email sent" flag for this id set_transient(self::$prefix . 'signup-email-sent', array($participant_id => true)); } } self::set_admin_message($action == 'insert' ? self::$i18n['added'] : self::$i18n['updated'], 'updated'); return $participant_id; }