Files
torebki-fabiola.pl/wp-content/plugins/email-subscribers/lite/includes/classes/class-es-export-subscribers.php
2026-03-05 13:07:40 +01:00

447 lines
14 KiB
PHP

<?php
// Exit if accessed directly
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* CSV Exporter bootstrap file
*/
class Export_Subscribers {
/**
* Constructor
*/
public function __construct() {
$report = ig_es_get_request_data( 'report' );
$status = ig_es_get_request_data( 'status' );
$link_id = ig_es_get_request_data( 'link_id' );
$campaign_id = ig_es_get_request_data( 'campaign_id' );
$can_access = ES_Common::ig_es_can_access( 'audience' );
$can_access_campaign = ES_Common::ig_es_can_access( 'campaigns' );
$export_nonce = ig_es_get_request_data('export-nonce');
if (wp_verify_nonce($export_nonce, 'ig-es-subscriber-export-nonce')) {
if ($report && $status && $can_access) {
$status = trim( $status );
$selected_list_id = 0;
if ( 'select_list' === $status ) {
$selected_list_id = ig_es_get_request_data( 'list_id', 0 );
if ( 0 === $selected_list_id ) {
$this->show_error_message(__('Please select list', 'email-subscribers'));
}
}
$csv = $this->generate_csv($status, $selected_list_id);
$file_name = sprintf('%s-contacts.csv', strtolower($status));
$this->output_CSV($csv, $file_name);
} elseif ($report && $link_id && $campaign_id && $can_access_campaign) {
$subscribers = ES()->actions_db->get_link_cliked_subscribers($campaign_id, $link_id);
if ( count( $subscribers ) > 0 ) {
$sub_headers = [
__('First Name', 'email-subscribers'),
__('Last Name', 'email-subscribers'),
__('Email', 'email-subscribers'),
];
$csv = implode(',', $sub_headers);
$csv.="\n";
foreach ($subscribers as $subscriber) {
$data = [
'first_name' => $this->escape_and_trim_data($subscriber['first_name']),
'last_name' => $this->escape_and_trim_data($subscriber['last_name']),
'email' => $this->escape_and_trim_data($subscriber['email']),
];
$csv .= '"' . implode('","', $data) . "\"\n";
}
}
if (empty($csv)) {
$this->show_error_message(__('No data available', 'email-subscribers'));
}
$this->output_CSV($csv, 'subscriber-contacts.csv');
}
}
add_filter( 'query_vars', array( $this, 'query_vars' ) );
add_action( 'parse_request', array( $this, 'parse_request' ) );
add_action( 'admin_menu', array( $this, 'plugin_menu' ) );
}
private function show_error_message( $message) {
ES_Common::show_message($message, 'error');
exit();
}
private function escape_and_trim_data( $data) {
return trim(str_replace('"', '""', $this->escape_data($data)));
}
private function output_CSV( $csv_content, $file_name) {
header('Pragma: public');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Cache-Control: private', false);
header('Content-Type: application/octet-stream');
header("Content-Disposition: attachment; filename=$file_name");
header('Content-Transfer-Encoding: binary');
echo wp_kses_post($csv_content);
exit();
}
public function plugin_menu() {
add_submenu_page( null, 'Export Contacts', __( 'Export Contacts', 'email-subscribers' ), 'edit_posts', 'es_export_subscribers', array( $this, 'export_subscribers_page' ) );
}
public function prepare_header_footer_row() {
?>
<tr class="bg-gray-100 text-sm text-left leading-4 text-gray-500 tracking-wider border-b border-t border-gray-200 ">
<th class="w-1/12 pl-8 py-4 font-medium" scope="col"><?php esc_html_e( 'No.', 'email-subscribers' ); ?></th>
<th class="w-2/12 pl-4 py-4 font-medium" scope="col"><?php esc_html_e( 'Contacts', 'email-subscribers' ); ?></th>
<th class="w-2/12 pl-8 py-4 font-medium" scope="col"><?php esc_html_e( 'Total contacts', 'email-subscribers' ); ?></th>
<th class="w-2/12 pl-16 py-4 font-medium" scope="col"><?php esc_html_e( 'Export', 'email-subscribers' ); ?></th>
</tr>
<?php
}
public function prepare_body() {
$list_dropdown_html = "<select class='form-select sm:w-32 lg:w-40' name='list_id' id='ig_es_export_list_dropdown'>";
$list_dropdown_html .= ES_Common::prepare_list_dropdown_options();
$list_dropdown_html .= '</select>';
$export_lists = array(
'all' => __( 'All contacts', 'email-subscribers' ),
'subscribed' => __( 'Subscribed contacts', 'email-subscribers' ),
'unsubscribed' => __( 'Unsubscribed contacts', 'email-subscribers' ),
'unconfirmed' => __( 'Unconfirmed contacts', 'email-subscribers' ),
'select_list' => $list_dropdown_html,
);
$i = 1;
$export_nonce = wp_create_nonce( 'ig-es-subscriber-export-nonce' );
foreach ( $export_lists as $key => $export_list ) {
$url = "admin.php?page=download_report&report=users&status={$key}&export-nonce={$export_nonce}";
?>
<tr class="border-b text-sm font-normal text-gray-700 border-gray-200" id="ig_es_export_<?php echo esc_attr( $key ); ?>">
<td class="py-2 pl-10 w-1/12"><?php echo esc_html( $i ); ?></td>
<td class="py-2 pl-4 w-2/12">
<?php
$allowedtags = ig_es_allowed_html_tags_in_esc();
echo wp_kses( $export_list, $allowedtags );
?>
</td>
<td class="py-2 pl-8 w-2/12 font-medium ig_es_total_contacts"><?php echo esc_html( $this->count_subscribers( $key ) ); ?></td>
<td class="py-2 pl-8 w-2/12">
<div class="inline-flex pl-10"><a href="<?php echo esc_url( $url ); ?>" id="ig_es_export_link_<?php echo esc_attr( $key ); ?>">
<svg fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" viewBox="0 0 24 24" class="w-8 h-8 text-indigo-600 hover:text-indigo-500 active:text-indigo-600"><path d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
</svg>
</a>
</div>
</td>
</tr>
<?php
$i ++;
}
}
public function export_subscribers_page() {
$audience_tab_main_navigation = array();
$active_tab = 'export';
$audience_tab_main_navigation = apply_filters( 'ig_es_audience_tab_main_navigation', $active_tab, $audience_tab_main_navigation );
?>
<div class="max-w-full -mt-3 font-sans">
<header class="wp-heading-inline">
<div class="flex">
<div>
<nav class="text-gray-400 my-0" aria-label="Breadcrumb">
<ol class="list-none p-0 inline-flex">
<li class="flex items-center text-sm tracking-wide">
<a class="hover:underline " href="admin.php?page=es_subscribers"><?php esc_html_e( 'Audience ', 'email-subscribers' ); ?></a>
<svg class="fill-current w-2.5 h-2.5 mx-2 mt-mx" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512"><path d="M285.476 272.971L91.132 467.314c-9.373 9.373-24.569 9.373-33.941 0l-22.667-22.667c-9.357-9.357-9.375-24.522-.04-33.901L188.505 256 34.484 101.255c-9.335-9.379-9.317-24.544.04-33.901l22.667-22.667c9.373-9.373 24.569-9.373 33.941 0L285.475 239.03c9.373 9.372 9.373 24.568.001 33.941z"></path></svg>
</li>
</ol>
</nav>
<h2 class="-mt-1.5 text-2xl font-medium text-gray-700 sm:leading-7 sm:truncate"> <?php esc_html_e( 'Export Contacts', 'email-subscribers' ); ?>
</h2>
</div>
<div class="mt-4 ml-2">
<?php
ES_Common::prepare_main_header_navigation( $audience_tab_main_navigation );
?>
</div>
</div>
</header>
<div><hr class="wp-header-end"></div>
<div class="mt-8 shadow rounded-lg overflow-hidden">
<form name="frm_es_subscriberexport" method="post">
<table class="min-w-full" id="straymanage">
<thead>
<?php $this->prepare_header_footer_row(); ?>
</thead>
<tbody class="bg-white">
<?php $this->prepare_body(); ?>
</tbody>
<tfoot>
<?php $this->prepare_header_footer_row(); ?>
</tfoot>
</table>
</form>
</div>
<?php
}
/**
* Count total subscribers
*
* @param string $status
*
* @return string|null
*/
public function count_subscribers( $status = 'all' ) {
global $wpdb;
switch ( $status ) {
case 'all':
return ES()->lists_contacts_db->get_all_contacts_count( 0, false );
break;
case 'subscribed':
return ES()->lists_contacts_db->get_subscribed_contacts_count( 0, false );
break;
case 'unsubscribed':
return ES()->lists_contacts_db->get_unsubscribed_contacts_count( 0, false );
break;
case 'confirmed':
return ES()->lists_contacts_db->get_confirmed_contacts_count( 0, false );
break;
case 'unconfirmed':
return ES()->lists_contacts_db->get_unconfirmed_contacts_count( 0, false );
break;
case 'select_list':
default:
return '-';
break;
}
}
/**
* Allow for custom query variables
*/
public function query_vars( $query_vars ) {
$query_vars[] = 'download_report';
return $query_vars;
}
/**
* Parse the request
*/
public function parse_request( &$wp ) {
if ( array_key_exists( 'download_report', $wp->query_vars ) ) {
$this->download_report();
exit;
}
}
/**
* Download report
*/
public function download_report() {
?>
<div class="wrap">
<div id="icon-tools" class="icon32"></div>
<h2>Download Report</h2>
<p>
<a href="?page=download_report&report=users"><?php esc_html_e( 'Export the Subscribers', 'email-subscribers' ); ?></a>
</p>
<?php
}
/**
* Generate CSV
* first_name, last_name, email, status, list, subscribed_at, unsubscribed_at
*
* @param string $status
* @param string $list_id
*
* @return string
*/
public function generate_csv( $status = 'all', $list_id = 0 ) {
global $wpbd;
// Add filter to increase memory limit
add_filter( 'ig_es_memory_limit', 'ig_es_increase_memory_limit' );
wp_raise_memory_limit( 'ig_es' );
// Remove the added filter function so that it won't be called again if wp_raise_memory_limit called later on.
remove_filter( 'ig_es_memory_limit', 'ig_es_increase_memory_limit' );
set_time_limit( IG_SET_TIME_LIMIT );
$results = array();
if ( 'all' === $status ) {
$results = ES()->lists_contacts_db->get_all_contacts();
} elseif ( 'subscribed' === $status ) {
$results = ES()->lists_contacts_db->get_all_subscribed_contacts();
} elseif ( 'unsubscribed' === $status ) {
$results = ES()->lists_contacts_db->get_all_unsubscribed_contacts();
} elseif ( 'confirmed' === $status ) {
$results = ES()->lists_contacts_db->get_all_confirmed_contacts();
} elseif ( 'unconfirmed' === $status ) {
$results = ES()->lists_contacts_db->get_all_unconfirmed_contacts();
} elseif ( 'select_list' === $status ) {
$list_id = absint( $list_id );
$results = ES()->lists_contacts_db->get_all_contacts_from_list( $list_id );
}
$subscribers = array();
if ( count( $results ) > 0 ) {
$contact_list_map = array();
$contact_ids = array();
foreach ( $results as $result ) {
if ( ! in_array( $result['contact_id'], $contact_ids, true ) ) {
$contact_ids[] = $result['contact_id'];
}
$contact_list_map[ $result['contact_id'] ][] = array(
'status' => $result['status'],
'list_id' => $result['list_id'],
'optin_type' => $result['optin_type'],
);
}
$contact_ids_str = implode( ',', $contact_ids );
$select_columns = array(
'id',
'first_name',
'last_name',
'email',
'created_at',
);
$custom_fields = ES()->custom_fields_db->get_custom_fields();
if ( ! empty( $custom_fields ) ) {
foreach ( $custom_fields as $field ) {
$select_columns[] = $field['slug'];
}
}
$query = 'SELECT ' . implode( ',', $select_columns ) . " FROM {$wpbd->prefix}ig_contacts WHERE id IN ({$contact_ids_str})";
$subscribers = $wpbd->get_results( $query, ARRAY_A );
}
$csv_output = '';
if ( count( $subscribers ) > 0 ) {
$headers = array(
__( 'First Name', 'email-subscribers' ),
__( 'Last Name', 'email-subscribers' ),
__( 'Email', 'email-subscribers' ),
__( 'List', 'email-subscribers' ),
__( 'Status', 'email-subscribers' ),
__( 'Opt-In Type', 'email-subscribers' ),
__( 'Created On', 'email-subscribers' ),
);
if ( ! empty( $custom_fields ) ) {
foreach ( $custom_fields as $field ) {
$headers[] = $field['label'];
}
}
$lists_id_name_map = ES()->lists_db->get_list_id_name_map();
$csv_output .= implode( ',', $headers );
foreach ( $subscribers as $key => $subscriber ) {
$data = array();
$data['first_name'] = trim( str_replace( '"', '""', $this->escape_data( $subscriber['first_name'] ) ) );
$data['last_name'] = trim( str_replace( '"', '""', $this->escape_data( $subscriber['last_name'] ) ) );
$data['email'] = trim( str_replace( '"', '""', $this->escape_data( $subscriber['email'] ) ) );
$contact_id = $subscriber['id'];
if ( ! empty( $contact_list_map[ $contact_id ] ) ) {
foreach ( $contact_list_map[ $contact_id ] as $list_details ) {
$data['list'] = $lists_id_name_map[ $list_details['list_id'] ];
$data['status'] = ucfirst( $list_details['status'] );
$data['optin_type'] = ( 1 == $list_details['optin_type'] ) ? 'Single Opt-In' : 'Double Opt-In';
$data['created_at'] = $subscriber['created_at'];
if ( ! empty( $custom_fields ) ) {
foreach ( $custom_fields as $field ) {
$column_name = $field['slug'];
$data[ $column_name ] = $subscriber[ $column_name ];
}
}
$csv_output .= "\n";
$csv_output .= '"' . implode( '","', $data ) . '"';
}
}
}
}
return $csv_output;
}
/**
* Escape a string to be used in a CSV context
*
* Malicious input can inject formulas into CSV files, opening up the possibility
* for phishing attacks and disclosure of sensitive information.
*
* Additionally, Excel exposes the ability to launch arbitrary commands through
* the DDE protocol.
*
* @see http://www.contextis.com/resources/blog/comma-separated-vulnerabilities/
* @see https://hackerone.com/reports/72785
*
* @since 5.5.3
* @param string $data CSV field to escape.
* @return string
*/
public function escape_data( $data ) {
$active_content_triggers = array( '=', '+', '-', '@' );
if ( in_array( mb_substr( $data, 0, 1 ), $active_content_triggers, true ) ) {
$data = "'" . $data;
}
return $data;
}
}