Headline
CVE-2022-3342: Changeset 2805282 for zero-bs-crm/trunk/includes/ZeroBSCRM.CSVImporter.php – WordPress Plugin Repository
The Jetpack CRM plugin for WordPress is vulnerable to PHAR deserialization via the ‘zbscrmcsvimpf’ parameter in the ‘zeroBSCRM_CSVImporterLitehtml_app’ function in versions up to, and including, 5.3.1. While the function performs a nonce check, steps 2 and 3 of the check do not take any action upon a failed check. These steps then perform a ‘file_exists’ check on the value of 'zbscrmcsvimpf’. If a phar:// archive is supplied, its contents will be deserialized and an object injected in the execution stream. This allows an unauthenticated attacker to obtain object injection if they are able to upload a phar archive (for instance if the site supports image uploads) and then trick an administrator into performing an action, such as clicking a link.
r2632084 r2805282 9494 9595 global $wpdb, $zbs, $zeroBSCRM_CSVImporterLiteversion; #} Req 96 96 9797 if (!current_user_can(‘admin_zerobs_customers’)) { wp_die( __('You do not have sufficient permissions to access this page.’,"zero-bs-crm") ); } 98 99 98 10099?> 101100 … … 208207} 209208 209// catch errors with nonce or other oddities 210function jpcrm_csvimporter_lite_preflight_checks( $stage ) { 211 212 if ( ! isset( $_POST[‘zbscrmcsvimportnonce’] ) || ! wp_verify_nonce( $_POST[‘zbscrmcsvimportnonce’], ‘zbscrm_csv_import’ ) ) { 213 // hard no 214 zeroBSCRM_html_msg( -1, __( 'There was an error processing your CSV file. Please try again.’, ‘zero-bs-crm’ ) ); 215 exit(); 216 } 217 218 // eventually update this to use the zbscrm-store/_wip replacement 219 // apparently sys_get_temp_dir() isn’t consistent on whether it has a trailing slash 220 $tmp_dir = untrailingslashit( sys_get_temp_dir() ); 221 $tmp_dir = realpath( $tmp_dir ) . '/’; 222 223 $field_map = array(); 224 225 if ( $stage == 1 ) { 226 227 if ( empty( $_FILES[‘zbscrmcsvfile’] ) || empty( $_FILES[‘zbscrmcsvfile’][‘name’] ) ) { 228 throw new Exception( __( 'No CSV file was provided. Please choose the CSV file you want to upload.’, ‘zero-bs-crm’ ) ); 229 } 230 231 $csv_file_data = $_FILES[‘zbscrmcsvfile’]; 232 233 // error uploading 234 if ( $csv_file_data[‘error’] !== UPLOAD_ERR_OK ) { 235 throw new Exception( __( 'There was an error processing your CSV file. Please try again.’, ‘zero-bs-crm’ ) ); 236 } 237 238 // basic MIME/extension check 239 if ( 240 ( $csv_file_data[‘type’] !== ‘text/csv’ && $csv_file_data[‘type’] !== ‘text/plain’ ) 241 || pathinfo( $csv_file_data[‘name’], PATHINFO_EXTENSION ) !== ‘csv’ 242 ) { 243 throw new Exception( __( 'Your file is not a correctly-formatted CSV file. Please check your file format. If you continue to have issues please contact support.’, ‘zero-bs-crm’ ) ); 244 } 245 246 /* 247 The main goal below is to have a file that can be read in future steps, but also that is unreadable to the public. 248 249 Things to be aware of: 250 - If we don’t move/rename the file, PHP automatically deletes it at the end of the process. 251 - The hash/encryption is overkill at the moment but exists in case the destination folder is publicly available (see 2435-gh). 252 - For now, we just rename the file and leave it in the system tmp folder, but eventually we can move it to the zbscrm-store replacement. 253 */ 254 255 $public_name = basename( $csv_file_data[‘tmp_name’] ); 256 257 $hashed_filename = jpcrm_get_hashed_filename( $public_name, ‘.csv’ ); 258 $file_path = $tmp_dir . $hashed_filename; 259 260 // try to move file to destination for future processing 261 if ( !move_uploaded_file( $csv_file_data[‘tmp_name’], $file_path ) ) { 262 throw new Exception( __( 'Unable to upload CSV file.’, ‘zero-bs-crm’ ) ); 263 } 264 265 } 266 267 // Check stage 2 and 3 268 if ( $stage === 2 || $stage === 3 ) { 269 270 // (carefully) check for file presence 271 $public_name = ( isset( $_POST[‘zbscrmcsvimpf’] ) ? sanitize_file_name( $_POST[‘zbscrmcsvimpf’] ) : ‘’ ); 272 273 if ( empty( $public_name ) ) { 274 throw new Exception( __( 'There was an error processing your CSV file. Please try again.’, ‘zero-bs-crm’ ) ); 275 } 276 277 $hashed_filename = jpcrm_get_hashed_filename( $public_name, ‘.csv’ ); 278 $file_path = $tmp_dir . $hashed_filename; 279 280 // Retrieve fields 281 $field_map = array(); 282 $mapped_field_count = 0; 283 for ( $fieldI = 1; $fieldI <= 30; $fieldI++ ) { 284 285 // Default to ignore 286 $map_to = 'ignorezbs’; 287 288 // Map :) 289 if ( !empty( $_POST['zbscrm-csv-fieldmap-'.$fieldI] ) && $_POST['zbscrm-csv-fieldmap-'.$fieldI] !== -1 ) { 290 291 $map_to = sanitize_text_field( $_POST['zbscrm-csv-fieldmap-'.$fieldI] ); 292 293 // Count actual mapped fields 294 if ( $map_to != ‘ignorezbs’ ) { 295 $mapped_field_count++; 296 } 297 298 // Pass it. 299 $field_map[$fieldI] = $map_to; 300 301 } 302 303 } 304 305 // no fields were mapped 306 if ( $mapped_field_count === 0 ) { 307 // delete the file 308 unlink( $file_path ); 309 throw new Exception( __( 'No fields were mapped. You cannot import customers without at least one field mapped to a customer attribute.’, ‘zero-bs-crm’ ) ); 310 } 311 312 } 313 314 // Now that we only pass the filename via POST, and we encrypt+hash it, the following few lines are probably 315 // no longer needed, but leaving for now 316 $file_path = realpath( $file_path ); 317 // This ensures that the provided file exists and is inside the upload folder or one of its subdirs (ie `/wp-content/uploads/*`) 318 // and not somewhere else, also prevent traversal attacks, and usage of wrappers like phar:// etc 319 if ( $file_path === false || strpos( $file_path, $tmp_dir ) !== 0) { 320 //Traversal attempt, file does not exist, invalid wrapper 321 throw new Exception( __( 'There was an error processing your CSV file. Please try again.’, ‘zero-bs-crm’ ) ); 322 } 323 324 // Get CSV data 325 $csv_data = file_get_contents( $file_path ); 326 327 // no lines or empty first line 328 if ( empty( $csv_data ) ) { 329 // delete the file 330 unlink( $file_path ); 331 throw new Exception( __( 'We did not find any usable lines in the provided file. If you are having continued problems please contact support.’, ‘zero-bs-crm’ ) ); 332 } 333 334 $csv_data = strip_tags( $csv_data ); 335 $csv_data = preg_split(“/\\r\\n|\\r|\\n/", $csv_data); 336 337 // Count lines 338 $num_lines = count( $csv_data ); 339 $ignore_first_line = isset( $_POST[‘zbscrmcsvimpignorefirst’] ); 340 if ($ignore_first_line) $num_lines–; 341 342 $file_details = array( 343 ‘public_name’ => $public_name, 344 ‘filename’ => $hashed_filename, 345 ‘file_path’ => $file_path, 346 ‘csv_data’ => $csv_data, 347 ‘num_lines’ => $num_lines, 348 ‘ignore_first_line’ => $ignore_first_line, 349 ‘field_map’ => $field_map, 350 ); 351 352 return $file_details; 353} 354 210355 211356#} HTML for main app … … 224369 #} - Complete (button) 225370 #} - Process 226 $stage = 0; if (isset($_POST[‘zbscrmcsvimpstage’]) && !empty($_POST[‘zbscrmcsvimpstage’]) && in_array($_POST[‘zbscrmcsvimpstage’],array(1,2,3))){ $stage = (int)sanitize_text_field($_POST[‘zbscrmcsvimpstage’]); } 227 $nonceOkay = true; 228 229 #} Validation (pre stage load) 230 231 #} Check nonce 232 if (! isset( $_POST[‘zbscrmcsvimportnonce’] ) || ! wp_verify_nonce( $_POST[‘zbscrmcsvimportnonce’], ‘zbscrm_csv_import’ )) { 233 $nonceOkay = false; 234 } 235 236 #} Catch file or nonce errors (back to beginning) 237 if ($stage == 1){ 238 239 #} Nonce? 240 if (!$nonceOkay) { 241 242 #} Send back to start 243 $stage = 0; 244 $stageError = __( 'There was an error uploading your CSV file. Please try again.’, ‘zero-bs-crm’ ); 245 } 246 247 #} File uploads 248 #} https://codex.wordpress.org/Function_Reference/wp_handle_upload 249 if ( ! function_exists( ‘wp_handle_upload’ ) ) { 250 require_once( ABSPATH . ‘wp-admin/includes/file.php’ ); 251 } 252 253 $uploadedfile = $_FILES[‘zbscrmcsvfile’]; 254 255 $upload_overrides = array( ‘test_form’ => false ); 256 257 $movefile = wp_handle_upload( $uploadedfile, $upload_overrides ); # 258 259 if ( $movefile && ! isset( $movefile[‘error’] ) ) { 260 #echo “File is valid, and was successfully uploaded.\n"; 261 #var_dump( $movefile ); 262 263 #} All good. Set var 264 $fileDetails = $movefile; 265 266 #} Check valid filetype: 267 268 #} Extension 269 $fileName = basename($fileDetails[‘file’]); 270 $fileURL = $fileDetails[‘url’]; #} Just passed through for later use 271 $extension = pathinfo($fileName, PATHINFO_EXTENSION); 272 if (strtolower($extension) != “csv”){ 273 274 #} Del file 275 unlink( $fileDetails[‘file’] ); 276 277 #} Send back to start 278 $stage = 0; 279 $stageError = __( 'Your file is not a “.csv” file. If you are having continued problems please email support with a copy of your CSV file attached.’, ‘zero-bs-crm’ ); 280 281 } 282 283 #} MIME 284 if ($fileDetails[‘type’] != “text/csv” && $fileDetails[‘type’] != “text/plain”) { 285 286 #} Del file 287 unlink( $fileDetails[‘file’] ); 288 289 #} Send back to start 290 $stage = 0; 291 $stageError = __( 'Your file is not a correctly formatted CSV, please check your file format. If you are having continued problems please email support with a copy of your CSV file attached.’, ‘zero-bs-crm’ ); 292 293 } 294 295 // Check format 296 $fullCSV = file_get_contents($fileDetails[‘file’]); 297 $fullCSV = strip_tags($fullCSV); 298 299 #$csvLines = explode(“\n",$fullCSV) 300 $csvLines = preg_split(“/\\r\\n|\\r|\\n/", $fullCSV); 301 if (count($csvLines) <= 0){ 302 303 #} Send back to start 304 $stage = 0; 305 $stageError = __( 'Your file does not appear to be a correctly formatted CSV File. We did not find any usable lines to import. If you are having continued problems please email support with a copy of your CSV file attached.’, ‘zero-bs-crm’ ); 306 307 } 308 309 310 } else { 311 /** 312 * Error generated by _wp_handle_upload() 313 * @see _wp_handle_upload() in wp-admin/includes/file.php 314 */ 315 #echo $movefile[‘error’]; 316 317 #} Send back to start 318 $stage = 0; 319 $stageError = $movefile[‘error’]; 320 } 321 371 $stage = 0; 372 if ( !empty( $_POST[‘zbscrmcsvimpstage’] ) ) { 373 $stage = (int)$_POST[‘zbscrmcsvimpstage’]; 374 } 375 376 if ( in_array( $stage, array( 1, 2, 3 ) ) ) { 377 try { 378 // check nonce and other things 379 $file_details = jpcrm_csvimporter_lite_preflight_checks( $stage ); 380 } catch (Exception $e) { 381 // send back to beginning and show error 382 $stage = 0; 383 $stageError = $e->getMessage(); 322384 } 323 324 #} Check stage 2 325 if ($stage == 2){ 326 327 #} Grab zbscrmcsvimpignorefirst 328 $ignoreFirstLine = false; if (isset($_POST[‘zbscrmcsvimpignorefirst’])) $ignoreFirstLine = true; 329 330 #} No record of file 331 if (!isset($_POST[‘zbscrmcsvimpf’]) || !file_exists($_POST[‘zbscrmcsvimpf’])){ 332 333 #} Send back to start 334 $stage = 0; 335 $stageError = __( 'There was an error maintaining a link to your uploaded CSV file. Please contact support if this error persists, quoting error code #457’, ‘zero-bs-crm’ ); #} lol. 336 337 } else { 338 339 #} set csv file var 340 $csvFileLoca = sanitize_text_field($_POST[‘zbscrmcsvimpf’]); 341 $csvFileURL = sanitize_text_field($_POST[‘zbscrmcsvimpfurl’]); 342 343 #} Get line count 344 $fullCSV = file_get_contents($csvFileLoca); 345 #$csvLines = explode(“\n",$fullCSV) 346 $csvLines = preg_split(“/\\r\\n|\\r|\\n/", $fullCSV); 347 348 #} Count total 349 $totalCSVLines = count($csvLines); 350 if ($ignoreFirstLine) $totalCSVLines–; 351 352 } 353 354 #} Retrieve fields 355 $fieldMap = array(); $realFields = 0; 356 for ($fieldI = 1; $fieldI <= 30; $fieldI++){ 357 358 #} Default to ignore 359 $mapTo = 'ignorezbs’; 360 361 #} Map :) 362 if (isset($_POST['zbscrm-csv-fieldmap-'.$fieldI]) && !empty($_POST['zbscrm-csv-fieldmap-'.$fieldI]) && $_POST['zbscrm-csv-fieldmap-'.$fieldI] !== -1){ 363 364 $mapTo = sanitize_text_field($_POST['zbscrm-csv-fieldmap-'.$fieldI]); 365 366 #} Count actual mapped fields 367 if ($mapTo != ‘ignorezbs’) $realFields++; 368 369 #} Pass it. 370 $fieldMap[$fieldI] = $mapTo; 371 372 } 373 374 } 375 376 if ($realFields == 0) $stageError = __( 'No fields were matched. You cannot import customers without at least one field mapped to a customer attribute.’, ‘zero-bs-crm’ ); 377 378 379 } 380 381 #} Check stage 3 382 if ($stage == 3){ 383 384 #} Grab zbscrmcsvimpignorefirst 385 $ignoreFirstLine = false; if (isset($_POST[‘zbscrmcsvimpignorefirst’])) $ignoreFirstLine = true; 386 387 #} No record of file 388 if (!isset($_POST[‘zbscrmcsvimpf’]) || !file_exists($_POST[‘zbscrmcsvimpf’])){ 389 390 #} Send back to start 391 $stage = 0; 392 $stageError = __( 'There was an error maintaining a link to your uploaded CSV file. Please contact support if this error persists, quoting error code #457’, ‘zero-bs-crm’ ); #} lol. 393 394 } else { 395 396 #} set csv file var 397 $csvFileLoca = sanitize_text_field($_POST[‘zbscrmcsvimpf’]); 398 $csvFileURL = sanitize_text_field($_POST[‘zbscrmcsvimpfurl’]); 399 $csvFileName = basename($csvFileLoca); 400 401 #} Get line count 402 $fullCSV = file_get_contents($csvFileLoca); 403 #$csvLines = explode(“\n",$fullCSV) 404 $csvLines = preg_split(“/\\r\\n|\\r|\\n/", $fullCSV); 405 406 } 407 408 #} Retrieve fields 409 $fieldMap = array(); $realFields = 0; 410 for ($fieldI = 0; $fieldI <= 30; $fieldI++){ 411 412 #} Default to ignore 413 $mapTo = 'ignorezbs’; 414 415 #} Map :) 416 if (isset($_POST['zbscrm-csv-fieldmap-'.$fieldI]) && !empty($_POST['zbscrm-csv-fieldmap-'.$fieldI]) && $_POST['zbscrm-csv-fieldmap-'.$fieldI] !== -1){ 417 418 #} NO validation?! #validationtodo 419 $mapTo = sanitize_text_field($_POST['zbscrm-csv-fieldmap-'.$fieldI]); 420 421 #} Count actual mapped fields 422 if ($mapTo != ‘ignorezbs’) $realFields++; 423 424 #} Pass it. 425 $fieldMap[$fieldI] = $mapTo; 426 427 } 428 429 } 430 431 if ($realFields == 0) { 432 433 #} Back 434 $stage = 0; 435 $stageError = __( 'No fields were matched. You cannot import customers without at least one field mapped to a customer attribute.’, ‘zero-bs-crm’ ); 436 437 } 438 439 440 } 441 442 385 } 443386 444387 switch ($stage){ … … 456399 <form method="post” class="zbscrm-csv-map-form"> 457400 <input type="hidden” id="zbscrmcsvimpstage” name="zbscrmcsvimpstage” value="2” /> 458 <input type="hidden” id="zbscrmcsvimpf” name="zbscrmcsvimpf” value="<?php echo $fileDetails[‘file’]; ?>" /> 459 <input type="hidden" id="zbscrmcsvimpfurl" name="zbscrmcsvimpfurl" value="<?php echo $fileDetails[‘url’]; ?>" /> 401 <input type="hidden" id="zbscrmcsvimpf" name="zbscrmcsvimpf" value="<?php echo esc_attr( $file_details[‘public_name’] ); ?>" /> 460402 <?php wp_nonce_field( 'zbscrm_csv_import’, ‘zbscrmcsvimportnonce’ ); ?> 461403 … … 463405 <div class="zbscrm-csv-map-ignorefirst"> 464406 <input type="checkbox" id="zbscrmcsvimpignorefirst" name="zbscrmcsvimpignorefirst" value="1" /> 465 <label><?php _e('Ignore first line of CSV file when running import.<br />(Use this if you have a “header line” in your CSV file.)‘,’zero-bs-crm’); ?></label> 407 <label for="zbscrmcsvimpignorefirst" ><?php _e('Ignore first line of CSV file when running import.<br />(Use this if you have a “header line” in your CSV file.)‘,’zero-bs-crm’); ?></label> 466408 </div> 467409 <hr /> … … 471413 #} Cycle through each field and display a mapping option 472414 #} Using first line of import 473 $firstLine = $csvLines[0]; 415 $firstLine = $file_details[‘csv_data’][0]; 474416 $firstLineParts = explode(“,",$firstLine); 475417 … … 534476 case 2: 535477 536 #} Title 478 // Title 537479 zeroBSCRM_CSVImporterLitepages_header(‘3. Run Import’); 538480 539 #} Stolen from plugin-install.php?tab=upload 481 // Stolen from plugin-install.php?tab=upload 540482 ?><div class="zbscrm-csvimport-wrap"> 541483 <h2>Complete Customer Import</h2> … … 546488 <form method="post” enctype="multipart/form-data" class="zbscrm-csv-import-form"> 547489 <input type="hidden" id="zbscrmcsvimpstage" name="zbscrmcsvimpstage" value="3" /> 548 <input type="hidden" id="zbscrmcsvimpf" name="zbscrmcsvimpf" value="<?php echo $csvFileLoca; ?>" /> 549 <input type="hidden" id="zbscrmcsvimpfurl" name="zbscrmcsvimpfurl" value="<?php echo $csvFileURL; ?>" /> 550 <?php wp_nonce_field( ‘zbscrm_csv_import’, ‘zbscrmcsvimportnonce’ ); ?> 551 <h3>Import <?php echo zeroBSCRM_prettifyLongInts($totalCSVLines); ?> Customers</h3> 552 <hr /> 553 <?php if ($ignoreFirstLine){ ?> 554 <p style="font-size:16px;text-align:center;">Ignore first line of CSV <i class="fa fa-check"></i></p> 555 <hr /> 556 <input type="hidden" id="zbscrmcsvimpignorefirst" name="zbscrmcsvimpignorefirst" value="1" /> 557 <?php } ?> 558 <?php if ($realFields > 0){ ?> 559 <p style="font-size:16px;text-align:center;">Map the following fields:</p> 560 <?php 561 562 #} Cycle through each field 563 #} Using first line of import 564 $firstLine = $csvLines[0]; 565 $firstLineParts = explode(",",$firstLine); 566 567 foreach ($fieldMap as $fieldID => $fieldTarget){ 568 569 $fieldTargetName = $fieldTarget; if (isset($zbsCustomerFields[$fieldTarget]) && isset($zbsCustomerFields[$fieldTarget][1]) && !empty($zbsCustomerFields[$fieldTarget][1])) $fieldTargetName = __($zbsCustomerFields[$fieldTarget][1],’zero-bs-crm’); 570 571 if (in_array($fieldTarget, array('secaddr1’, 'secaddr2’, 'seccity’, 'seccounty’, 'seccountry’, ‘secpostcode’))) $fieldTargetName .= ' (‘.__(‘2nd Address’,’zero-bs-crm’).’)'; 572 573 $fromStr = '’; 574 if (isset($firstLineParts[$fieldID-1])) $fromStr = $firstLineParts[$fieldID-1]; 575 576 #} Clean user field - “” 577 if (substr($fromStr,0,1) == ‘"’ && substr($fromStr,-1) == ‘"’){ 578 $fromStr = substr($fromStr,1,strlen($fromStr)-2); 579 } 580 #} Clean user field - ‘’ 581 if (substr($fromStr,0,1) == “’” && substr($fromStr,-1) == “’”){ 582 $fromStr = substr($fromStr,1,strlen($fromStr)-2); 583 } 584 585 586 587 ?> 588 <input type="hidden" id="zbscrm-csv-fieldmap-<?php echo ($fieldID-1); ?>" name="zbscrm-csv-fieldmap-<?php echo ($fieldID-1); ?>" value="<?php echo $fieldTarget; ?>" /> 589 <div class="zbscrm-impcsv-map"> 590 <div class="zbscrm-impcsv-from"><?php if (!empty($fromStr)) echo '"’.$fromStr.’"’; else echo sprintf( __( 'Field #%s’, ‘zero-bs-crm’ ), $fieldID ); ?></div> 591 <div class="zbscrm-impcsv-arrow"><?php if ($fieldTarget != “ignorezbs”) echo '<i class="fa fa-long-arrow-right"></i>’; else echo '-'; ?></div> 592 <div class="zbscrm-impcsv-to"><?php if ($fieldTarget != “ignorezbs”) echo '"’.$fieldTargetName.’"’; else _e( 'Ignore’, ‘zero-bs-crm’ ); ?></div> 593 </div><?php 594 595 } 596 597 ?> 598 <hr /> 490 <input type="hidden" id="zbscrmcsvimpf" name="zbscrmcsvimpf" value="<?php echo esc_attr( $file_details[‘public_name’] ); ?>" /> 491 <?php wp_nonce_field( ‘zbscrm_csv_import’, ‘zbscrmcsvimportnonce’ ); ?> 492 <h3>Import <?php echo zeroBSCRM_prettifyLongInts( $file_details[‘num_lines’] ); ?> Customers</h3> 493 <hr /> 494 <?php if ( $file_details[‘ignore_first_line’] ){ ?> 495 <p style="font-size:16px;text-align:center;">Ignore first line of CSV <i class="fa fa-check"></i></p> 496 <hr /> 497 <input type="hidden" id="zbscrmcsvimpignorefirst" name="zbscrmcsvimpignorefirst" value="1" /> 498 <?php } ?> 499 <p style="font-size:16px;text-align:center;">Map the following fields:</p> 500 <?php 501 502 // Cycle through each field 503 // Using first line of import 504 $firstLine = $file_details[‘csv_data’][0]; 505 $firstLineParts = explode(",",$firstLine); 506 507 foreach ( $file_details[‘field_map’] as $fieldID => $fieldTarget ) { 508 509 $fieldTargetName = $fieldTarget; if (isset($zbsCustomerFields[$fieldTarget]) && isset($zbsCustomerFields[$fieldTarget][1]) && !empty($zbsCustomerFields[$fieldTarget][1])) $fieldTargetName = __($zbsCustomerFields[$fieldTarget][1],’zero-bs-crm’); 510 511 if (in_array($fieldTarget, array('secaddr1’, 'secaddr2’, 'seccity’, 'seccounty’, 'seccountry’, ‘secpostcode’))) $fieldTargetName .= ' (‘.__(‘2nd Address’,’zero-bs-crm’).’)'; 512 513 $fromStr = '’; 514 if (isset($firstLineParts[$fieldID-1])) $fromStr = $firstLineParts[$fieldID-1]; 515 516 // Clean user field - “” 517 if (substr($fromStr,0,1) == ‘"’ && substr($fromStr,-1) == ‘"’){ 518 $fromStr = substr($fromStr,1,strlen($fromStr)-2); 519 } 520 // Clean user field - ‘’ 521 if (substr($fromStr,0,1) == “’” && substr($fromStr,-1) == “’”){ 522 $fromStr = substr($fromStr,1,strlen($fromStr)-2); 523 } 524 525 ?> 526 <input type="hidden" id="zbscrm-csv-fieldmap-<?php echo ($fieldID-1); ?>" name="zbscrm-csv-fieldmap-<?php echo ($fieldID-1); ?>" value="<?php echo esc_attr( $fieldTarget ); ?>" /> 527 <div class="zbscrm-impcsv-map"> 528 <div class="zbscrm-impcsv-from"><?php if (!empty($fromStr)) echo '"’.$fromStr.’"’; else echo sprintf( __( 'Field #%s’, ‘zero-bs-crm’ ), $fieldID ); ?></div> 529 <div class="zbscrm-impcsv-arrow"><?php if ($fieldTarget != “ignorezbs”) echo '<i class="fa fa-long-arrow-right"></i>’; else echo '-'; ?></div> 530 <div class="zbscrm-impcsv-to"><?php if ($fieldTarget != “ignorezbs”) echo '"’.$fieldTargetName.’"’; else _e( 'Ignore’, ‘zero-bs-crm’ ); ?></div> 531 </div> 532 <?php 533 534 } 535 536 ?> 537 <hr /> 599538 <div style="text-align:center"> 600539 <button type="submit" name="csv-map-submit" id="csv-map-submit" class="button button-primary button-large" type="submit"><?php _e( 'Run Import’, ‘zero-bs-crm’ ); ?></button> 601540 </div> 602 <?php } else { 603 #} No fields? wtf? 604 ?><button type="button" class="button button-primary button-large" onclick="javascript:window.location=’?page=<?php echo $zbs->slugs[‘csvlite’]; ?>’;"><?php _e('Back’,"zero-bs-crm"); ?></button><?php 605 } ?> 606541 </form> 607542 </div> 608 </div><?php 543 </div> 544 <?php 609545 610546 break; 547 611548 case 3: 612549 … … 620557 <div class="zbscrm-final-stage"> 621558 <div class="zbscrm-import-log"> 622 <div class="zbscrm-import-log-line"><?php _e(“Loading CSV File: “,"zero-bs-crm”); ?> <?php echo $csvFileName; ?> … <i class="fa fa-check"></i></div> 623 <div class="zbscrm-import-log-line"><?php _e(“Parsing rows…","zero-bs-crm”);?> <i class="fa fa-check"></i></div> 624 <div class="zbscrm-import-log-line"><?php echo sprintf( __(“Beginning Import of %s rows…","zero-bs-crm”), zeroBSCRM_prettifyLongInts( count( $csvLines ) ) );?></div> 559 <div class="zbscrm-import-log-line"><?php _e( 'Loading CSV File…’, ‘zero-bs-crm’ ); ?> <i class="fa fa-check"></i></div> 560 <div class="zbscrm-import-log-line"><?php _e( 'Parsing rows…’, ‘zero-bs-crm’ );?> <i class="fa fa-check"></i></div> 561 <div class="zbscrm-import-log-line"><?php echo sprintf( __( 'Beginning Import of %s rows…’, ‘zero-bs-crm’ ), zeroBSCRM_prettifyLongInts( $file_details[‘num_lines’] ) );?></div> 625562 <?php 626563 627564 #} Cycle through 628565 $lineIndx = 0; $linesAdded = 0; $existingOverwrites = array(); $brStrs = array(‘<br>’,’<BR>’,’<br />’,’<BR />’,’<br/>’,’<BR/>’); 629 if (count($csvLines) > 0) foreach ($csvLines as $line){ 566 foreach ( $file_details[‘csv_data’] as $line ) { 630567 631568 #} Check line 632 if ($lineIndx == 0 && $ignoreFirstLine){ 569 if ( $lineIndx === 0 && $file_details[‘ignore_first_line’] ){ 633570 634571 echo ‘<div class="zbscrm-import-log-line">’ . __( 'Skipping header row…’, ‘zero-bs-crm’ ) . '<i class="fa fa-check"></i></div>’; … … 644581 #} Catch first if there 645582 646 foreach ($fieldMap as $fieldID => $fieldTarget){ 583 foreach ( $file_details[‘field_map’] as $fieldID => $fieldTarget ) { 647584 648585 #} id … … 691628 692629 #} Try and find a unique id for this user 693 $userUniqueID = md5($line.’#’.$csvFileName); 630 $userUniqueID = md5($line.’#’.$file_details[‘public_name’]); 694631 695632 #} 1st use email if there … … 727664 728665 #} Line 729 echo '<div class="zbscrm-import-log-line">’.esc_html( 666 echo '<div class="zbscrm-import-log-line">’. 730667 sprintf( 731668 __( 'Successfully added contact #<a href="%s” target="_blank">%d</a>… <i class="fa fa-user"></i><span>+1</span>’, ‘zero-bs-crm’ ), … … 733670 $newCustID 734671 ) 735 ).’</div>’; 672 .’</div>’; 736673 737674 } else { … … 771708 } 772709 773 774 775 #} Delete file if flagged 776 if (!$saveCopyOfCSVFile){ 777 778 if (file_exists($csvFileLoca)) unlink($csvFileLoca); 779 echo ‘<div class="zbscrm-import-log-line">’ . __( 'CSV Upload File Deleted…’, ‘zero-bs-crm’ ) . ‘<i class="fa fa-check"></i></div>’; 780 781 } else { 782 /* not in lite 783 #} Leave in place. 784 #} In fact add to log :) 785 if (isset($settings[‘csvimportlog’]) && is_array($settings[‘csvimportlog’])){ 786 $existingLog = $settings[‘csvimportlog’]; 787 } else { 788 $existingLog = array(); 789 } 790 array_unshift($existingLog,array($csvFileLoca,$csvFileURL,$linesAdded.’ lines imported '.date(‘F jS Y’,time()).’ at '.date('g:i a’,time()))); 791 $zeroBSCRM_CSVImporterSettings->update('csvimportlog’,$existingLog); 792 793 echo '<div class="zbscrm-import-log-line">Skipping deletion of CSV File (as per settings)… <i class="fa fa-check"></i></div>’; 794 echo '<div class="zbscrm-import-log-line">Added CSV Import to log… <i class="fa fa-check"></i></div>’; 795 */ 796 710 if ( $file_details[‘file_path’] ) { 711 unlink($file_details[‘file_path’]); 797712 } 713 echo ‘<div class="zbscrm-import-log-line">’ . __( 'CSV Upload File Deleted…’, ‘zero-bs-crm’ ) . '<i class="fa fa-check"></i></div>’; 798714 799715 ?>