/**
 * Process PayPal IPN
 *
 * @since 1.0
 * @return void
 */
function edd_process_paypal_ipn()
{
    // Check the request method is POST
    if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] != 'POST') {
        return;
    }
    // Set initial post data to empty string
    $post_data = '';
    // Fallback just in case post_max_size is lower than needed
    if (ini_get('allow_url_fopen')) {
        $post_data = file_get_contents('php://input');
    } else {
        // If allow_url_fopen is not enabled, then make sure that post_max_size is large enough
        ini_set('post_max_size', '12M');
    }
    // Start the encoded data collection with notification command
    $encoded_data = 'cmd=_notify-validate';
    // Get current arg separator
    $arg_separator = edd_get_php_arg_separator_output();
    // Verify there is a post_data
    if ($post_data || strlen($post_data) > 0) {
        // Append the data
        $encoded_data .= $arg_separator . $post_data;
    } else {
        // Check if POST is empty
        if (empty($_POST)) {
            // Nothing to do
            return;
        } else {
            // Loop through each POST
            foreach ($_POST as $key => $value) {
                // Encode the value and append the data
                $encoded_data .= $arg_separator . "{$key}=" . urlencode($value);
            }
        }
    }
    // Convert collected post data to an array
    parse_str($encoded_data, $encoded_data_array);
    // Get the PayPal redirect uri
    $paypal_redirect = edd_get_paypal_redirect(true);
    if (!edd_get_option('disable_paypal_verification')) {
        // Validate the IPN
        $remote_post_vars = array('method' => 'POST', 'timeout' => 45, 'redirection' => 5, 'httpversion' => '1.1', 'blocking' => true, 'headers' => array('host' => 'www.paypal.com', 'connection' => 'close', 'content-type' => 'application/x-www-form-urlencoded', 'post' => '/cgi-bin/webscr HTTP/1.1'), 'sslverify' => false, 'body' => $encoded_data_array);
        // Get response
        $api_response = wp_remote_post(edd_get_paypal_redirect(), $remote_post_vars);
        if (is_wp_error($api_response)) {
            edd_record_gateway_error(__('IPN Error', 'edd'), sprintf(__('Invalid IPN verification response. IPN data: %s', 'edd'), json_encode($api_response)));
            return;
            // Something went wrong
        }
        if ($api_response['body'] !== 'VERIFIED' && edd_get_option('disable_paypal_verification', false)) {
            edd_record_gateway_error(__('IPN Error', 'edd'), sprintf(__('Invalid IPN verification response. IPN data: %s', 'edd'), json_encode($api_response)));
            return;
            // Response not okay
        }
    }
    // Check if $post_data_array has been populated
    if (!is_array($encoded_data_array) && !empty($encoded_data_array)) {
        return;
    }
    $defaults = array('txn_type' => '', 'payment_status' => '');
    $encoded_data_array = wp_parse_args($encoded_data_array, $defaults);
    $payment_id = isset($encoded_data_array['custom']) ? absint($encoded_data_array['custom']) : 0;
    if (has_action('edd_paypal_' . $encoded_data_array['txn_type'])) {
        // Allow PayPal IPN types to be processed separately
        do_action('edd_paypal_' . $encoded_data_array['txn_type'], $encoded_data_array, $payment_id);
    } else {
        // Fallback to web accept just in case the txn_type isn't present
        do_action('edd_paypal_web_accept', $encoded_data_array, $payment_id);
    }
    exit;
}
/**
 * Process PayPal IPN
 *
 * @access      private
 * @since       1.0 
 * @return      void
*/
function edd_process_paypal_ipn()
{
    global $edd_options;
    // check the request method is POST
    if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] != 'POST') {
        return;
    }
    // set initial post data to false
    $post_data = false;
    // fallback just in case post_max_size is lower than needed
    if (ini_get('allow_url_fopen')) {
        $post_data = file_get_contents('php://input');
    } else {
        // if allow_url_fopen is not enabled, then make sure that post_max_size is large enough
        ini_set('post_max_size', '12M');
    }
    // start the encoded data collection with notification command
    $encoded_data = 'cmd=_notify-validate';
    // get current arg separator
    $arg_separator = edd_get_php_arg_separator_output();
    // verify there is a post_data
    if ($post_data || strlen($post_data) > 0) {
        // append the data
        $encoded_data .= $arg_separator . $post_data;
    } else {
        // check if POST is empty
        if (empty($_POST)) {
            // nothing to do
            return;
        } else {
            // loop trough each POST
            foreach ($_POST as $key => $value) {
                // encode the value and append the data
                $encoded_data .= $arg_separator . "{$key}=" . urlencode($value);
            }
        }
    }
    // convert collected post data to an array
    parse_str($encoded_data, $encoded_data_array);
    // get the PayPal redirect uri
    $paypal_redirect = edd_get_paypal_redirect(true);
    $remote_post_vars = array('method' => 'POST', 'timeout' => 45, 'redirection' => 5, 'httpversion' => '1.0', 'blocking' => true, 'headers' => array(), 'body' => $encoded_data_array);
    // get response
    $api_response = wp_remote_post(edd_get_paypal_redirect(), $remote_post_vars);
    if (is_wp_error($api_response)) {
        return;
    }
    // something went wrong
    if ($api_response['body'] !== 'VERIFIED' && !isset($edd_options['disable_paypal_verification'])) {
        return;
    }
    // response not okay
    // convert collected post data to an array
    parse_str($post_data, $post_data_array);
    // check if $post_data_array has been populated
    if (!is_array($encoded_data_array) && !empty($encoded_data_array)) {
        return;
    }
    // collect payment details
    $payment_id = $encoded_data_array['custom'];
    $purchase_key = $encoded_data_array['item_number'];
    $paypal_amount = $encoded_data_array['mc_gross'];
    $payment_status = $encoded_data_array['payment_status'];
    $currency_code = strtolower($encoded_data_array['mc_currency']);
    // retrieve the meta info for this payment
    $payment_meta = get_post_meta($payment_id, '_edd_payment_meta', true);
    $payment_amount = edd_format_amount($payment_meta['amount']);
    // verify details
    if ($currency_code != strtolower($edd_options['currency'])) {
        // the currency code is invalid
        return;
    }
    if (number_format((double) $paypal_amount, 2) != $payment_amount) {
        // the prices don't match
        //return;
    }
    if ($purchase_key != $payment_meta['key']) {
        // purchase keys don't match
        return;
    }
    if (isset($encoded_data_array['txn_type']) && $encoded_data_array['txn_type'] == 'web_accept') {
        $status = strtolower($payment_status);
        if ($status == 'completed' || edd_is_test_mode()) {
            edd_update_payment_status($payment_id, 'publish');
        }
    }
}
/**
 * Get system info
 *
 * @since       2.0
 * @access      public
 * @global      object $wpdb Used to query the database using the WordPress Database API
 * @return      string $return A string containing the info to output
 */
function edd_tools_sysinfo_get()
{
    global $wpdb;
    if (!class_exists('Browser')) {
        require_once EDD_PLUGIN_DIR . 'includes/libraries/browser.php';
    }
    $browser = new Browser();
    // Get theme info
    $theme_data = wp_get_theme();
    $theme = $theme_data->Name . ' ' . $theme_data->Version;
    // Try to identify the hosting provider
    $host = edd_get_host();
    $return = '### Begin System Info ###' . "\n\n";
    // Start with the basics...
    $return .= '-- Site Info' . "\n\n";
    $return .= 'Site URL:                 ' . site_url() . "\n";
    $return .= 'Home URL:                 ' . home_url() . "\n";
    $return .= 'Multisite:                ' . (is_multisite() ? 'Yes' : 'No') . "\n";
    $return = apply_filters('edd_sysinfo_after_site_info', $return);
    // Can we determine the site's host?
    if ($host) {
        $return .= "\n" . '-- Hosting Provider' . "\n\n";
        $return .= 'Host:                     ' . $host . "\n";
        $return = apply_filters('edd_sysinfo_after_host_info', $return);
    }
    // The local users' browser information, handled by the Browser class
    $return .= "\n" . '-- User Browser' . "\n\n";
    $return .= $browser;
    $return = apply_filters('edd_sysinfo_after_user_browser', $return);
    // WordPress configuration
    $return .= "\n" . '-- WordPress Configuration' . "\n\n";
    $return .= 'Version:                  ' . get_bloginfo('version') . "\n";
    $return .= 'Language:                 ' . (defined('WPLANG') && WPLANG ? WPLANG : 'en_US') . "\n";
    $return .= 'Permalink Structure:      ' . (get_option('permalink_structure') ? get_option('permalink_structure') : 'Default') . "\n";
    $return .= 'Active Theme:             ' . $theme . "\n";
    $return .= 'Show On Front:            ' . get_option('show_on_front') . "\n";
    // Only show page specs if frontpage is set to 'page'
    if (get_option('show_on_front') == 'page') {
        $front_page_id = get_option('page_on_front');
        $blog_page_id = get_option('page_for_posts');
        $return .= 'Page On Front:            ' . ($front_page_id != 0 ? get_the_title($front_page_id) . ' (#' . $front_page_id . ')' : 'Unset') . "\n";
        $return .= 'Page For Posts:           ' . ($blog_page_id != 0 ? get_the_title($blog_page_id) . ' (#' . $blog_page_id . ')' : 'Unset') . "\n";
    }
    $return .= 'ABSPATH:                  ' . ABSPATH . "\n";
    // Make sure wp_remote_post() is working
    $request['cmd'] = '_notify-validate';
    $params = array('sslverify' => false, 'timeout' => 60, 'user-agent' => 'EDD/' . EDD_VERSION, 'body' => $request);
    $response = wp_remote_post('https://www.paypal.com/cgi-bin/webscr', $params);
    if (!is_wp_error($response) && $response['response']['code'] >= 200 && $response['response']['code'] < 300) {
        $WP_REMOTE_POST = 'wp_remote_post() works';
    } else {
        $WP_REMOTE_POST = 'wp_remote_post() does not work';
    }
    $return .= 'Remote Post:              ' . $WP_REMOTE_POST . "\n";
    $return .= 'Table Prefix:             ' . 'Length: ' . strlen($wpdb->prefix) . '   Status: ' . (strlen($wpdb->prefix) > 16 ? 'ERROR: Too long' : 'Acceptable') . "\n";
    // Commented out per https://github.com/easydigitaldownloads/Easy-Digital-Downloads/issues/3475
    //$return .= 'Admin AJAX:               ' . ( edd_test_ajax_works() ? 'Accessible' : 'Inaccessible' ) . "\n";
    $return .= 'WP_DEBUG:                 ' . (defined('WP_DEBUG') ? WP_DEBUG ? 'Enabled' : 'Disabled' : 'Not set') . "\n";
    $return .= 'Memory Limit:             ' . WP_MEMORY_LIMIT . "\n";
    $return .= 'Registered Post Stati:    ' . implode(', ', get_post_stati()) . "\n";
    $return = apply_filters('edd_sysinfo_after_wordpress_config', $return);
    // EDD configuration
    $return .= "\n" . '-- EDD Configuration' . "\n\n";
    $return .= 'Version:                  ' . EDD_VERSION . "\n";
    $return .= 'Upgraded From:            ' . get_option('edd_version_upgraded_from', 'None') . "\n";
    $return .= 'Test Mode:                ' . (edd_is_test_mode() ? "Enabled\n" : "Disabled\n");
    $return .= 'AJAX:                     ' . (!edd_is_ajax_disabled() ? "Enabled\n" : "Disabled\n");
    $return .= 'Guest Checkout:           ' . (edd_no_guest_checkout() ? "Disabled\n" : "Enabled\n");
    $return .= 'Symlinks:                 ' . (apply_filters('edd_symlink_file_downloads', edd_get_option('symlink_file_downloads', false)) && function_exists('symlink') ? "Enabled\n" : "Disabled\n");
    $return .= 'Download Method:          ' . ucfirst(edd_get_file_download_method()) . "\n";
    $return .= 'Currency Code:            ' . edd_get_currency() . "\n";
    $return .= 'Currency Position:        ' . edd_get_option('currency_position', 'before') . "\n";
    $return .= 'Decimal Separator:        ' . edd_get_option('decimal_separator', '.') . "\n";
    $return .= 'Thousands Separator:      ' . edd_get_option('thousands_separator', ',') . "\n";
    $return .= 'Upgrades Completed:       ' . implode(',', edd_get_completed_upgrades()) . "\n";
    $return = apply_filters('edd_sysinfo_after_edd_config', $return);
    // EDD pages
    $purchase_page = edd_get_option('purchase_page', '');
    $success_page = edd_get_option('success_page', '');
    $failure_page = edd_get_option('failure_page', '');
    $return .= "\n" . '-- EDD Page Configuration' . "\n\n";
    $return .= 'Checkout:                 ' . (!empty($purchase_page) ? "Valid\n" : "Invalid\n");
    $return .= 'Checkout Page:            ' . (!empty($purchase_page) ? get_permalink($purchase_page) . "\n" : "Unset\n");
    $return .= 'Success Page:             ' . (!empty($success_page) ? get_permalink($success_page) . "\n" : "Unset\n");
    $return .= 'Failure Page:             ' . (!empty($failure_page) ? get_permalink($failure_page) . "\n" : "Unset\n");
    $return .= 'Downloads Slug:           ' . (defined('EDD_SLUG') ? '/' . EDD_SLUG . "\n" : "/downloads\n");
    $return = apply_filters('edd_sysinfo_after_edd_pages', $return);
    // EDD gateways
    $return .= "\n" . '-- EDD Gateway Configuration' . "\n\n";
    $active_gateways = edd_get_enabled_payment_gateways();
    if ($active_gateways) {
        $default_gateway_is_active = edd_is_gateway_active(edd_get_default_gateway());
        if ($default_gateway_is_active) {
            $default_gateway = edd_get_default_gateway();
            $default_gateway = $active_gateways[$default_gateway]['admin_label'];
        } else {
            $default_gateway = 'Test Payment';
        }
        $gateways = array();
        foreach ($active_gateways as $gateway) {
            $gateways[] = $gateway['admin_label'];
        }
        $return .= 'Enabled Gateways:         ' . implode(', ', $gateways) . "\n";
        $return .= 'Default Gateway:          ' . $default_gateway . "\n";
    } else {
        $return .= 'Enabled Gateways:         None' . "\n";
    }
    $return = apply_filters('edd_sysinfo_after_edd_gateways', $return);
    // EDD Taxes
    $return .= "\n" . '-- EDD Tax Configuration' . "\n\n";
    $return .= 'Taxes:                    ' . (edd_use_taxes() ? "Enabled\n" : "Disabled\n");
    $return .= 'Tax Rate:                 ' . edd_get_tax_rate() * 100 . "\n";
    $return .= 'Display On Checkout:      ' . (edd_get_option('checkout_include_tax', false) ? "Displayed\n" : "Not Displayed\n");
    $return .= 'Prices Include Tax:       ' . (edd_prices_include_tax() ? "Yes\n" : "No\n");
    $rates = edd_get_tax_rates();
    if (!empty($rates)) {
        $return .= 'Country / State Rates:    ' . "\n";
        foreach ($rates as $rate) {
            $return .= '                          Country: ' . $rate['country'] . ', State: ' . $rate['state'] . ', Rate: ' . $rate['rate'] . "\n";
        }
    }
    $return = apply_filters('edd_sysinfo_after_edd_taxes', $return);
    // EDD Templates
    $dir = get_stylesheet_directory() . '/edd_templates/*';
    if (is_dir($dir) && count(glob("{$dir}/*")) !== 0) {
        $return .= "\n" . '-- EDD Template Overrides' . "\n\n";
        foreach (glob($dir) as $file) {
            $return .= 'Filename:                 ' . basename($file) . "\n";
        }
        $return = apply_filters('edd_sysinfo_after_edd_templates', $return);
    }
    // Get plugins that have an update
    $updates = get_plugin_updates();
    // Must-use plugins
    // NOTE: MU plugins can't show updates!
    $muplugins = get_mu_plugins();
    if (count($muplugins) > 0) {
        $return .= "\n" . '-- Must-Use Plugins' . "\n\n";
        foreach ($muplugins as $plugin => $plugin_data) {
            $return .= $plugin_data['Name'] . ': ' . $plugin_data['Version'] . "\n";
        }
        $return = apply_filters('edd_sysinfo_after_wordpress_mu_plugins', $return);
    }
    // WordPress active plugins
    $return .= "\n" . '-- WordPress Active Plugins' . "\n\n";
    $plugins = get_plugins();
    $active_plugins = get_option('active_plugins', array());
    foreach ($plugins as $plugin_path => $plugin) {
        if (!in_array($plugin_path, $active_plugins)) {
            continue;
        }
        $update = array_key_exists($plugin_path, $updates) ? ' (needs update - ' . $updates[$plugin_path]->update->new_version . ')' : '';
        $return .= $plugin['Name'] . ': ' . $plugin['Version'] . $update . "\n";
    }
    $return = apply_filters('edd_sysinfo_after_wordpress_plugins', $return);
    // WordPress inactive plugins
    $return .= "\n" . '-- WordPress Inactive Plugins' . "\n\n";
    foreach ($plugins as $plugin_path => $plugin) {
        if (in_array($plugin_path, $active_plugins)) {
            continue;
        }
        $update = array_key_exists($plugin_path, $updates) ? ' (needs update - ' . $updates[$plugin_path]->update->new_version . ')' : '';
        $return .= $plugin['Name'] . ': ' . $plugin['Version'] . $update . "\n";
    }
    $return = apply_filters('edd_sysinfo_after_wordpress_plugins_inactive', $return);
    if (is_multisite()) {
        // WordPress Multisite active plugins
        $return .= "\n" . '-- Network Active Plugins' . "\n\n";
        $plugins = wp_get_active_network_plugins();
        $active_plugins = get_site_option('active_sitewide_plugins', array());
        foreach ($plugins as $plugin_path) {
            $plugin_base = plugin_basename($plugin_path);
            if (!array_key_exists($plugin_base, $active_plugins)) {
                continue;
            }
            $update = array_key_exists($plugin_path, $updates) ? ' (needs update - ' . $updates[$plugin_path]->update->new_version . ')' : '';
            $plugin = get_plugin_data($plugin_path);
            $return .= $plugin['Name'] . ': ' . $plugin['Version'] . $update . "\n";
        }
        $return = apply_filters('edd_sysinfo_after_wordpress_ms_plugins', $return);
    }
    // Server configuration (really just versioning)
    $return .= "\n" . '-- Webserver Configuration' . "\n\n";
    $return .= 'PHP Version:              ' . PHP_VERSION . "\n";
    $return .= 'MySQL Version:            ' . $wpdb->db_version() . "\n";
    $return .= 'Webserver Info:           ' . $_SERVER['SERVER_SOFTWARE'] . "\n";
    $return = apply_filters('edd_sysinfo_after_webserver_config', $return);
    // PHP configs... now we're getting to the important stuff
    $return .= "\n" . '-- PHP Configuration' . "\n\n";
    $return .= 'Safe Mode:                ' . (ini_get('safe_mode') ? 'Enabled' : 'Disabled' . "\n");
    $return .= 'Memory Limit:             ' . ini_get('memory_limit') . "\n";
    $return .= 'Upload Max Size:          ' . ini_get('upload_max_filesize') . "\n";
    $return .= 'Post Max Size:            ' . ini_get('post_max_size') . "\n";
    $return .= 'Upload Max Filesize:      ' . ini_get('upload_max_filesize') . "\n";
    $return .= 'Time Limit:               ' . ini_get('max_execution_time') . "\n";
    $return .= 'Max Input Vars:           ' . ini_get('max_input_vars') . "\n";
    $return .= 'Display Errors:           ' . (ini_get('display_errors') ? 'On (' . ini_get('display_errors') . ')' : 'N/A') . "\n";
    $return .= 'PHP Arg Separator:        ' . edd_get_php_arg_separator_output() . "\n";
    $return = apply_filters('edd_sysinfo_after_php_config', $return);
    // PHP extensions and such
    $return .= "\n" . '-- PHP Extensions' . "\n\n";
    $return .= 'cURL:                     ' . (function_exists('curl_init') ? 'Supported' : 'Not Supported') . "\n";
    $return .= 'fsockopen:                ' . (function_exists('fsockopen') ? 'Supported' : 'Not Supported') . "\n";
    $return .= 'SOAP Client:              ' . (class_exists('SoapClient') ? 'Installed' : 'Not Installed') . "\n";
    $return .= 'Suhosin:                  ' . (extension_loaded('suhosin') ? 'Installed' : 'Not Installed') . "\n";
    $return = apply_filters('edd_sysinfo_after_php_ext', $return);
    // Session stuff
    $return .= "\n" . '-- Session Configuration' . "\n\n";
    $return .= 'EDD Use Sessions:         ' . (defined('EDD_USE_PHP_SESSIONS') && EDD_USE_PHP_SESSIONS ? 'Enforced' : (EDD()->session->use_php_sessions() ? 'Enabled' : 'Disabled')) . "\n";
    $return .= 'Session:                  ' . (isset($_SESSION) ? 'Enabled' : 'Disabled') . "\n";
    // The rest of this is only relevant is session is enabled
    if (isset($_SESSION)) {
        $return .= 'Session Name:             ' . esc_html(ini_get('session.name')) . "\n";
        $return .= 'Cookie Path:              ' . esc_html(ini_get('session.cookie_path')) . "\n";
        $return .= 'Save Path:                ' . esc_html(ini_get('session.save_path')) . "\n";
        $return .= 'Use Cookies:              ' . (ini_get('session.use_cookies') ? 'On' : 'Off') . "\n";
        $return .= 'Use Only Cookies:         ' . (ini_get('session.use_only_cookies') ? 'On' : 'Off') . "\n";
    }
    $return = apply_filters('edd_sysinfo_after_session_config', $return);
    $return .= "\n" . '### End System Info ###';
    return $return;
}
/**
 * Process PayPal IPN
 *
 * @access      private
 * @since       1.0
 * @return      void
*/
function edd_process_paypal_ipn()
{
    global $edd_options;
    // check the request method is POST
    if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] != 'POST') {
        return;
    }
    // set initial post data to false
    $post_data = false;
    // fallback just in case post_max_size is lower than needed
    if (ini_get('allow_url_fopen')) {
        $post_data = file_get_contents('php://input');
    } else {
        // if allow_url_fopen is not enabled, then make sure that post_max_size is large enough
        ini_set('post_max_size', '12M');
    }
    // start the encoded data collection with notification command
    $encoded_data = 'cmd=_notify-validate';
    // get current arg separator
    $arg_separator = edd_get_php_arg_separator_output();
    // verify there is a post_data
    if ($post_data || strlen($post_data) > 0) {
        // append the data
        $encoded_data .= $arg_separator . $post_data;
    } else {
        // check if POST is empty
        if (empty($_POST)) {
            // nothing to do
            return;
        } else {
            // loop trough each POST
            foreach ($_POST as $key => $value) {
                // encode the value and append the data
                $encoded_data .= $arg_separator . "{$key}=" . urlencode($value);
            }
        }
    }
    // convert collected post data to an array
    parse_str($encoded_data, $encoded_data_array);
    // get the PayPal redirect uri
    $paypal_redirect = edd_get_paypal_redirect(true);
    $remote_post_vars = array('method' => 'POST', 'timeout' => 45, 'redirection' => 5, 'httpversion' => '1.0', 'blocking' => true, 'headers' => array(), 'sslverify' => false, 'body' => $encoded_data_array);
    // get response
    $api_response = wp_remote_post(edd_get_paypal_redirect(), $remote_post_vars);
    if (is_wp_error($api_response)) {
        edd_record_gateway_error(__('IPN Error', 'edd'), sprintf(__('Invalid IPN verification response. IPN data: ', 'edd'), json_encode($api_response)));
        return;
        // something went wrong
    }
    if ($api_response['body'] !== 'VERIFIED' && !isset($edd_options['disable_paypal_verification'])) {
        edd_record_gateway_error(__('IPN Error', 'edd'), sprintf(__('Invalid IPN verification response. IPN data: ', 'edd'), json_encode($api_response)));
        return;
        // response not okay
    }
    // check if $post_data_array has been populated
    if (!is_array($encoded_data_array) && !empty($encoded_data_array)) {
        return;
    }
    if (has_action('edd_paypal_' . $encoded_data_array['txn_type'])) {
        // allow PayPal IPN types to be processed separately
        do_action('edd_paypal_' . $encoded_data_array['txn_type'], $encoded_data_array);
    } else {
        // fallback to web accept just in case the txn_type isn't present
        do_action('edd_paypal_web_accept', $encoded_data_array);
    }
}