· 8 years ago · Feb 23, 2018, 10:44 AM
1<?php
2/**
3 * @package Import_Users_from_CSV
4 */
5/*
6Plugin Name: Import Users from CSV
7Plugin URI: http://wordpress.org/extend/plugins/import-users-from-csv/
8Description: Import Users data and metadata from a csv file. <a href="https://stackoverflow.com/q/48859151/9217760" target="_blank"><strong>Modified by Sally.</strong></a>
9Version: 20180219.1
10Author: Ulrich Sossou
11Author URI: http://ulrichsossou.com/
12License: GPL2
13Text Domain: import-users-from-csv
14
15This version has been tested with WordPress 4.9.4 and PHP 7.2.0.
16*/
17/* Copyright 2011 Ulrich Sossou (https://github.com/sorich87)
18
19 This program is free software; you can redistribute it and/or modify
20 it under the terms of the GNU General Public License, version 2, as
21 published by the Free Software Foundation.
22
23 This program is distributed in the hope that it will be useful,
24 but WITHOUT ANY WARRANTY; without even the implied warranty of
25 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 GNU General Public License for more details.
27
28 You should have received a copy of the GNU General Public License
29 along with this program; if not, write to the Free Software
30 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
31*/
32
33load_plugin_textdomain( 'import-users-from-csv', false, basename( dirname( __FILE__ ) ) . '/languages' );
34
35if ( ! defined( 'IS_IU_CSV_DELIMITER' ) )
36 define ( 'IS_IU_CSV_DELIMITER', ',' );
37
38/**
39 * Main plugin class
40 *
41 * @since 0.1
42 **/
43class IS_IU_Import_Users {
44 private static $log_dir_path = '';
45 private static $log_dir_url = '';
46
47 /**
48 * The single instance of the class.
49 *
50 * @var IS_IU_Import_Users
51 * @since 20180219.1
52 */
53 protected static $_instance = null;
54
55 /**
56 * Main IS_IU_Import_Users Instance.
57 *
58 * @since 20180219.1
59 * @static
60 * @see is_iu_import_users()
61 * @return IS_IU_Import_Users
62 */
63 public static function instance() {
64 if ( is_null( self::$_instance ) ) {
65 self::$_instance = new self();
66 }
67 return self::$_instance;
68 }
69
70 /**
71 * Initialization
72 *
73 * This function was renamed from "init".
74 *
75 * @since 0.1
76 **/
77 public function __construct() {
78 add_action( 'admin_menu', array( $this, 'add_admin_pages' ) );
79 add_action( 'init', array( $this, 'process_csv' ) );
80
81 $upload_dir = wp_upload_dir();
82 self::$log_dir_path = trailingslashit( $upload_dir['basedir'] );
83 self::$log_dir_url = trailingslashit( $upload_dir['baseurl'] );
84 }
85
86 /**
87 * Add administration menus
88 *
89 * @since 0.1
90 **/
91 public function add_admin_pages() {
92 add_users_page( __( 'Import From CSV' , 'import-users-from-csv'), __( 'Import From CSV' , 'import-users-from-csv'), 'create_users', 'import-users-from-csv', array( $this, 'users_page' ) );
93 }
94
95 /**
96 * Process content of CSV file
97 *
98 * @since 0.1
99 **/
100 public function process_csv() {
101 if ( isset( $_POST['_wpnonce-is-iu-import-users-users-page_import'] ) ) {
102 check_admin_referer( 'is-iu-import-users-users-page_import', '_wpnonce-is-iu-import-users-users-page_import' );
103
104 if ( isset( $_FILES['users_csv']['tmp_name'] ) ) {
105 // Setup settings variables
106 $filename = $_FILES['users_csv']['tmp_name'];
107 $password_nag = isset( $_POST['password_nag'] ) ? $_POST['password_nag'] : false;
108 $users_update = isset( $_POST['users_update'] ) ? $_POST['users_update'] : false;
109 $new_user_notification = isset( $_POST['new_user_notification'] ) ? $_POST['new_user_notification'] : false;
110
111 $results = self::import_csv( $filename, array(
112 'password_nag' => $password_nag,
113 'new_user_notification' => $new_user_notification,
114 'users_update' => $users_update
115 ) );
116
117 // No users imported?
118 if ( ! $results['user_ids'] )
119 wp_redirect( add_query_arg( 'import', 'fail', wp_get_referer() ) );
120
121 // Some users imported?
122 elseif ( $results['errors'] )
123 wp_redirect( add_query_arg( 'import', 'errors', wp_get_referer() ) );
124
125 // All users imported? :D
126 else
127 wp_redirect( add_query_arg( 'import', 'success', wp_get_referer() ) );
128
129 exit;
130 }
131
132 wp_redirect( add_query_arg( 'import', 'file', wp_get_referer() ) );
133 exit;
134 }
135 }
136
137 /**
138 * Content of the settings page
139 *
140 * @since 0.1
141 **/
142 public function users_page() {
143 if ( ! current_user_can( 'create_users' ) )
144 wp_die( __( 'You do not have sufficient permissions to access this page.' , 'import-users-from-csv') );
145?>
146
147<div class="wrap">
148 <h2><?php _e( 'Import users from a CSV file' , 'import-users-from-csv'); ?></h2>
149 <?php
150 $error_log_file = self::$log_dir_path . 'is_iu_errors.log';
151 $error_log_url = self::$log_dir_url . 'is_iu_errors.log';
152
153 if ( ! file_exists( $error_log_file ) ) {
154 if ( ! @fopen( $error_log_file, 'x' ) )
155 echo '<div class="updated"><p><strong>' . sprintf( __( 'Notice: please make the directory %s writable so that you can see the error log.' , 'import-users-from-csv'), self::$log_dir_path ) . '</strong></p></div>';
156 }
157
158 if ( isset( $_GET['import'] ) ) {
159 $error_log_msg = '';
160 if ( file_exists( $error_log_file ) )
161 $error_log_msg = sprintf( __( ', please <a href="%s">check the error log</a>' , 'import-users-from-csv'), $error_log_url );
162
163 switch ( $_GET['import'] ) {
164 case 'file':
165 echo '<div class="error"><p><strong>' . __( 'Error during file upload.' , 'import-users-from-csv') . '</strong></p></div>';
166 break;
167 case 'data':
168 echo '<div class="error"><p><strong>' . __( 'Cannot extract data from uploaded file or no file was uploaded.' , 'import-users-from-csv') . '</strong></p></div>';
169 break;
170 case 'fail':
171 echo '<div class="error"><p><strong>' . sprintf( __( 'No user was successfully imported%s.' , 'import-users-from-csv'), $error_log_msg ) . '</strong></p></div>';
172 break;
173 case 'errors':
174 echo '<div class="error"><p><strong>' . sprintf( __( 'Some users were successfully imported but some were not%s.' , 'import-users-from-csv'), $error_log_msg ) . '</strong></p></div>';
175 break;
176 case 'success':
177 echo '<div class="updated"><p><strong>' . __( 'Users import was successful.' , 'import-users-from-csv') . '</strong></p></div>';
178 break;
179 default:
180 break;
181 }
182 }
183 ?>
184 <form method="post" action="" enctype="multipart/form-data">
185 <?php wp_nonce_field( 'is-iu-import-users-users-page_import', '_wpnonce-is-iu-import-users-users-page_import' ); ?>
186 <table class="form-table">
187 <tr valign="top">
188 <th scope="row"><label for="users_csv"><?php _e( 'CSV file' , 'import-users-from-csv'); ?></label></th>
189 <td>
190 <input type="file" id="users_csv" name="users_csv" value="" class="all-options" /><br />
191 <span class="description"><?php echo sprintf( __( 'You may want to see <a href="%s">the example of the CSV file</a>.' , 'import-users-from-csv'), plugin_dir_url(__FILE__).'examples/import.csv'); ?></span>
192 </td>
193 </tr>
194 <tr valign="top">
195 <th scope="row"><?php _e( 'Notification' , 'import-users-from-csv'); ?></th>
196 <td><fieldset>
197 <legend class="screen-reader-text"><span><?php _e( 'Notification' , 'import-users-from-csv'); ?></span></legend>
198 <label for="new_user_notification">
199 <input id="new_user_notification" name="new_user_notification" type="checkbox" value="1" />
200 <?php _e('Send to new users', 'import-users-from-csv') ?>
201 </label>
202 </fieldset></td>
203 </tr>
204 <tr valign="top">
205 <th scope="row"><?php _e( 'Password nag' , 'import-users-from-csv'); ?></th>
206 <td><fieldset>
207 <legend class="screen-reader-text"><span><?php _e( 'Password nag' , 'import-users-from-csv'); ?></span></legend>
208 <label for="password_nag">
209 <input id="password_nag" name="password_nag" type="checkbox" value="1" />
210 <?php _e('Show password nag on new users signon', 'import-users-from-csv') ?>
211 </label>
212 </fieldset></td>
213 </tr>
214 <tr valign="top">
215 <th scope="row"><?php _e( 'Users update' , 'import-users-from-csv'); ?></th>
216 <td><fieldset>
217 <legend class="screen-reader-text"><span><?php _e( 'Users update' , 'import-users-from-csv' ); ?></span></legend>
218 <label for="users_update">
219 <input id="users_update" name="users_update" type="checkbox" value="1" />
220 <?php _e( 'Update user when a username or email exists', 'import-users-from-csv' ) ;?>
221 </label>
222 </fieldset></td>
223 </tr>
224 </table>
225 <p class="submit">
226 <input type="submit" class="button-primary" value="<?php _e( 'Import' , 'import-users-from-csv'); ?>" />
227 </p>
228 </form>
229<?php
230 }
231
232 /**
233 * Import a csv file
234 *
235 * @since 0.5
236 */
237 public static function import_csv( $filename, $args ) {
238 $errors = $user_ids = array();
239
240 $defaults = array(
241 'password_nag' => false,
242 'new_user_notification' => false,
243 'users_update' => false
244 );
245 extract( wp_parse_args( $args, $defaults ) );
246
247 // User data fields list used to differentiate with user meta
248 $userdata_fields = array(
249 'ID', 'user_login', 'user_pass',
250 'user_email', 'user_url', 'user_nicename',
251 'display_name', 'user_registered', 'first_name',
252 'last_name', 'nickname', 'description',
253 'rich_editing', 'comment_shortcuts', 'admin_color',
254 'use_ssl', 'show_admin_bar_front', 'show_admin_bar_admin',
255 'role'
256 );
257
258 include( plugin_dir_path( __FILE__ ) . 'class-readcsv.php' );
259
260 // Loop through the file lines
261 $file_handle = fopen( $filename, 'r' );
262 $csv_reader = new ReadCSV( $file_handle, IS_IU_CSV_DELIMITER, "\xEF\xBB\xBF" ); // Skip any UTF-8 byte order mark.
263
264 $first = true;
265 $rkey = 0;
266 while ( ( $line = $csv_reader->get_row() ) !== NULL ) {
267
268 // If the first line is empty, abort
269 // If another line is empty, just skip it
270 if ( empty( $line ) ) {
271 if ( $first )
272 break;
273 else
274 continue;
275 }
276
277 // If we are on the first line, the columns are the headers
278 if ( $first ) {
279 $headers = $line;
280 $first = false;
281 continue;
282 }
283
284 // Separate user data from meta
285 $userdata = $usermeta = array();
286 foreach ( $line as $ckey => $column ) {
287 $column_name = $headers[$ckey];
288 $column = trim( $column );
289
290 if ( in_array( $column_name, $userdata_fields ) ) {
291 $userdata[$column_name] = $column;
292 } else {
293 $usermeta[$column_name] = $column;
294 }
295 }
296
297 // A plugin may need to filter the data and meta
298 $userdata = apply_filters( 'is_iu_import_userdata', $userdata, $usermeta );
299 $usermeta = apply_filters( 'is_iu_import_usermeta', $usermeta, $userdata );
300
301 // If no user data, bailout!
302 if ( empty( $userdata ) )
303 continue;
304
305 // Something to be done before importing one user?
306 do_action( 'is_iu_pre_user_import', $userdata, $usermeta );
307
308 $user = $user_id = false;
309
310 if ( isset( $userdata['ID'] ) )
311 $user = get_user_by( 'ID', $userdata['ID'] );
312
313 if ( ! $user && $users_update ) {
314 if ( isset( $userdata['user_login'] ) )
315 $user = get_user_by( 'login', $userdata['user_login'] );
316
317 if ( ! $user && isset( $userdata['user_email'] ) )
318 $user = get_user_by( 'email', $userdata['user_email'] );
319 }
320
321 $update = false;
322 if ( $user ) {
323 $userdata['ID'] = $user->ID;
324 $update = true;
325 }
326
327 // If creating a new user and no password was set, let auto-generate one!
328 if ( ! $update && empty( $userdata['user_pass'] ) )
329 $userdata['user_pass'] = wp_generate_password( 12, false );
330
331 // If a key was not created for a user, lets create one
332 if ( empty( $userdata['user_activation_key'] ) ) {
333
334 // ref: https://developer.wordpress.org/reference/functions/get_password_reset_key/
335 // Generate something random for a password reset key
336 $key = wp_generate_password( 20, false );
337
338 // call the hasher
339 if ( empty( $wp_hasher ) ) {
340 require_once ABSPATH . WPINC . '/class-phpass.php';
341 $wp_hasher = new PasswordHash( 8, true );
342 }
343 $hashed = time() . ':' . $wp_hasher->HashPassword( $key );
344 $userdata['user_activation_key'] = $key;
345 }
346
347 // update existing users
348 if ( $update )
349 $user_id = wp_update_user( $userdata );
350
351 // create new users
352 else
353 $user_id = wp_insert_user( $userdata );
354
355 // Is there an error o_O?
356 if ( is_wp_error( $user_id ) ) {
357 $errors[$rkey] = $user_id;
358 } else {
359 // If no error, let's update the user meta too!
360 if ( $usermeta ) {
361 foreach ( $usermeta as $metakey => $metavalue ) {
362 $metavalue = maybe_unserialize( $metavalue );
363 update_user_meta( $user_id, $metakey, $metavalue );
364 }
365 }
366
367 // If we created a new user, maybe set password nag and send new user notification?
368 if ( ! $update ) {
369 if ( $password_nag )
370 update_user_option( $user_id, 'default_password_nag', true, true );
371
372 if ( $new_user_notification ) {
373 // https://codex.wordpress.org/Function_Reference/wpmu_signup_user_notification
374 $userdata['user_email'] = $user_email;
375 $userdata['user_login'] = $user;
376 wpmu_signup_user_notification ( $user, $user_email, $key );
377
378 //$userdata: wpmu_signup_user_notification( $userdata['user_login'], $userdata['user_email'], $key, array() );
379 }
380 }
381
382 // Some plugins may need to do things after one user has been imported. Who know?
383 do_action( 'is_iu_post_user_import', $user_id );
384
385 $user_ids[] = $user_id;
386 }
387
388 $rkey++;
389 }
390 fclose( $file_handle );
391
392 // One more thing to do after all imports?
393 do_action( 'is_iu_post_users_import', $user_ids, $errors );
394
395 // Let's log the errors
396 self::log_errors( $errors );
397
398 return array(
399 'user_ids' => $user_ids,
400 'errors' => $errors
401 );
402 }
403
404 /**
405 * Log errors to a file
406 *
407 * @since 0.2
408 **/
409 private static function log_errors( $errors ) {
410 if ( empty( $errors ) )
411 return;
412
413 $log = @fopen( self::$log_dir_path . 'is_iu_errors.log', 'a' );
414 @fwrite( $log, sprintf( __( 'BEGIN %s' , 'import-users-from-csv'), date( 'Y-m-d H:i:s', time() ) ) . "\n" );
415
416 foreach ( $errors as $key => $error ) {
417 $line = $key + 1;
418 $message = $error->get_error_message();
419 @fwrite( $log, sprintf( __( '[Line %1$s] %2$s' , 'import-users-from-csv'), $line, $message ) . "\n" );
420 }
421
422 @fclose( $log );
423 }
424}
425
426/**
427 * Main instance of IS_IU_Import_Users.
428 *
429 * @since 20180219.1
430 * @return IS_IU_Import_Users
431 */
432function is_iu_import_users() {
433 return IS_IU_Import_Users::instance();
434}
435
436is_iu_import_users();