5 * Simple, extensible user import from a CSV file.
9 * User import multi-part form.
11 function uif_import_form($form, &$form_state) {
12 // Cause return to beginning if we just completed an import
13 if (isset($form_state['storage']['step']) && $form_state['storage']['step'] >= 3) {
14 unset($form_state['storage']);
17 $step = empty($form_state['storage']['step']) ? 1 : $form_state['storage']['step'];
18 $form_state['storage']['step'] = $step;
22 $form['instructions'] = array(
23 '#type' => 'fieldset',
24 '#title' => t('User import help'),
25 '#collapsible' => TRUE,
28 $form['instructions']['help'] = array(
29 '#markup' => theme('uif_form_help'),
31 $file_size_msg = t('Your PHP settings limit the maximum file size per upload to %size. Depending on your server environment, these settings may be changed in the system-wide php.ini file, a php.ini file in your Drupal root directory, in your Drupal site\'s settings.php file, or in the .htaccess file in your Drupal root directory.', array('%size' => format_size(file_upload_max_size())));
33 $form['user_upload'] = array(
35 '#title' => t('Import file'),
37 '#description' => t('Select the CSV file to be imported.') . '<br />' . $file_size_msg,
40 $form['field_delimiter'] = array(
42 '#title' => t('Field delimiter'),
43 '#default_value' => variable_get('uif_field_delimiter', ','),
44 '#options' => uif_field_delimiters(),
45 '#description' => t('Select field delimiter. Comma is typical for CSV export files.'),
47 $form['value_delimiter'] = array(
49 '#title' => t('Value delimiter'),
50 '#default_value' => variable_get('uif_value_delimiter', '|'),
51 '#options' => uif_value_delimiters(),
52 '#description' => t('Select value delimiter for fields receiving multiple values.'),
55 $preview_count = drupal_map_assoc(array(0, 1, 10, 100, 1000, 10000, 9999999));
56 $preview_count[0] = t('None - just do it');
57 $preview_count[9999999] = t('Preview all');
59 $form['preview_count'] = array(
61 '#title' => t('Users to preview'),
62 '#default_value' => 10,
63 '#options' => $preview_count,
64 '#description' => t('Number of users to preview before importing. Note: If you run out of memory set this lower or increase your memory.')
67 $form['notify'] = array(
68 '#type' => 'checkbox',
69 '#title' => t('Notify new users of account'),
70 '#description' => t('If checked, each newly created user will receive the <em>Welcome, new user created by administrator</em> email using the template on the <a href="@url1">user settings page</a>. This is the same email sent for <a href="@url2">admin-created accounts</a>.', array('@url1' => url('admin/user/settings'), '@url2' => url('admin/user/user/create'))),
73 $form['next'] = array(
78 // Set form parameters so we can accept file uploads.
79 $form['#attributes'] = array('enctype' => 'multipart/form-data');
83 $form['instructions'] = array(
84 '#markup' => t('Preview these records and when ready to import click Import users.'),
85 '#prefix' => '<div id="uif_form_instructions">',
86 '#suffix' => '</div>',
88 $form['user_preview'] = array(
89 '#markup' => $form_state['storage']['user_preview'],
90 '#prefix' => '<div id="uif_user_preview">',
91 '#suffix' => '</div>',
93 $form['back'] = array(
95 '#value' => t('Back'),
96 '#submit' => array('uif_import_form_back'),
98 $form['submit'] = array(
100 '#value' => t('Import users'),
109 * Validate the import data.
111 function uif_import_form_validate($form, &$form_state) {
112 $step = empty($form_state['storage']['step']) ? 1 : $form_state['storage']['step'];
116 // Validate the upload file
118 'file_validate_extensions' => array('csv'),
119 'file_validate_size' => array(file_upload_max_size()),
122 if ($user_file = file_save_upload('user_upload', $validators)) {
123 $errors = uif_validate_user_file($user_file->uri, $data, $form_state);
124 if (!empty($errors)) {
125 form_set_error('user_upload', '<ul><li>' . implode('</li><li>', $errors) . '</li></ul>');
130 form_set_error('user_upload', t('Cannot save the import file to temporary storage. Please try again.'));
134 // Save the validated data to avoid reparsing
135 $form_state['storage']['data'] = $data;
141 * Form submission handler.
143 function uif_import_form_submit($form, &$form_state) {
144 $step = empty($form_state['storage']['step']) ? 1 : $form_state['storage']['step'];
147 $form_state['rebuild'] = TRUE;
148 $form_state['storage']['notify'] = isset($form_state['values']['notify']) ? $form_state['values']['notify'] : FALSE;
149 $form_state['storage']['field_delimiter'] = $form_state['values']['field_delimiter'];
150 $form_state['storage']['value_delimiter'] = $form_state['values']['value_delimiter'];
152 $preview_count = $form_state['values']['preview_count'];
153 if ($preview_count) {
154 $form_state['storage']['preview_count'] = $preview_count;
155 $form_state['storage']['user_preview'] = theme('uif_preview_users', array('data' => $form_state['storage']['data'], 'limit' => $preview_count));
163 $form_state['rebuild'] = TRUE;
164 uif_batch_import_users($form_state);
167 $form_state['storage']['step'] = $step + 1;
171 * Read the user import file and validate on the way.
174 * filepath to the user import file
176 * returns with array of users
178 * FALSE if no errors found
179 * array of error strings if error found
181 function uif_validate_user_file($uri, &$data, $form_state) {
183 $data['user'] = array();
185 $delimiter = $form_state['values']['field_delimiter'];
187 // Without this fgetcsv() fails for Mac-created files
188 ini_set('auto_detect_line_endings', TRUE);
190 if ($fp = fopen($uri, 'r')) {
191 // Read the header and allow alterations
192 $header_row = fgetcsv($fp, NULL, $delimiter);
193 $header_row = uif_normalize_header($header_row);
194 uif_adjust_header_values($header_row);
195 drupal_alter('uif_header', $header_row);
198 $errors = module_invoke_all('uif_validate_header', $header_row, $form_state);
199 uif_add_line_number($errors, $line);
200 if (!empty($errors)) {
203 $data['header'] = $header_row;
205 // Gather core and entity field info
206 $data['fields'] = uif_get_field_info($header_row);
210 while (!feof($fp) && (count($errors) < 20)) {
211 // Read a row and allow alterations
212 $row = fgetcsv($fp, NULL, $delimiter);
213 drupal_alter('uif_row', $row, $header_row);
216 if (uif_row_has_data($row)) {
217 $user_row = uif_clean_and_key_row($header_row, $row, $line);
218 $args = array(':mail' => db_like($user_row['mail']));
219 $uid = db_query_range('SELECT uid FROM {users} WHERE mail LIKE :mail', 0, 1, $args)->fetchField();
221 $more_errors = module_invoke_all('uif_validate_user', $user_row, $uid, $header_row, $form_state);
222 uif_add_line_number($more_errors, $line);
223 $errors = array_merge($errors, $more_errors);
224 $data['user'][] = $user_row;
229 if (!empty($errors)) {
234 return t('Cannot open that import file.');
237 // Final validation opportunity after header and all users validated individually.
238 $errors = module_invoke_all('uif_validate_all_users', $data['user'], $form_state);
239 if (!empty($errors)) {
245 * Trim all elements of $row, and pad $row out to the number of columns in the
246 * $header. Then replace keys in $row with $header values.
248 function uif_clean_and_key_row($header, $row, $line) {
249 $row = array_map('trim', $row);
252 $row = array_map('uif_clean_value', $row);
254 for ($i = 0; $i < count($row); $i++) {
255 if ($raw_row[$i] !== $row[$i]) {
256 $vars = array('@line' => $line, '@column' => $header[$i]);
257 drupal_set_message(t('Warning on row @line: Non UTF-8 characters were removed from @column column.', $vars), 'warning');
261 if (count($row) < count($header)) {
262 $row = array_merge($row, array_fill(count($row), count($header) - count($row), ''));
263 drupal_set_message(t('Warning on row @line: Empty values added for missing data.', array('@line' => $line)), 'warning');
265 elseif (count($row) > count($header)) {
266 array_splice($row, count($header));
267 drupal_set_message(t('Warning on row @line: Data values beyond header were truncated.', array('@line' => $line)), 'warning');
270 $row = array_combine($header, $row);
275 * Check that input is UTF-8.
277 function uif_clean_value($value) {
278 if (!drupal_validate_utf8($value)) {
279 // Remove all chars except LF, CR, and basic ascii
280 return preg_replace('/[^\x0A\x0D\x20-\x7E]/', '', $value);
287 * Is there data in the row?
289 function uif_row_has_data($row) {
290 if (isset($row) && is_array($row)) {
291 foreach ($row as $value) {
292 $value = trim($value);
293 if (!empty($value)) {
302 * Normalize the header columns.
304 function uif_normalize_header($header) {
305 $header = array_map('trim', $header);
306 $normal_header = array();
307 foreach ($header as $column) {
308 $normal_header[] = strtolower($column);
310 return $normal_header;
314 * Implementation of hook_uif_validate_header().
316 function uif_uif_validate_header($header) {
319 if (!in_array('mail', $header)) {
320 $errors[] = t('There is no mail column in the import file.');
324 foreach ($header as $label) {
325 if (isset($labels[$label])) {
326 $errors[] = t('Repeated columns in input file are not allowed: %label', array('%label' => $label));
335 * Implementation of hook_uif_validate_user().
337 function uif_uif_validate_user($user_data, $uid, $header = NULL) {
340 if (!valid_email_address($user_data['mail'])) {
341 $errors[] = t('Missing or invalid email address: %mail', array('%mail' => $user_data['mail']));
343 if (isset($user_data['name']) && empty($user_data['name'])) {
344 $errors[] = t('Username is empty. Leave this column out to create a unique username based on email address.', array());
346 if (isset($user_data['pass']) && empty($user_data['pass'])) {
347 $errors[] = t('Password is empty. Leave this column out to have an automatically generated password.', array());
349 if (isset($user_data['roles'])) {
350 uif_parse_roles($user_data['roles'], $roles_errors);
351 $errors = array_merge($errors, $roles_errors);
358 * Prepend the line number on the error.
360 function uif_add_line_number(&$errors, $line) {
361 foreach ($errors as &$error) {
362 $error = t('Error on row !line:', array('!line' => $line)) . ' ' . $error;
367 * Return user to starting point on template multi-form.
369 function uif_import_form_back($form, &$form_state) {
370 $form_state['storage']['step'] = 1;
374 * Theme preview of all users.
376 function theme_uif_preview_users($variables) {
377 $data = $variables['data'];
378 $limit = $variables['limit'];
382 foreach ($data['user'] as $user_data) {
384 if ($current > $limit) {
387 $output .= theme('uif_preview_one_user', array('data' => $user_data));
391 $output = t('There are no users to import.');
398 * Theme preview of a single user.
400 function theme_uif_preview_one_user($variables) {
401 $user_data = $variables['data'];
403 foreach ($user_data as $field => $value) {
404 $rows[] = array($field, $value);
407 $args = array(':mail' => db_like($user_data['mail']));
408 $user_exists = db_query('SELECT COUNT(*) FROM {users} WHERE mail LIKE :mail', $args)->fetchField();
409 $annotation = $user_exists ? t('update') : t('create');
410 $heading = $user_data['mail'] . ' (' . $annotation . ')';
412 return '<h3>' . $heading . '</h3>' . theme('table', array('rows' => $rows));
416 * Batch import all users.
418 function uif_batch_import_users($form_state) {
420 'title' => t('Importing users'),
421 'operations' => array(
422 array('uif_batch_import_users_process', array($form_state))
424 'progress_message' => '', // uses count(operations) which is irrelevant in this case
425 'finished' => 'uif_batch_import_users_finished',
426 'file' => drupal_get_path('module', 'uif') . '/uif.admin.inc',
432 * User import batch processing.
434 function uif_batch_import_users_process($form_state, &$context) {
436 if (empty($context['sandbox']['progress'])) {
437 $context['sandbox']['progress'] = 0;
438 $context['sandbox']['max'] = count($form_state['storage']['data']['user']);
439 $context['results']['created'] = 0;
440 $context['results']['updated'] = 0;
443 // Process max 20 users at a time
445 $notify = $form_state['storage']['notify'];
446 while ($context['sandbox']['progress'] < $context['sandbox']['max'] && $processed < 20) {
447 $index = $context['sandbox']['progress'];
448 uif_import_user($form_state['storage']['data']['user'][$index], $notify, $context['results'], $form_state);
449 $context['sandbox']['progress']++;
454 if ($context['sandbox']['progress'] != $context['sandbox']['max']) {
455 $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
460 * User import batch completion.
462 function uif_batch_import_users_finished($success, $results, $operations) {
465 if (isset($results['self'])) {
466 uif_update_user($results['self'], $user->uid);
467 $results['updated']++;
468 unset($results['self']);
470 $done = t('User import complete.');
471 $created = $results['created'] ?
472 ' ' . format_plural($results['created'], 'One user was created.', '@count users were created.') . ' ' :
474 $updated = $results['updated'] ?
475 ' ' . format_plural($results['updated'], 'One user was updated.', '@count users were updated.') . ' ' :
477 $more = t('View the <a href="@url">user list</a>.', array('@url' => url('admin/people')));
478 drupal_set_message($done . $created . $updated . $more);
481 drupal_set_message(t('An error occurred and processing did not complete.'), 'error');
488 function uif_import_user($user_data, $notify, &$results, $form_state) {
489 $args = array(':mail' => db_like($user_data['mail']));
490 if ($uid = db_query('SELECT uid FROM {users} WHERE mail LIKE :mail', $args)->fetchField()) {
492 if ($uid === $user->uid) {
493 $results['self'] = $user_data;
496 $account = uif_update_user($user_data, $uid, $form_state);
497 $results['updated']++;
500 $account = uif_create_user($user_data, $notify, $form_state);
501 $results['created']++;
508 function uif_create_user($user_data, $notify, $form_state) {
510 $account['mail'] = $user_data['mail'];
511 $account['init'] = $user_data['mail'];
512 $account['status'] = 1;
514 // Use the provided username if any, or derive it from the email
515 $username = empty($user_data['name']) ? preg_replace('/@.*$/', '', $user_data['mail']) : $user_data['name'];
516 $account['name'] = uif_unique_username($username);
518 // Use the provided password if any, otherwise a random one
519 $pass = empty($user_data['pass']) ? user_password() : $user_data['pass'];
520 $account['pass'] = $pass;
522 // Add roles if present
523 if (isset($user_data['roles'])) {
524 $account['roles'] = uif_parse_roles($user_data['roles']);
527 $account = array_merge($account, module_invoke_all('uif_pre_create', $account, $user_data, $form_state));
528 $account = user_save('', $account);
529 module_invoke_all('uif_post_create', $account, $user_data, $form_state);
532 $account->password = $pass; // For mail token; _user_mail_notify() expects this
533 _user_mail_notify('register_admin_created', $account);
540 * Update an existing user.
542 function uif_update_user($user_data, $uid, $form_state) {
543 $account = user_load($uid);
545 // todo: Support update of user mail. This requires optional inclusion of uid column,
546 // which would override use of email column as uid lookup method.
547 $changes = module_invoke_all('uif_pre_update', $account, $user_data, $form_state);
549 // Update the username if it has changed
550 if (!empty($user_data['name'])) {
551 $username = uif_unique_username($user_data['name'], $uid);
552 if ($username != $account->name) {
553 $changes['name'] = $username;
557 // Update the password if one is provided
558 if (!empty($user_data['pass'])) {
559 $changes['pass'] = $user_data['pass'];
562 // Update roles if present
563 if (isset($user_data['roles'])) {
564 $changes['roles'] = uif_parse_roles($user_data['roles']);
567 $account = user_save($account, $changes);
568 module_invoke_all('uif_post_update', $account, $user_data, $form_state);
574 * Implements hook_uif_pre_create().
576 function uif_uif_pre_create($account, $user_data, $form_state) {
577 return uif_assign_presave_fields($account, $user_data, $form_state);
581 * Implements hook_uif_pre_update().
583 function uif_uif_pre_update($account, $user_data, $form_state) {
584 return uif_assign_presave_fields($account, $user_data, $form_state);
588 * Given a starting point for a Drupal username (e.g. the name portion of an email address) return
589 * a legal, unique Drupal username.
592 * A name from which to base the final user name. May contain illegal characters; these will be stripped.
595 * (optional) Uid to ignore when searching for unique user (e.g. if we update the username after the
596 * {users} row is inserted)
599 * A unique user name based on $name.
602 function uif_unique_username($name, $uid = 0) {
603 // Strip illegal characters
604 $name = preg_replace('/[^\x{80}-\x{F7} a-zA-Z0-9@_.\'-]/', '', $name);
606 // Strip leading and trailing whitespace
609 // Convert any other series of spaces to a single space
610 $name = preg_replace('/ +/', ' ', $name);
612 // If there's nothing left use a default
613 $name = ('' === $name) ? t('user') : $name;
615 // Truncate to reasonable size
616 $name = (drupal_strlen($name) > (USERNAME_MAX_LENGTH - 10)) ? drupal_substr($name, 0, USERNAME_MAX_LENGTH - 11) : $name;
618 // Iterate until we find a unique name
621 $newname = empty($i) ? $name : $name . '_' . $i;
622 $args = array(':uid' => $uid, ':name' => $newname);
623 $found = db_query_range('SELECT uid from {users} WHERE uid <> :uid AND name = :name', 0, 1, $args)->fetchField();
631 * Theme function for import form help.
633 function theme_uif_form_help() {
634 $basic_help = '<p>' . t('Choose an import file. You\'ll have a chance to preview the data before doing the import. The import file must have a header row with a name in each column for the value you are importing. Importable fields include the following:') . '</p>';
637 // Core user table fields
638 $supported_fields = uif_get_supported_fields();
639 foreach ($supported_fields as $name => $data) {
640 if ($data['type'] == 'core') {
641 $required = uif_isset_or($data['required']) ? t('required') : t('optional');
642 $subs = array('@name' => $name, '@required' => $required, '!description' => $data['description']);
643 $items[] = t('@name (@required) - !description', $subs);
648 foreach (uif_field_info_instances('user', 'user') as $name => $data) {
649 $field_type = uif_lookup_field_type($name);
650 if (uif_is_supported_field($field_type)) {
653 '@required' => $data['required'] ? t('required') : t('optional'),
654 '%label' => $data['label'],
655 '%type' => $field_type,
656 '@description' => $data['description'] ? $data['description'] : uif_isset_or($supported_fields[$field_type]['description']),
658 $items[] = t('@name (@required) - @description (type is %type, human name is %label)', $subs);
662 $basic_help .= theme('item_list', array('items' => $items));
664 if (!module_exists('uif_plus')) {
665 $basic_help .= '<p>' . t('If you need support for entity reference, file, or image fields, or support for modules such profile2 and organic groups, try adding and enabling the <a href="http://drupal.org/project/uif_plus">User Import Framework Plus</a> module.') . '</p>';
668 // Add other modules' help
669 $helps = module_invoke_all('uif_help');
670 array_unshift($helps, $basic_help);
672 foreach ($helps as $help) {
673 $output .= '<div class="uif_help_section">' . $help . '</div>';
680 * Field delimiter options.
682 function uif_field_delimiters() {
691 * Value delimiter options.
693 function uif_value_delimiters() {
703 * Parse input roles if any.
705 function uif_parse_roles($roles_string, &$errors = array()) {
710 $role_names = explode(variable_get('uif_value_delimiter', '|'), $roles_string);
711 foreach ($role_names as $name) {
712 $rid = db_query('SELECT rid FROM {role} WHERE name = :name', array(':name' => $name))->fetchField();
713 if (is_numeric($rid) && $rid < 2) {
714 $errors[] = t('System-managed roles are not allowed: %name', array('%name' => $name));
717 $roles[$rid] = $name;
720 $errors[] = t('Unrecognized role: %name', array('%name' => $name));
729 * Perform header adjustments.
731 function uif_adjust_header_values(&$header_row) {
732 foreach ($header_row as &$label) {
733 if ('email' == $label) {
735 drupal_set_message(t('Header label <em>mail</em> substituted for deprecated label <em>email</em>.'), 'warning');
737 if ('username' == $label) {
739 drupal_set_message(t('Header label <em>name</em> substituted for deprecated label <em>username</em>.'), 'warning');
741 if ('password' == $label) {
743 drupal_set_message(t('Header label <em>pass</em> substituted for deprecated label <em>password</em>.'), 'warning');
749 * Prepare core and entity user fields for user_save().
751 function uif_assign_presave_fields($account, $user_data, $form_state) {
752 $value_delimiter = $form_state['storage']['value_delimiter'];
753 $timestamp_fields = array('created', 'access', 'login');
754 $user_fields = array();
756 foreach ($form_state['storage']['data']['fields'] as $label => $info) {
757 if (!$info['supported']) {
761 $parser = uif_isset_or($info['import']['parser']) ? $info['import']['parser'] : 'uif_get_raw_value';
763 if ($info['type'] == 'core') {
764 $user_fields[$label] = $parser($account, $info['data'], $user_data[$label]);
766 elseif ($info['type'] == 'entity') {
767 $field_values = array();
768 $values = explode($value_delimiter, $user_data[$label]);
769 $key = uif_isset_or($info['import']['key']) ? $info['import']['key'] : 'value';
771 foreach ($values as $value) {
772 $value = trim($value);
773 if (drupal_strlen($value)) {
774 $parsed_value = $parser($account, $info['data'], $value);
775 if (!is_null($parsed_value)) {
776 $field_values[] = $parsed_value;
781 for ($delta = 0; $delta < count($field_values); $delta++) {
782 if (($info['data']['cardinality'] == 1) && ($delta > 0)) {
786 if (drupal_strlen($field_values[$delta])) {
787 $user_fields[$label][LANGUAGE_NONE][$delta][$key] = $field_values[$delta];
797 * Read and store field info relevant to the import.
799 function uif_get_field_info($header) {
800 $field_info = array();
802 $users_table = drupal_get_schema('users');
803 $instance_fields = uif_field_info_instances('user', 'user');
804 $supported_fields = uif_get_supported_fields();
806 foreach ($header as $label) {
807 if (isset($users_table['fields'][$label])) {
808 $supported = isset($supported_fields[$label]);
810 $field_info[$label] = array(
812 'supported' => $supported,
813 'data' => $users_table['fields'][$label],
817 $field_info[$label]['import'] = $supported_fields[$label];
820 elseif (isset($instance_fields[$label])) {
821 $data = uif_field_info_field($label);
822 $supported = isset($supported_fields[$data['type']]);
824 $field_info[$label] = array(
826 'supported' => $supported,
831 $field_info[$label]['import'] = $supported_fields[$data['type']];
835 // Contrib module handling?
836 $supported = isset($supported_fields[$label]);
838 $field_info[$label] = array(
840 'supported' => FALSE,
846 drupal_set_message(t('Unknown column @field in the import file. Data in this column will be ignored.', array('@field' => $label)), 'warning');
854 * Given a field's machine name look up the field type.
856 function uif_lookup_field_type($field_name) {
857 if ($info = uif_field_info_field($field_name)) {
858 return $info['type'];
863 * Return TRUE if a module supports import of the passed field type.
865 function uif_is_supported_field($field_type) {
866 $supported_fields = uif_get_supported_fields();
867 return isset($supported_fields[$field_type]);
871 * Return list of supported fields.
873 function uif_get_supported_fields() {
874 $supported_fields = &drupal_static(__FUNCTION__);
875 if (!isset($supported_fields)) {
876 $supported_fields = module_invoke_all('uif_supported_fields');
877 drupal_alter('uif_supported_fields', $supported_fields);
879 return $supported_fields;
883 * Implementation of hook_uif_supported_fields().
885 * Provide out-of-box supported fields.
887 function uif_uif_supported_fields() {
889 '@strtotime_url' => 'http://php.net/manual/en/function.strtotime.php',
890 '@tz_url' => url('admin/config/regional/settings'),
891 '@mods_url' => url('admin/modules'),
892 '@flds_url' => url('admin/config/people/accounts/fields'),
899 'description' => t('the user\'s email address'),
903 'description' => t('a name for the user. If not provided, a name is created based on the email.'),
907 'description' => t('a password for the user. If not provided, a password is generated.'),
911 'description' => t('roles for the user as delimited text, e.g. "admin|editor" (without quotes).'),
915 'description' => t('the creation date for the user in <a href="@strtotime_url">strtotime()</a> format.', $subs),
916 'parser' => 'uif_get_strtotime_value',
920 'description' => t('the last access date for the user in <a href="@strtotime_url">strtotime()</a> format.', $subs),
921 'parser' => 'uif_get_strtotime_value',
925 'description' => t('the last login date for the user in <a href="@strtotime_url">strtotime()</a> format.', $subs),
926 'parser' => 'uif_get_strtotime_value',
930 'description' => t('the account status (1 = active (default) 0 = blocked).'),
934 'description' => t('the time zone to use for this user. You should <a href="@tz_url">let users set their time zone</a> if you import this.', $subs),
938 'description' => t('the language to use for this user. You should <a href="@mods_url">enable the locale module</a> if you import this.', $subs),
942 'description' => t('the uid of the user (experts only; use mail as unique key, not uid)'),
944 'list_boolean' => array(
946 'label' => t('Boolean'),
947 'description' => t('true/false. Use 0 for false, 1 for true.'),
949 'number_float' => array(
951 'label' => t('Float'),
952 'description' => t('floating point number'),
954 'number_decimal' => array(
956 'label' => t('Decimal'),
957 'description' => t('decimal number'),
959 'number_integer' => array(
961 'label' => t('Integer'),
962 'description' => t('integer number'),
964 'list_float' => array(
966 'label' => t('List (float)'),
967 'description' => t('list of floating point values'),
969 'list_integer' => array(
971 'label' => t('List (integer)'),
972 'description' => t('list of integers'),
974 'list_text' => array(
976 'label' => t('List (text)'),
977 'description' => t('list of text values'),
981 'label' => t('Text'),
982 'description' => t('text'),
984 'text_long' => array(
986 'label' => t('Long text'),
987 'description' => t('long text'),
989 'text_with_summary' => array(
991 'label' => t('Long text and summary'),
992 'description' => t('long text and summary'),
994 'taxonomy_term_reference' => array(
996 'label' => t('Taxonomy term reference'),
997 'parser' => 'uif_get_taxonomy_value',
999 'description' => t('taxonomy term ID or name'),
1005 * Helper function to process import data for core supported fields.
1007 function uif_get_raw_value($account, $field_info, $value) {
1012 * Helper function to process import data for core supported fields.
1014 function uif_get_taxonomy_value($account, $field_info, $value) {
1015 if (uif_is_natural($value)) {
1019 if (drupal_strlen($field_info['settings']['allowed_values'][0]['vocabulary'])) {
1020 $terms = taxonomy_get_term_by_name($value, $field_info['settings']['allowed_values'][0]['vocabulary']);
1021 if (count($terms)) {
1022 $tids = array_keys($terms);
1029 * Helper function to convert date string to timestamp.
1031 function uif_get_strtotime_value($account, $field_info, $value) {
1032 // BUG: do strtotime() check in validation?
1033 $timestamp = strtotime($value);
1034 return ($timestamp < 1) ? strtotime('now') : $timestamp;
1038 * Return TRUE if a $val is a natural number (integer 1, 2, 3, ...). Base can
1039 * be changed to zero if desired.
1041 function uif_is_natural($val, $base = 1) {
1045 $return = ((string)$val === (string)(int)$val);
1046 if ($return && intval($val) < $base) {
1053 * Check if a variable is set and return it if so, otherwise the alternative.
1055 function uif_isset_or(&$val, $alternate = NULL) {
1056 return isset($val) ? $val : $alternate;
1060 * Wrapper for field_info_instances() to avoid module dependency.
1062 function uif_field_info_instances($entity_type = NULL, $bundle_name = NULL) {
1063 return function_exists('field_info_instances') ? field_info_instances($entity_type, $bundle_name) : array();
1067 * Wrapper for field_info_field() to avoid module dependency.
1069 function uif_field_info_field($field_name) {
1070 return function_exists('field_info_field') ? field_info_field($field_name) : array();