PATH:
var
/
www
/
clients
/
client1
/
web1
/
web
/
wp-content
/
plugins
/
corona-test-results-premium
/
premium
<?php /** * Copyright 2021 48DESIGN GmbH * All rights reserved. Redistribution of these files without prior consent is prohibited. */ /** * save encrypted personal data to a code */ function corona_test_results_update_code_data( $code, $data, $pin, $meta = array() ) { $returnData = array(); if ( ! corona_test_results_check_crypto_activated() || !preg_match( corona_test_results_get_code_regex(), $code ) ) { return false; } global $wpdb; $use_location = 1; $use_location = corona_test_results_get_current_location(); if ( isset( $_POST['location'] ) && is_numeric( $_POST['location'] ) ) { $accept_different_location = apply_filters( 'corona_test_results_filter_is_master_location', false, $use_location ); if ( $accept_different_location ) { $locations = corona_test_results_locations_get(); if ( isset( $locations[ (int)$_POST[ 'location' ] ] ) ) { $use_location = (int)$_POST[ 'location' ]; } } } $tableName = corona_test_results_get_table_name( '', $use_location ); require_once( corona_test_results_plugin_dir_path() . 'lib/DataEncryption.class.php' ); $E = new DataEncryption(); $values = array(); $hasData = is_array( $data ); if ( $hasData ) { if ( apply_filters( 'corona_test_results_pins_bday', false ) && isset( $_POST['bday'] ) ) { if ( preg_match( '/^\d{4}-\d{2}-\d{2}$/', $_POST['bday'] ) ) { $pin = date( apply_filters( 'corona_test_results_pins_bday', false ), strtotime( $_POST['bday'] ) ); } else if ( ! preg_match( '/^\d+$/', $pin ) ) { $pin = DataEncryption::getRandomPIN(); } $returnData['test_result_pin'] = $pin; } $values[] = $E->encrypt( json_encode( wp_unslash( $data ) ), $pin ); } $metaUpdate = ''; if ( isset( $meta['created_at'] ) ) { $utcDateTime = get_gmt_from_date( $meta['created_at'] ); if ( $utcDateTime ) { $metaUpdate .= ', `created_at` = %s'; $values[] = get_gmt_from_date( $meta['created_at'] ); } } if ( isset( $meta['code_update'] ) ) { if ( preg_match( corona_test_results_get_code_regex(), $meta['code_update'] ) ) { $metaUpdate .= ', `code` = %s'; $values[] = $meta['code_update']; } else { $returnData['error'] = __( 'The code that you entered has an invalid format.', 'corona-test-results' ); return $returnData; } } if ( defined( 'CTR_DATA_IMPORT' ) ) { if ( isset( $meta['status'] ) && isset( corona_test_results_get_states()[$meta['status']] ) ) { $metaUpdate .= ', `status` = %d'; $values[] = $meta['status']; } if ( isset( $meta['status_changed'] ) ) { $utcDateTime = get_gmt_from_date( $meta['status_changed'] ); if ( $utcDateTime ) { $metaUpdate .= ', `status_changed` = %s'; $values[] = $utcDateTime; } } if ( isset( $meta['trash'] ) && isset( corona_test_results_get_states()[$meta['trash']] ) ) { $metaUpdate .= ', `trash` = %d'; $values[] = !!$meta['trash'] ? 1 : 0; } } $values[] = $code; // auto status change when not updating from modal if ( ! isset( $meta['is_update'] ) || ! $meta['is_update'] ) { $update_status = apply_filters( 'corona_test_results_update_code_data_status', null ); if ( $update_status !== null ) { $update_status = (int)$update_status; $metaUpdate .= sprintf( ', `status` = %d' , $update_status ); } } $wpdb->suppress_errors = true; $queryResult = $wpdb->query( $hasData ? $wpdb->prepare( "UPDATE `$tableName` SET `data` = %s $metaUpdate WHERE `code` = %s", $values ) : $wpdb->prepare( "UPDATE `$tableName` SET `data` = NULL $metaUpdate WHERE `code` = %s", $values ) ); if ( $queryResult === false || $queryResult === 0 ) { if ( !!$wpdb->last_error && strpos( $wpdb->last_error, 'Duplicate entry' ) === 0 ) { $returnData['error'] = __( 'The code that you entered already exists.', 'corona-test-results' ); } else { $returnData['error'] = __( 'The code data could not be updated.', 'corona-test-results' ); } return $returnData; } if ( corona_test_results_check_datatransfer_integration_enabled( 'cwa' ) ) { corona_test_results_conditionally_create_table(); $dt_tableName = corona_test_results_get_table_name('datatransfer'); if ( isset( $meta['datatransfer'] ) && isset( $meta['datatransfer']['cwa'] ) ) { require_once( corona_test_results_plugin_dir_path() . 'vendor/autoload.php' ); $timestamp = (new DateTimeImmutable('now'))->getTimestamp(); try { $salt = FortyeightDesign\CWAQuicktest::getSalt(); } catch ( \Exception $e ) { wp_send_json_error( "[CWAQuicktest::getSalt] " . $e->getMessage(), 500 ); } $dataFields = array( 'salt' => $salt, 'timestamp' => $timestamp ); if ( $meta['datatransfer']['cwa']['type'] === 'personal' ) { $personalDataFields = array( 'fn' => $data['firstname'], 'ln' => $data['surname'], 'dob' => $data['dateofbirth'], 'testid' => $code . '#' . $timestamp, ); $dataFields = array_merge( $dataFields, $personalDataFields ); } try { $cwaTestData = new FortyeightDesign\CWAQuicktestData( $dataFields ); } catch ( \Exception $e ) { wp_send_json_error( "[CWAQuicktestData] " . $e->getMessage(), 500 ); } $integration_data = array( 'hash' => $cwaTestData->getHash() ); $all_integration_data = array_merge( $dataFields, $integration_data ); if ( defined( 'CTR_CWA_SAVE_ALL' ) && !! constant( 'CTR_CWA_SAVE_ALL' ) ) { $integration_data_json = json_encode( $all_integration_data ); } else { $integration_data_json = json_encode( $integration_data ); } $wpdb->query( $wpdb->prepare( "INSERT INTO `$dt_tableName` (`code`,`integration`,`data`) VALUES (%s, 'cwa', %s) ON DUPLICATE KEY UPDATE `data` = %s, `transferred` = 0", array( $code, $integration_data_json, $integration_data_json ) ) ); $integrationInstance = corona_test_results_check_datatransfer_integration_getinstance( 'cwa' ); if ( $integrationInstance instanceof \Exception ) { $errorMessage = "[datatransfer] [cwa] " . $integrationInstance->getMessage(); if ( !isset( $returnData['error'] ) ) { $returnData['error'] = $errorMessage; } else { $returnData['error'] .= "\n" . $errorMessage; } $returnData['datatransfer'] = array( 'cwa' => array( 'error' => $integrationInstance->getMessage() ) ); } else { $returnData['datatransfer'] = array( 'cwa' => array( 'qrUrl' => $integrationInstance->getDataURL( $cwaTestData ) ) ); } } else if ( ! isset( $meta['is_update'] ) || ! $meta['is_update'] ) { // delete datatransfer rows if not updating existing code data via the certificate modal $wpdb->query( $wpdb->prepare( "DELETE FROM `$dt_tableName` WHERE `code` = %s AND `integration` = 'cwa'", array( $code ) ) ); } } if ( defined( 'CTR_CWA_DEBUG' ) && !! constant( 'CTR_CWA_DEBUG' ) && isset( $returnData['datatransfer'] ) && isset( $returnData['datatransfer']['cwa'] ) ) { $returnData['datatransfer']['cwa']['data'] = $all_integration_data; } return $returnData; } /** * Booking Integration */ function corona_test_results_get_bookings( $integration ) { global $wpdb; $options = corona_test_results_get_options(); $fieldNames = array(); array_walk( $integration['db']['fields_map'], function( $value, $key ) use ( &$fieldNames ) { $fieldName = sanitize_key( $value ); $parts = explode( '.', $value ); if ( count( $parts ) === 2 ) { // we can't use sanitize_key() here, as it is case sensitive // so we use the regex from the function instead, which should be safe enough $fieldName = '`' . preg_replace( '/[^a-z0-9_\-]/i', '', $parts[0] ) . '`.`' . sanitize_key( $parts[1] ) . '`'; } $fieldNames[] = $fieldName . ' AS `' . sanitize_key( $key ) . '`'; }); $fieldNamesString = implode( ', ', $fieldNames ); $dateCompareClause = '= CURDATE()'; if ( isset( $options['booking_futuredays'] ) && (int)$options['booking_futuredays'] > 0 ) { $dateCompareClause = 'BETWEEN CURDATE() AND DATE_ADD(CURDATE(), INTERVAL ' . (int)$options['booking_futuredays'] . ' DAY)'; } $whereClause = sprintf( " WHERE DATE(`%s`) " . $dateCompareClause, sanitize_key( $integration['db']['fields_map']['start'] ) ); $arguments = array( $wpdb->prefix . sanitize_key( $integration['db']['table_relation'] ), $wpdb->prefix. sanitize_key( $integration['db']['table_appointments'] ), sanitize_key( $integration['db']['key_appointments'] ), $wpdb->prefix . sanitize_key( $integration['db']['table_data'] ), sanitize_key( $integration['db']['key_data'] ), $wpdb->prefix . sanitize_key( $integration['db']['table_payments'] ), sanitize_key( $integration['db']['key_payments'] ), $fieldNamesString ); // check for required location add-on for booking integration $locations_enabled = function_exists( 'corona_test_results_locations_enabled' ) ? corona_test_results_locations_enabled( $integration ) : false; if ( $locations_enabled ) { $locations_table =corona_test_results_sanitize_tablename( $integration['locations']['table'] ); $locations_id_column = corona_test_results_sanitize_tablename( $integration['locations']['location_id_column'] ); $foreign_key_column = corona_test_results_sanitize_tablename( $integration['locations']['foreign_key_column'] ); $location_name_column = corona_test_results_sanitize_tablename( $integration['locations']['location_name_column'] ); $location_name = corona_test_results_get_current_location_data()['name'] ?? null; if ( $location_name ) { $locationIdSQL = $wpdb->prepare( "SELECT `" . corona_test_results_sanitize_tablename( $locations_id_column ) . "` FROM `$locations_table` WHERE UPPER(`" . corona_test_results_sanitize_tablename( $location_name_column ) . "`) LIKE %s", strtoupper( $location_name ) ); $matchingLocations = $wpdb->get_results ( $locationIdSQL ); if ( count( $matchingLocations ) ) { $whereClause .= sprintf( ' AND `%s` = %d', $foreign_key_column, (int)$matchingLocations[0]->id ); } else { // if not an admin user, return no bookings if there's no matching location, // otherwise, all bookings from any location will be shown if ( ! current_user_can( corona_test_results_get_required_capability( 'settings' ) ) ) { return array(); } } } } $appointmentsSql = apply_filters( 'corona_test_results_appointment_bookings_query', vsprintf( 'SELECT `%1$s`.`id` AS `id`,%8$s FROM `%1$s` LEFT JOIN `%2$s` ON `%1$s`.`%3$s` = `%2$s`.`id` LEFT JOIN `%4$s` ON `%1$s`.`%5$s` = `%4$s`.`id` LEFT JOIN `%6$s` ON `%1$s`.`%7$s` = `%6$s`.`id` ' . $whereClause . ' ORDER BY `start` ASC', $arguments ), $integration, $fieldNames ); $appointments = $wpdb->get_results( $appointmentsSql ); if ( !empty( $appointments ) ) { foreach ( $appointments as $key => $appointment ) { $appointment = apply_filters( 'corona_test_results_appointments_before', $appointment ); if ( isset( $integration['payment_status_filter'] ) ) { $appointment->payment_status = isset( $appointment->payment_status ) ? $integration['payment_status_filter']( $appointment->payment_status ) : null; } $appointment->address = preg_replace( "/[ ]+/", " ", strtr( // translators: Address format for bookings. Available placeholders: %firstname, %surname, %addition, %number, %street, %city, %postcode, %state, %country apply_filters( 'corona_test_results_booking_address_template', __( "%addition\n%number %street\n%city, %postcode %state\n%country", 'corona-test-results' ), $appointment ), array( '%firstname' => isset( $appointment->firstname ) ? $appointment->firstname : '', '%surname' => isset( $appointment->surname ) ? $appointment->surname : '', '%addition' => isset( $appointment->addition ) ? $appointment->addition : '', '%number' => isset( $appointment->number ) ? $appointment->number : '', '%street' => isset( $appointment->street ) ? $appointment->street : '', '%city' => isset( $appointment->city ) ? $appointment->city : '', '%postcode' => isset( $appointment->postcode ) ? $appointment->postcode : '', '%state' => isset( $appointment->state ) ? $appointment->state : '', '%country' => isset( $appointment->country ) ? $appointment->country : '' ) )); $appointment->start_time = isset( $appointment->start ) ? date_i18n( get_option('time_format'), strtotime( $appointment->start ) ) : null; unset( $appointment->addition ); unset( $appointment->number ); unset( $appointment->street ); unset( $appointment->city ); unset( $appointment->postcode ); unset( $appointment->state ); unset( $appointment->country ); // trim whitespace and empty rows $appointment->address = trim( preg_replace( "/\n\s*\n/", "\n", $appointment->address ) ); $appointment = apply_filters( 'corona_test_results_appointments_after', $appointment ); } } return $appointments; } function corona_test_results_ajax_get_current_bookings() { corona_test_results_security_check_ajax_auth( 'register' ); if ( !isset( $_POST['provider'] ) || empty( sanitize_key( $_POST['provider'] ) ) ) { wp_send_json_error( null, 400 ); } $provider = sanitize_key( $_POST['provider'] ); $bookingIntegrations = corona_test_results_get_supported_booking_integrations(); if ( !isset( $bookingIntegrations[ $provider ] ) ) { wp_send_json_error( null, 404 ); } corona_test_results_force_gzip(); wp_send_json_success( corona_test_results_get_bookings( $bookingIntegrations[ $provider ] ) ); } add_action( 'wp_ajax_corona_test_results_ajax_get_current_bookings', 'corona_test_results_ajax_get_current_bookings' ); /** * Update check */ function corona_test_results_update_check_plugin_defaults() { $icon_image = 'assets/icon.svg'; $icon_url = trailingslashit( corona_test_results_plugin_dir_url() ) . $icon_image . '?rev=' . filemtime( corona_test_results_plugin_dir_path() . $icon_image ); $banner_1x_image = 'assets/banner-772x250.jpg'; $banner_1x_url = trailingslashit( corona_test_results_plugin_dir_url() ) . $banner_1x_image . '?rev=' . filemtime( corona_test_results_plugin_dir_path() . $banner_1x_image ); $banner_2x_image = 'assets/banner-1544x500.jpg'; $banner_2x_url = trailingslashit( corona_test_results_plugin_dir_url() ) . $banner_2x_image . '?rev=' . filemtime( corona_test_results_plugin_dir_path() . $banner_2x_image ); $pluginInfo = corona_test_results_get_plugin_info(); return array( 'id' => untrailingslashit(explode("//", corona_test_results_premium_shop_url(), 2)[1]), 'slug' => dirname( corona_test_results__mainfile( true ) ), 'plugin' => corona_test_results__mainfile( true ), 'name' => $pluginInfo['Name'], 'version' => $pluginInfo['Version'], 'requires' => $pluginInfo['RequiresWP'], 'tested' => '5.8.1', 'requires_php' => $pluginInfo['RequiresPHP'], 'author' => corona_test_results_get_author_link(), 'url' => corona_test_results_premium_shop_url(), // 'rating' => 100, 'icons' => array( '2x' => $icon_url, '1x' => $icon_url, ), 'banners' => array( '2x' => $banner_2x_url, 'high' => $banner_2x_url, '1x' => $banner_1x_url, 'low' => $banner_1x_url, ), 'sections' => array( 'description' => preg_replace( '/^<br><br>/', '', str_replace( array( '🦠', '</strong>' ) , array( '<br><br>🦠', '</strong><br>' ), $pluginInfo['Description'] ) ), // 'installation' => 'Installation...', // 'changelog' => 'Changelog...' ) ); } function corona_test_results_update_get_remote_info() { global $corona_test_results_current_location, $corona_test_results_current_options_name; // force main location during update check $corona_test_results_current_location = 1; $corona_test_results_current_options_name = corona_test_results_get_options_option_name( 1 ); $options = corona_test_results_get_options( 1 ); $response = null; $use_cache = false; if( false === $use_cache || false == $response = get_transient( 'corona_test_results_update_check_cache' ) ) { $remote = wp_remote_post( base64_decode('aHR0cHM6Ly9zaG9wLjQ4ZGVzaWduLmNvbS92aWVyYWNodGRlc2lnbl9saWNlbnNpbmcucGhw'), array( 'timeout' => 10, 'headers' => array( 'Accept' => 'application/json' ), 'body' => array( 'action' => 'wp_check_update', 'pid' => 'b05bd1e415c8eedd93ed10302f88be8457f73aaa23db1ebd13e06f155b063903', 'key' => trim( $options[ base64_decode( 'bGljZW5zZV9rZXk=' ) ] ), 'uuid' => $_SERVER[ base64_decode( 'SFRUUF9IT1NU' ) ] ) )); if ( !is_wp_error( $remote ) && isset( $remote['response']['code'] ) && $remote['response']['code'] == 200 && !empty( $remote['body'] ) ) { $response = json_decode( $remote['body'] ); set_transient( 'corona_test_results_update_check_cache', $response, 4 * 60 * 60 ); } else { delete_transient( 'corona_test_results_update_check_cache' ); } } return $response; } function corona_test_results_plugin_info_overwrite_slug( $args, $action ) { if( 'plugin_information' !== $action ) { return $args; } $defaults = (object)corona_test_results_update_check_plugin_defaults(); // do nothing if it is not our plugin if( $defaults->slug !== $args->slug ) { return $args; } $args->slug = 'corona-test-results'; return $args; } add_filter('plugins_api_args', 'corona_test_results_plugin_info_overwrite_slug', 20, 2); function corona_test_results_plugin_info_premium_overrides( $res, $action, $args ) { if( 'plugin_information' !== $action ) { return $res; } $defaults = (object)corona_test_results_update_check_plugin_defaults(); // do nothing if it is not our plugin if( $defaults->slug !== $args->slug && 'corona-test-results' !== $args->slug ) { return $res; } $response = corona_test_results_update_get_remote_info(); if ( $response && isset( $response->success ) && $response->success && isset( $response->data ) ) { if ( empty( $res ) || is_wp_error( $res )) { $res = (object) array_merge((array) $res, (array) $defaults); } else { $res = (object) array_merge((array) $defaults, (array) $res); } if ( $defaults->slug !== $args->slug ) { $res->name = $defaults->name; $res->slug = $defaults->slug; } $response = $response->data; $res->name = isset( $response->name ) ? $response->name : $res->name; $res->url = isset( $response->url ) ? $response->url : $res->url; $res->icons = isset( $response->icons ) ? $response->icons : $res->icons; $res->banners = isset( $response->banners ) ? $response->banners : $res->banners; $res->version = isset( $response->latest_version ) ? $response->latest_version : $res->version; $res->tested = isset( $response->tested ) ? $response->tested : $res->tested; $res->requires = isset( $response->requires ) ? $response->requires : $res->requires; $res->download_link = isset( $response->latest_version_download ) ? $response->latest_version_download : null; $res->trunk = isset( $response->latest_version_download ) ? $response->latest_version_download : null; $res->requires_php = isset( $response->requires_php ) ? $response->requires_php : $res->requires_php; // $res->last_updated = isset( $response->last_updated ) ? $response->last_updated : $res->last_updated; if ( isset( $response->tab_sections ) ) { $res->sections = array_merge( $res->sections, (array)$response->tab_sections ); } return $res; } return $res; } add_filter('plugins_api_result', 'corona_test_results_plugin_info_premium_overrides', 20, 3); function corona_test_results_hook_update_check( $transient ) { $options = corona_test_results_get_options(); $defaults = (object)corona_test_results_update_check_plugin_defaults(); if ( !isset($transient->checked) || empty( $transient->checked ) || !isset( $transient->checked[ $defaults->plugin ] ) ) { return $transient; } $response = corona_test_results_update_get_remote_info(); $hasUpdate = false; if ( !empty( $options[ base64_decode( 'bGljZW5zZV9rZXk=' ) ] )) { if( $response && isset( $response->success ) && $response->success && isset( $response->data ) ) { $response = $response->data; if ( $response->latest_version && version_compare( $defaults->version, $response->latest_version, '<' ) && ( empty($response->requires) || version_compare($response->requires, get_bloginfo('version'), '<' ) ) ) { $res = $defaults; $res->new_version = $response->latest_version; $res->tested = $response->tested ?: $res->tested; $res->requires = isset( $response->requires ) ? $response->requires : $res->requires; $res->requires_php = isset( $response->requires_php ) ? $response->requires_php : $res->requires_php; $res->package = $response->latest_version_download; $transient->response[$res->plugin] = $res; // $transient->checked[$res->plugin] = $res->latest_version; } } else if ( $response && isset( $response->code ) ) { $reqres = array( base64_decode('bGljZW5zZV9hbHJlYWR5X2FjdGl2YXRlZF9mb3JfZGlmZmVyZW50X3V1aWQ='), base64_decode('bm90X2ZvdW5k'), base64_decode('bm9fb3JkZXJfZm9yX2xpY2Vuc2U='), base64_decode('aW5jb3JyZWN0X3BpZA==' ), base64_decode('d3JvbmdfcHJvZHVjdF90eXBl' ) ); if ( in_array( $response->code, $reqres )) { $options[ base64_decode( 'bGljZW5zZV9rZXk=' ) ] = ''; update_option( base64_decode( 'Y29yb25hX3Rlc3RfcmVzdWx0c19vcHRpb25z' ), $options ); set_transient( base64_decode( 'Y29yb25hX3Rlc3RfcmVzdWx0c19saWNlbnNlX2Vycm9y' ), sprintf( // translators: support link with text "contact us" __( "Your license could not be verified and may have expired. Try activating the plugin again or %s if there is an issue.", 'corona-test-results' ), corona_test_results_get_support_mail_link( __( 'contact us', 'corona-test-results' ) ) ), 0 ); } } } if ( false === $hasUpdate ) { $transient->no_update[ $defaults->plugin ] = $defaults; } return $transient; } add_filter('pre_set_site_transient_update_plugins', 'corona_test_results_hook_update_check' ); function corona_test_results_update_cleanup( $upgrader, $options ) { if ( $options['action'] == 'update' && $options['type'] === 'plugin' && 'corona-test-results-premium' === $upgrader->result['destination_name']) { delete_transient( 'corona_test_results_update_check_cache' ); } } add_action( 'upgrader_process_complete', 'corona_test_results_update_cleanup', 10, 2 ); /** * get the encrypted data for a code from the database */ function corona_test_results_ajax_getdata() { corona_test_results_security_check_ajax_auth( 'codes' ); $code = sanitize_text_field( $_POST['code'] ); $pin = sanitize_text_field( $_POST['pin'] ); if ( ! corona_test_results_check_crypto_activated() || ! preg_match( corona_test_results_get_code_regex(), $code ) ) { wp_send_json_error( null, 400 ); } global $wpdb; $location_ids = array( 1 ); $current_location = corona_test_results_get_current_location(); $fetch_multiple_locations = apply_filters( 'corona_test_results_filter_is_master_location', false, $current_location ); $locations = corona_test_results_locations_get(); $location_ids = $fetch_multiple_locations ? array_keys( $locations ) : array( $current_location ); $tableName = corona_test_results_get_table_name( '', $fetch_multiple_locations && isset( $_POST['location'] ) && is_numeric( $_POST['location'] ) && in_array( (int)$_POST['location'], $location_ids ) ? (int)$_POST['location'] : $current_location ); $dataSQL = $wpdb->prepare( "SELECT `data`,`created_at`,`registration_user_id`,`status_changed`,`status` FROM `$tableName` WHERE `code` = %s AND `trash` = 0 LIMIT 1", $code ); $codeData = $wpdb->get_results ( $dataSQL ); if ( count( $codeData ) === 1 ) { $updated = false; $mysql_now = current_time( 'mysql', true ); // update code status if ( isset( $_POST['status'] ) && is_numeric( $_POST['status'] ) && array_key_exists( (int)$_POST['status'], corona_test_results_get_states() ) ) { $newStatus = (int)$_POST['status']; $update_stmt = "UPDATE `$tableName` SET `status` = %d, `status_changed` = %s WHERE `code` = %s AND `status` != %d"; $result = $wpdb->query( $wpdb->prepare( $update_stmt, $newStatus, $mysql_now, $code, $newStatus ) ); $updated = !!$result; } $createdAt = get_date_from_gmt( $codeData[0]->created_at, 'Y-m-d H:i:s' ); $statusChanged = get_date_from_gmt( $updated ? $mysql_now : $codeData[0]->status_changed, 'Y-m-d H:i:s' ); $updateNonce = wp_create_nonce( 'corona_test_results_ajax_update_codedata-' . $code ); if ( empty( $codeData[0]->data ) ) { corona_test_results_force_gzip(); wp_send_json_success( array( 'certData' => null, 'meta' => array( 'created_at' => $createdAt, 'registration_user_id' => (int)$codeData[0]->registration_user_id, 'status_changed' => $statusChanged, 'status' => $updated ? (int)$_POST['status'] : $codeData[0]->status, 'update_nonce' => $updateNonce ), 'updated' => $updated ) ); } require_once( corona_test_results_plugin_dir_path() . 'lib/DataEncryption.class.php' ); $E = new DataEncryption(); if ( false === $E->decrypt( $codeData[0]->data, $pin ) ) { wp_send_json_error( null, 401 ); } else { corona_test_results_force_gzip(); wp_send_json_success( array( 'certData' => json_decode( $E->decrypt( $codeData[0]->data, $pin ) ), 'meta' => array( 'created_at' => $createdAt, 'registration_user_id' => (int)$codeData[0]->registration_user_id, 'status_changed' => $statusChanged, 'status' => $updated ? (int)$_POST['status'] : (int)$codeData[0]->status, 'update_nonce' => $updateNonce ), 'updated' => $updated ) ); } } else { wp_send_json_error( null, 404 ); } } add_action( 'wp_ajax_corona_test_results_ajax_getdata', 'corona_test_results_ajax_getdata' ); function corona_test_results_auth_files_path() { $wpUploadDir = wp_upload_dir(); return $wpUploadDir['basedir'] . '/.ctr_auth/'; } function corona_test_results_ajax_uploadfile() { corona_test_results_security_check_ajax_auth( 'settings' ); $content = sanitize_textarea_field( $_POST['content'] ); $file = sanitize_text_field( $_POST['file'] ); $allowedFiles = array( 'cwa_certificate-wru.cer', 'cwa_key-wru.key', 'cwa_certificate-production.cer', 'cwa_key-production.key' ); if ( empty( $content) || empty( $file ) || ! in_array( $file, $allowedFiles ) ) { wp_send_json_error( null, 400 ); } if ( !defined( 'FS_CHMOD_DIR' ) || !defined( 'FS_CHMOD_FILE' ) ) { if( function_exists( 'WP_Filesystem' )) { WP_Filesystem(); } else { if ( ! defined( 'FS_CHMOD_DIR' ) ) { define( 'FS_CHMOD_DIR', ( fileperms( ABSPATH ) & 0777 | 0755 ) ); } if ( ! defined( 'FS_CHMOD_FILE' ) ) { define( 'FS_CHMOD_FILE', ( fileperms( ABSPATH . 'index.php' ) & 0777 | 0644 ) ); } } } $filesDir = corona_test_results_auth_files_path(); $filePrefix = hash( 'sha256', get_site_url() . '#' . $filesDir . '#' . $file ) . '-'; if ( ! is_dir( $filesDir ) ) { mkdir( $filesDir, FS_CHMOD_DIR, true ); } if ( ! is_file( $filesDir . '.htaccess' ) ) { file_put_contents( $filesDir . '.htaccess', "Order Deny,Allow\nDeny from all"); chmod( $filesDir . '.htaccess', FS_CHMOD_FILE ); } // if the htaccess file could not be written if ( ! is_file( $filesDir . '.htaccess' ) ) { wp_send_json_error( 'AUTH_DIR_NOT_PROTECTED', 500 ); } $filePath = $filesDir . $filePrefix . $file; if ( is_file( $filePath ) ) { chmod( $filePath, FS_CHMOD_FILE ); } file_put_contents( $filePath, $content ); chmod( $filePath, FS_CHMOD_FILE ); wp_send_json_success( array( 'filePath' => realpath( $filePath ) ) ); } add_action( 'wp_ajax_corona_test_results_ajax_uploadfile', 'corona_test_results_ajax_uploadfile' ); function corona_test_results_ajax_datatransfer_submit() { $nonce_check = corona_test_results_security_check_ajax_auth( 'codes', null, true ); if ( $nonce_check !== true ) { wp_send_json_error('ACCESS_DENIED', 403); exit; } ini_set('display_errors',1); $code = sanitize_text_field( $_POST['code'] ); $integration = sanitize_text_field( $_POST['integration'] ); if ( ! corona_test_results_check_crypto_activated() || ! preg_match( corona_test_results_get_code_regex(), $code ) || ! corona_test_results_check_datatransfer_integration_enabled( $integration ) ) { wp_send_json_error( null, 400 ); } global $wpdb; $tableName = corona_test_results_get_table_name(); $datatransferTableName = corona_test_results_get_table_name( 'datatransfer' ); $dataSQLQuery = "SELECT `$tableName`.`status_changed`, `$tableName`.`status`, `$datatransferTableName`.`data`, `$datatransferTableName`.`transferred` FROM `$tableName` LEFT JOIN `$datatransferTableName` ON `$datatransferTableName`.`code` = `$tableName`.`code` AND `$datatransferTableName`.`integration` = %s WHERE `$tableName`.`code` = %s AND `$tableName`.`trash` = 0 AND `$datatransferTableName`.`integration` = %s LIMIT 1"; $dataSQL = $wpdb->prepare( $dataSQLQuery, array( $integration, $code, $integration ) ); $codeData = $wpdb->get_results( $dataSQL ); if ( count( $codeData ) === 1 ) { if ( $integration === 'cwa' ) { $codeData = $codeData[0]; if ( (bool)$codeData->transferred ) { wp_send_json_error( __( 'Data has already been transferred to this interface.', 'corona-test-results' ), 400); } $integrationData = $codeData->data; if ( empty ( $integrationData ) ) { wp_send_json_error('INTEGRATION_DATA_MISSING', 500); } $integrationData = json_decode( $codeData->data ); if ( empty ( $integrationData ) ) { wp_send_json_error('INTEGRATION_DATA_INVALID', 500); } if ( ! isset( $integrationData->hash ) || empty( $integrationData->hash) ) { wp_send_json_error('INTEGRATION_DATA_HASH_MISSING', 500); } $CWAQuicktest = corona_test_results_check_datatransfer_integration_getinstance( $integration ); if ( $CWAQuicktest instanceof \Exception ) { wp_send_json_error( "[CWAQuicktest] " . $CWAQuicktest->getMessage(), 500 ); } $statusMap = array( 0 => FortyeightDesign\CWAQuicktest::RESULT_INVALID, 1 => FortyeightDesign\CWAQuicktest::RESULT_POSITIVE, 2 => FortyeightDesign\CWAQuicktest::RESULT_NEGATIVE, 3 => FortyeightDesign\CWAQuicktest::RESULT_INVALID ); $submitStatus = $statusMap[$codeData->status]; $sampling_timestamp = ((int)get_date_from_gmt( $codeData->status_changed, 'U' )) - ( 15 * 60 ); try { $resultObject = new FortyeightDesign\CWAQuicktestResult(array( 'id' => $integrationData->hash, 'result' => $submitStatus, 'sc' => $sampling_timestamp )); } catch ( \Exception $e ) { wp_send_json_error( "[CWAQuicktestResult] " . $e->getMessage(), 500 ); } $statusSubmitted = $CWAQuicktest->sendResults(array( $resultObject )); if ( $statusSubmitted !== true ) { wp_send_json_error( 'INTEGRATION_SUBMIT_FAILED' . ( is_object( $statusSubmitted ) && isset( $statusSubmitted->status ) ? '[' . (int)$statusSubmitted->status . ']' : '' ), 500 ); } $wpdb->query( $wpdb->prepare( "UPDATE `$datatransferTableName` SET `transferred` = 1 WHERE `code` = %s AND `integration` = %s", array( $code, $integration ) ) ); wp_send_json_success(); } wp_send_json_error( null, 500 ); } else { wp_send_json_error( __( 'No data transfer was requested for this interface.', 'corona-test-results' ) , 404 ); } } add_action( 'wp_ajax_corona_test_results_ajax_datatransfer_submit', 'corona_test_results_ajax_datatransfer_submit' ); function corona_test_results_ajax_datatransfer_check() { corona_test_results_security_check_ajax_auth( 'settings' ); $integration = isset( $_POST['integration'] ) ? sanitize_text_field( $_POST['integration'] ) : null; if ( empty( $integration ) ) { wp_send_json_error( __( 'Authentication data could not be verified', 'corona-test-results' ), 400 ); } $integrationInstance = corona_test_results_check_datatransfer_integration_getinstance( $integration ); if ( ! $integrationInstance || $integrationInstance instanceof \Exception ) { wp_send_json_error( __( 'Authentication data could not be verified', 'corona-test-results' ) . ': ' . $integrationInstance->getMessage(), 500 ); } else { wp_send_json_success( __( 'Authentication data verified successfully.', 'corona-test-results' ) ); } } add_action( 'wp_ajax_corona_test_results_ajax_datatransfer_check', 'corona_test_results_ajax_datatransfer_check' ); function corona_test_results_ajax_import_csv() { global $wpdb; $options = corona_test_results_get_options(); corona_test_results_security_check_ajax_auth( 'register' ); if ( ! isset( $options['license_key'] ) || empty( $options['license_key'] ) ) { wp_send_json_error('ACCESS_DENIED', 403); } global $linesProcessedOK, $parsed, $recordsSkipped, $codesCreated, $recordErrors; $parsed = array(); $recordErrors = array(); $recordsSkipped = 0; $linesProcessedOK = 0; $codesCreated = 0; function ctr_csv_import_shutdown() { global $linesProcessedOK, $parsed, $recordsSkipped, $codesCreated, $recordErrors; $error = error_get_last(); if ( $error ) { ob_clean(); $returnData = array( 'error' => sprintf( // transoators: %s: the error message __( 'An error occurred on the server during the import process: %s', 'corona-test-results' ), $error['message'] ) . "\n", 'total' => count( $parsed ), 'skipped' => $recordsSkipped, 'ok' => $linesProcessedOK, 'created' => $codesCreated, 'recordErrors' => $recordErrors ); if ( $returnData['ok'] > 0 ) { $returnData['error'] .= "\n" . sprintf( __( '%d records were imported successfully before this error occurred. Please check latest imported record for completeness.', 'corona-test-results' ), $returnData['ok'] ); wp_send_json_success( $returnData ); } wp_send_json_error( $returnData ); } } add_action( 'shutdown', 'ctr_csv_import_shutdown', 0 ); ini_set('display_errors',0); @set_time_limit(10 * 60); @session_write_close(); // based on code from https://stackoverflow.com/questions/26717462/php-best-approach-to-detect-csv-delimiter/59581170 function detectDelimiter( $firstCSVLine ): ?string { $delimiters = [ ';' => 0, ',' => 0, "|" => 0, "\t" => 0 ]; foreach ($delimiters as $delimiterCharacter => $delimiterCount) { $foundColumnsWithThisDelimiter = count(str_getcsv($firstCSVLine, $delimiterCharacter)); if ($foundColumnsWithThisDelimiter > 1) { $delimiters[$delimiterCharacter] = $foundColumnsWithThisDelimiter; } else { unset($delimiters[$delimiterCharacter]); } } if ( !empty($delimiters) ) { return array_search(max($delimiters), $delimiters); } else { throw new \Exception('The CSV delimiter could not been found. Should be semicolon, comma, pipe or tab!'); } } function ctr_parse_csv( $str, $delimiter = ',' ) { // match all the non-quoted text and one series of quoted text (or the end of the string) // each group of matches will be parsed with the callback, with $matches[1] containing all the non-quoted text, // and $matches[3] containing everything inside the quotes $str = preg_replace_callback( '/([^"=]*)(=?"((""|[^"])*)"|$)/s', function ( $matches ) use ( $delimiter ) { return ctr_parse_csv_quotes( $matches, $delimiter ); }, $str ); // remove the very last newline to prevent a 0-field array for the last line $str = preg_replace( '/\n$/', '', $str ); // split on LF and parse each line with a callback return array_map(function ( $lineStr ) use ( $delimiter ) { return ctr_parse_csv_line( $lineStr, $delimiter ); }, explode("\n", $str) ); } // replace all the csv-special characters inside double quotes with markers using an escape sequence function ctr_parse_csv_quotes( $matches, $delimiter = ',' ) { // anything inside the quotes that might be used to split the string into lines and fields later, // needs to be quoted. The only character we can guarantee as safe to use, because it will never appear in the unquoted text, is a CR // So we're going to use CR as a marker to make escape sequences for CR, LF, Quotes, and Commas. if ( isset( $matches[3] ) && ! empty( $matches[3] ) ) { $str = str_replace("\r", "\rR", $matches[3] ); $str = str_replace("\n", "\rN", $str); $str = str_replace('""', "\rQ", $str); $str = str_replace($delimiter, "\rC", $str); } else { $str = ''; } // The unquoted text is where commas and newlines are allowed, and where the splits will happen // We're going to remove all CRs from the unquoted text, by normalizing all line endings to just LF // This ensures us that the only place CR is used, is as the escape sequences for quoted text return preg_replace('/\r\n?/', "\n", $matches[1]) . $str; } // split on comma and parse each field with a callback function ctr_parse_csv_line( $line, $delimiter = ',' ) { return array_map(function( $arr ) use ( $delimiter ) { return ctr_parse_csv_field( $arr, $delimiter ); }, explode($delimiter, $line) ); } // restore any csv-special characters that are part of the data function ctr_parse_csv_field( $field, $delimiter = ',' ) { $field = str_replace("\rC", $delimiter, $field); $field = str_replace("\rQ", '"', $field); $field = str_replace("\rN", "\n", $field); $field = str_replace("\rR", "\r", $field); return $field; } $skipRecords = isset( $_POST['skipRecords'] ) ? (int)$_POST['skipRecords'] : 0; $csvString = file_get_contents( $_FILES['csvContent']['tmp_name'] ); $hasBOM = substr($csvString, 0, 3) === chr(0xEF) . chr(0xBB) . chr(0xBF); if ( ! $hasBOM ) { $encoding = mb_detect_encoding( $csvString, array('UTF-8', 'ISO-8859-1') ); if ( $encoding === 'ISO-8859-1' ) { $csvString = utf8_encode($csvString); } } else { $csvString = substr( $csvString, 3 ); } // remove empty lines $csvString = preg_replace("/(\r?\n){2,}/", "$1", $csvString); $separator = "\r\n"; $line = strtok($csvString, $separator); $delimiter = detectDelimiter( $line ); if ( $delimiter ) { $parsed = ctr_parse_csv( $csvString, $delimiter ); $columnNames = array_shift ( $parsed ); $certs_enabled = corona_test_results_check_certificates_enabled(); $pins_disabled = ! $certs_enabled || apply_filters( 'corona_test_results_pins_disabled', false ); $hasPINColumn = trim( $columnNames[3] ) === __( 'PIN', 'corona-test-results' ); if ( $hasPINColumn && $pins_disabled ) { wp_send_json_error(array( 'error' => sprintf( // translators: reason (certificate or PIN functionality disabled) __( 'Unexpected PIN column - %s', 'corona-test-results' ), ( ! $certs_enabled ? __( 'certificate functionality is disabled', 'corona-test-results' ) : __( 'PIN functionality is disabled', 'corona-test-results' ) ) ) ), 422); } else if ( ! $hasPINColumn && ! $pins_disabled ) { wp_send_json_error(array( 'error' => __( 'Missing PIN column', 'corona-test-results' ) ), 422); } $columnCount = count ( (array)$columnNames ); $valid_states = corona_test_results_get_states(); defined( 'CTR_DATA_IMPORT' ) or define( "CTR_DATA_IMPORT", true ); $customfields = corona_test_results_get_custom_fields(); $importedCodes = array_filter( array_map( function( $line ) { return $line[0]; }, $parsed ) ); $certField = ''; if ( $certs_enabled ) { $certField = ',`certificate_sent`'; } if ( !empty( $importedCodes ) ) { // $wpdb->show_errors = true; $tableName = corona_test_results_get_table_name(); $dt_tableName = corona_test_results_get_table_name( 'datatransfer' ); $codesSql = $wpdb->prepare( "SELECT `$tableName`.`code`,`$dt_tableName`.`transferred` $certField FROM `$tableName` LEFT JOIN `$dt_tableName` ON ( `$tableName`.`code` = `$dt_tableName`.`code` ) WHERE `$tableName`.`code` IN(" . implode(', ', array_fill( 0, count( $importedCodes ), '%s' ) ) . ")", $importedCodes ); $existingCodesData = $wpdb->get_results( $codesSql ); } else { $existingCodesData = array(); } // var_dump($existingCodesData); exit; $existingCodes = array(); if ( count( $existingCodesData ) ) { $existingCodes = array_map( function( $code ) { return $code->code; }, $existingCodesData ); } $certificateSentCodes = array(); if ( $certs_enabled ) { $certificateSentCodes = array_map( function( $code ) { return $code->code; }, array_filter( $existingCodesData, function( $code ) { return $code->certificate_sent; } ) ); } $dataTransferredCodes = array(); if ( $certs_enabled ) { $dataTransferredCodes = array_map( function( $code ) { return $code->code; }, array_filter( $existingCodesData, function( $code ) { return $code->transferred; } ) ); } function ctr_detectDateFormat( $stringIn, $fallBack = false ) { global $date_format; $format_detected = null; if ( $stringIn[4] === '-' && $stringIn[7] === $stringIn[4] ) { $format_detected = 'iso'; } else if ( $stringIn[2] === '.' && $stringIn[5] === $stringIn[2] ) { $format_detected = 'de'; } else if ( $stringIn[2] === '/' && $stringIn[5] === $stringIn[2] ) { $format_detected = 'uk_or_us'; if ( (int)strtok( $stringIn, '/' ) > 12 ) { $format_detected = 'uk'; } else if ( (int)strtok( '/' ) > 12 ) { $format_detected = 'us'; } } if ( $fallBack && $format_detected === 'uk_or_us' && in_array( $fallBack, array( 'uk', 'us' ) ) ) { $format_detected = $fallBack; } return $format_detected; } function ctr_unifyDate( $inputString, $format ) { if ( !in_array( $format, array( 'iso', 'de', 'uk', 'us' ) ) ) { throw new \Exception( "Invalid format: $format" ); } if ( $format === 'iso' ) { return $inputString; } $parts = explode( ' ', $inputString ); $hasTime = ( count( $parts ) > 1 ); $dateParts = array(); $mdy = ($format === 'us' ); switch ( $format ) { case 'de': $dateParts = explode( '.', $parts[0] ); break; case 'uk': case 'us': $dateParts = explode( '/', $parts[0] ); break; } if ( count( $dateParts ) < 2 ) { throw new \Exception( "Invalid input string or date format combination." ); } if ( $mdy ) { $gluedDate = $dateParts[2] . '-' . $dateParts[0] . '-' . $dateParts[1]; } else { $gluedDate = implode( '-', array_reverse( $dateParts ) ); } return $gluedDate . ( $hasTime ? ' ' . $parts[1] : '' ); } // auto-detect date format $date_format = null; foreach( $parsed as $recordNo => $line ) { if ( $recordNo < $skipRecords ) { $recordsSkipped++; continue; } $recordNo = $recordNo + 1; $dateColumn = $line[2]; $format_detected = ctr_detectDateFormat( $dateColumn ); switch ( true ) { case ! $format_detected: wp_send_json_error(array( 'error' => sprintf( __( 'Could not determine date format for record #%d', 'corona-test-results' ), $recordNo ) ), 422); break; case ! $date_format: case $date_format === 'uk_or_us' && ( $format_detected === 'uk' || $format_detected === 'us' ) : $date_format = $format_detected; break; case $date_format === 'uk_or_us' && $format_detected !== $date_format && $format_detected !== 'uk' && $format_detected !== 'us' : case $date_format !== 'uk_or_us' && $format_detected !== $date_format && ! ( ( $date_format === 'uk' || $date_format === 'us' ) && $format_detected === 'uk_or_us' ) : wp_send_json_error(array( 'error' => sprintf( __( 'Inconsistent date format used in record #%d', 'corona-test-results' ), $recordNo ) ), 422); break; } } if ( empty( $date_format ) ) { wp_send_json_error(array( 'error' => __( 'Could not determine date format', 'corona-test-results' ) ), 422); } else if ( $date_format === 'uk_or_us' ) { if ( isset( $_POST['forceDateFormat'] ) && in_array( $_POST['forceDateFormat'], array( 'uk', 'us' ) ) ) { $date_format = $_POST['forceDateFormat']; } else { wp_send_json_error(array( 'error' => __( 'Date format used is ambiguous. Please force the date format from the selection below.', 'corona-test-results' ), 'error_date_ambiguous' => true ), 422); } } $o = $pins_disabled ? 0 : 1; // column offset: 1 if pin is used foreach( $parsed as $recordNo => $line ) { $recordNo = $recordNo + 1; $birthday_format = empty( $line[ 5 + $o ] ) ? false : ctr_detectDateFormat( $line[ 5 + $o ], $date_format ); if ( count( (array)$line ) !== $columnCount ) { $recordErrors[ $recordNo ] = __( 'Column count does not match', 'corona-test-results' ); } else if ( !empty( $line[0] ) && ! in_array( $line[0], $existingCodes ) && ! preg_match( corona_test_results_get_code_regex(), $line[0] ) ) { $recordErrors[ $recordNo ] = sprintf( __( 'Code "%s" is not a valid code', 'corona-test-results' ), $line[0] ); } else if ( ! $pins_disabled && ( ! is_numeric( $line[3] ) || strlen( $line[3] ) !== 6 ) ) { $recordErrors[ $recordNo ] = sprintf( __( 'No valid 6-digit PIN provided', 'corona-test-results' ), $line[0] ); } else if ( in_array( $line[0], $certificateSentCodes) ) { $recordErrors[ $recordNo ] = sprintf( __( 'Certificate for code "%s" has already been sent', 'corona-test-results' ), $line[0] ); } else if ( in_array( $line[0], $dataTransferredCodes) ) { $recordErrors[ $recordNo ] = sprintf( __( 'Data for code "%s" has already been transferred', 'corona-test-results' ), $line[0] ); } else if ( ! in_array( trim( $line[1] ), $valid_states ) ) { $recordErrors[ $recordNo ] = sprintf( __( 'Code status "%s" is not a valid status', 'corona-test-results' ), $line[1] ); } else if ( $birthday_format !== false && ( $birthday_format === null || ( $birthday_format === 'uk_or_us' && !in_array( $date_format, array( 'uk', 'us' ) ) ) ) ) { $recordErrors[ $recordNo ] = sprintf( __( 'Could not determine date format of birthday column. Please use the following format: yyyy-mm-dd', 'corona-test-results' ), $line[1] ); } if ( empty( $recordErrors ) ) { $codeEmpty = empty( $line[0] ); $addCode = ! in_array( $line[0], $existingCodes ); $isNewCode = $codeEmpty || $addCode; if ( $isNewCode ) { if ( $codeEmpty ) { $_POST['code'] = corona_test_results_ajax_get_unique_code(); if ( empty( $_POST['code'] ) ) { $recordErrors[ $recordNo ] = __( 'New random code could not be generated', 'corona-test-results' ); continue; } $createResult = corona_test_results_ajax_getcode(); } else if ( $addCode ) { add_filter( 'corona_test_results_result_code_readonly', '__return_false', 99 ); $_POST['code'] = $line[0]; $createResult = corona_test_results_ajax_getcode(); remove_filter( 'corona_test_results_result_code_readonly', '__return_false', 99 ); } if ( ! $createResult || ! isset( $createResult['success'] ) ) { // var_dump($createResult); $errorMsg = isset( $createResult['error'] ) ? $createResult['error'] : ( isset( $createResult['data'] ) ? $createResult['data'] : null ); $recordErrors[ $recordNo ] = __( 'New code could not be added', 'corona-test-results' ) . ( $errorMsg ? ': ' . $errorMsg : '' ); continue; } else { $line[0] = $createResult['data']['test_result_code']; } $codesCreated++; } // var_dump($line); $pin = $pins_disabled ? '' : $line[3]; $new_status = array_search( trim( $line[1] ), $valid_states ); $test_date = ctr_unifyDate( $line[2], $date_format ); $date_of_birth = $birthday_format !== false ? ctr_unifyDate( $line[ 5 + $o ], $birthday_format ) : ''; $meta = array( 'status' => $new_status, 'status_changed' => $test_date, 'created_at' => $test_date, 'trash' => 0 ); // var_dump($meta); $data = array( 'surname' => $line[ 3 + $o ], 'firstname' => $line[ 4 + $o ], 'dateofbirth' => $date_of_birth, 'email' => $line[ 6 + $o ], 'phone' => $line[ 7 + $o ], 'address' => $line[ 8 + $o ], 'passport' => $line[ 9 + $o ], 'tradename' => $line[ 10 + $o ], ); // var_dump( $data ); foreach ( $customfields as $id => $cf ) { $colNum = 11 + $o + $id; $data[$cf] = isset( $line[ $colNum ] ) ? $line[ $colNum ] : ''; } $returnData = corona_test_results_update_code_data( $line[0], $data, $pin, $meta ); // var_dump($returnData); $linesProcessedOK++; } } wp_send_json_success( array( 'total' => count( $parsed ), 'skipped' => $recordsSkipped, 'ok' => $linesProcessedOK, 'created' => $codesCreated, 'recordErrors' => $recordErrors ) ); } else { wp_send_json_error(array( 'error' => __( 'Column delimiter could not be determined', 'corona-test-results' ) ), 422); } } add_action( 'wp_ajax_corona_test_results_ajax_import_csv', 'corona_test_results_ajax_import_csv' );
[-] corona-test-results-admin.premium.php
[edit]
[-] corona-test-results-shortcodes.premium.php
[edit]
[+]
js
[-] corona-test-results-admin-locations.premium.php
[edit]
[-] corona-test-results-global.premium.php
[edit]
[+]
..
[-] LICENSE.txt
[edit]