private function contact_create($mode = 'import')
 {
     $this->import_status_update('contact');
     // bug fix for $this->contacts keep being appended
     if (!empty($this->contacts)) {
         unset($this->contacts);
         $this->contacts = array();
     }
     for ($i = 0; $i < count($this->csv->data); $i++) {
         $param = array('version' => '3', 'contact_type' => 'Individual');
         if ($mode == 'import') {
             $param['dupe_check'] = $this->data->dupe_check == 1 ? TRUE : FALSE;
             // #FIX issue 87: auto-append contact source if it is not mapped
             // appending the date and the job id to the import
             if (!in_array('contact_source', $this->contacts)) {
                 $param['contact_source'] = date('Ymd') . '_' . $this->data->jobid;
             }
             // #FIX issue 72: Add email only de-dupe feature
             if ($this->data->dupe_check == 2) {
                 $mapping = array_flip($this->contact_data);
                 $email = $this->csv->data[$i][$mapping['email']];
                 $contact_id = $this->check_email($email);
                 if (is_numeric($contact_id)) {
                     // for email only dedupe, we delete the param and skip this iteration
                     $this->log->_log('Error on CSV line ' . $i . ':, (Matching contact found:, ' . $contact_id . '),' . implode(',', $this->csv->data[$i]), 'error_csv');
                     unset($param);
                     continue;
                 }
             }
         }
         // in case we are doing an append with *ONLY* Location data we still need to fill $this->contact
         if (count($this->contact_data) == 1) {
             $id = array_values($this->contact_data);
             $column = array_keys($this->contact_data);
             if ($id[0] == 'external_identifier') {
                 $contact_id = $this->fetch_contact_id($this->csv->data[$i][$column[0]]);
             } else {
                 $contact_id = $this->csv->data[$i][$column[0]];
             }
             if (isset($contact_id) && $contact_id != '') {
                 $this->contacts[$contact_id] = $this->csv->data[$i];
             } else {
                 // unmatched append row
                 $this->log->_log('Record not found in database:,' . implode(',', $this->csv->data[$i]), 'error_csv');
             }
         } else {
             foreach ($this->contact_data as $column => $field) {
                 // dealing with some special fields because of CiviCRM's internal workings
                 switch ($field) {
                     case 'birth_date':
                         $param[$field] = civicrm_import_utils::format_date($this->csv->data[$i][$column], $this->data->date_format);
                         break;
                     case 'gender':
                         $param[$field] = civicrm_import_utils::format_gender($this->csv->data[$i][$column]);
                         break;
                         // in appending job you have to get contact_id if they choose to match to external identifier
                     // in appending job you have to get contact_id if they choose to match to external identifier
                     case 'external_identifier':
                         // get the contact id
                         if ($mode == 'import') {
                             $param[$field] = $this->csv->data[$i][$column];
                         } else {
                             $param['contact_id'] = $this->fetch_contact_id($this->csv->data[$i][$column]);
                         }
                         break;
                     default:
                         $param[$field] = $this->csv->data[$i][$column];
                         break;
                 }
             }
             // print_r($param);
             // data filtering validation:
             // if the $param does not fit our validation requirement
             // i.e. First name, Last name, Email, we do not import them.
             // #FEATURE: $this->check_filter should return an array of bad fields so we can pin them down in
             // the log
             if ($this->check_filter($param, $mode)) {
                 if ($mode == 'import') {
                     // @CiviCRM API (v3)
                     $contact = civicrm_api('contact', 'create', $param);
                 } else {
                     if (isset($param['contact_id']) && $param['contact_id'] != '') {
                         // @CiviCRM API (v3)
                         $param['id'] = $param['contact_id'];
                         unset($param['contact_id']);
                         $contact = civicrm_api('contact', 'create', $param);
                     } else {
                         // log all the ones that did not find a matching record into the error_csv
                         $this->log->_log('Error on CSV line ' . $i . ':, (No matching contact found with the id provided),' . implode(',', $this->csv->data[$i]), 'error_csv');
                     }
                 }
                 // #FIXED: memory leak from API call
                 CRM_Core_DAO::freeResult();
                 if ($contact['is_error'] == 1) {
                     $this->log->_log('Error on CSV line ' . $i . ':, (' . $contact['error_message'] . '),' . implode(',', $this->csv->data[$i]), 'error_csv');
                 } else {
                     $this->contacts[$contact['id']] = $this->csv->data[$i];
                     $this->contact_imported++;
                     // record the contact import count for tracking
                     if ($this->contact_imported % 100 == 0) {
                         $this->update_count('contact');
                     }
                 }
             } else {
                 // log this row as bad row
                 $this->log->_log('Error on CSV line ' . $i . ':, (Bad last name or email on CSV line),' . implode(',', $this->csv->data[$i]), 'error_csv');
             }
             $this->update_count('contact');
         }
     }
     $this->log->_log($this->contact_imported . ' number of contact records created from ' . count($this->csv->data) . ' number of rows read from CSV file');
     // free the original parsed csv from memory
     unset($this->csv->data);
 }
 public function validate_custom_fields($mapping = array(), $csv_filepath, $depth = 100, $csv_log = FALSE)
 {
     $this->log->__set('logging', $csv_log);
     # 1st, get the import data to see if there's any custom fields
     // $mappings = unserialize($this->data->mapping);
     $custom_fields_mapping = array();
     $custom_fields_mapping_set = array();
     foreach ($mapping as $column => $field) {
         if (strstr($field, 'custom_')) {
             $custom_fields_mapping[$column] = substr($field, 7, 8);
             // just want the custom field id
         }
     }
     // if there's no custom fields to import, don't waste time
     if (!empty($custom_fields_mapping)) {
         # 2nd, are they radios, checkboxes or selections? (SET values)
         foreach ($custom_fields_mapping as $column => $custom_field_id) {
             $custom_field_type = $this->db->get_var(sprintf("SELECT html_type FROM civicrm_custom_field WHERE id = %d", $custom_field_id));
             if ($custom_field_type == 'Select' || $custom_field_type == 'CheckBox' || $custom_field_type == 'Radio') {
                 $custom_fields_mapping_set[$column] = $custom_field_id;
             }
         }
         // only care if the custom field we import has set values
         if (!empty($custom_fields_mapping_set)) {
             # 3rd, fetch the expected set values of the custom fields
             $errors = 0;
             foreach ($custom_fields_mapping_set as $column => $custom_field_id) {
                 $query = sprintf("SELECT cov.value FROM civicrm_option_value cov \n\t\t\t\t\tJOIN civicrm_option_group cog ON cov.option_group_id = cog.id\n\t\t\t\t\tJOIN civicrm_custom_field ccf ON ccf.option_group_id = cog.id\n\t\t\t\t\tWHERE ccf.option_group_id IS NOT NULL AND ccf.id = %d", $custom_field_id);
                 if ($results = $this->db->get_results($query, ARRAY_N)) {
                     # 4 match the fields with csv data
                     $_res = civicrm_import_utils::flattenArray($results);
                     #4.1 parse limited data
                     $this->csv->offset = 1;
                     $this->csv->limit = $depth;
                     $this->csv->parse($csv_filepath);
                     for ($i = 0; $i < count($this->csv->data); $i++) {
                         if (!in_array($this->csv->data[$i][$column], $_res)) {
                             $errors++;
                             // mark the error and log the data validation error
                             $this->csv->data[$i][$column] .= ' [acceptable values are: ' . implode(',', $_res) . ']';
                             $this->log->_log($this->csv->unparse(array($this->csv->data[$i])), 'error_csv', FALSE);
                         }
                     }
                 }
             }
             // end of foreach
             if ($errors > 0) {
                 // Trigger error email and point or attach the error csv report and include the message below
                 // echo $errors . " Error(s) occured. Inconsistent custom data detected, this import job is cancelled";
                 $this->custom_field_errors = $errors;
                 return FALSE;
             }
             // At this point we are successful?
             unset($this->csv->data);
             return TRUE;
         }
     } else {
         // if no custom field detected, just return TRUE
         return TRUE;
     }
 }