s2Member Framework (Member Roles, Capabilities, Membership, PayPal Members) - Version 2.9

Version Description

  • This release is all about security and bug fixes, with very few feature additions.
  • Bug fix, %%registration_url%% in the Signup Confirmation Email was being replaced with 1, instead of the full URL. This bug was first introduced in s2Member v2.8.7. This has been corrected in v2.9.
  • s2Member now uses MCRYPT_RIJNDAEL_256 / CBC through mcrypt_encrypt() when it's available on your server. XOR encryption is used as a fallback for hosts that do not have the mcrypt extension installed. The MCRYPT_RIJNDAEL_256 algorithm provides much better security.
  • A full security review of s2Member has been completed, in anticipation of the s2Member Pro Module; being released later this month ( May 2010 ). A new panel under: s2Member -> General Options -> Security Encryption Key should be configured. Just click the auto-generate button there. s2Member will assign a special Security Key to your installation.
  • Please join us in discussion. A new Support Forum has been created for s2Member ( May 2010 ). Feel free to submit code samples, error messages, feature requests, etc.
  • Please report all bugs. If you have any trouble with this release, you can always revert back to a previous version until the issue is corrected.
Download this release

Release Info

Developer PriMoThemes
Plugin Icon 128x128 s2Member Framework (Member Roles, Capabilities, Membership, PayPal Members)
Version 2.9
Comparing to
See all releases

Code changes from version 2.8.9 to 2.9

images/brand-support.fla ADDED
Binary file
images/brand-support.png ADDED
Binary file
images/brand-tips.fla DELETED
Binary file
images/brand-tips.png DELETED
Binary file
includes/functions/activate-deactivate.inc.php CHANGED
@@ -112,13 +112,13 @@ function ws_plugin__s2member_activate ()
112
  /**/
113
  if (get_option ("ws_plugin__s2member_configured")) /* If they already have s2Member configured, read the Changelog. */
114
  {
115
- $notice = '<strong>s2Member</strong> has been <strong>re-activated</strong>, with the latest version.<br />';
116
  $notice .= 'Have fun, <a href="admin.php?page=ws-plugin--s2member-info">read the Changelog</a>, and make some money! :-)';
117
  ws_plugin__s2member_enqueue_admin_notice ($notice, array ("plugins.php", "ws-plugin--s2member-options"));
118
  }
119
  else /* Otherwise, we'll help the site owner out by giving them a link to the Quick Start Guide. */
120
  {
121
- $notice = '<strong>s2Member</strong> has been <strong>activated</strong>, with the latest version.<br />';
122
  $notice .= 'Have fun, <a href="admin.php?page=ws-plugin--s2member-start">read the Quick Start Guide</a>, and make some money! :-)';
123
  ws_plugin__s2member_enqueue_admin_notice ($notice, array ("plugins.php", "ws-plugin--s2member-options"));
124
  }
112
  /**/
113
  if (get_option ("ws_plugin__s2member_configured")) /* If they already have s2Member configured, read the Changelog. */
114
  {
115
+ $notice = '<strong>s2Member</strong> has been <strong>re-activated</strong>, with the latest version. Your existing configuration remains intact.<br />';
116
  $notice .= 'Have fun, <a href="admin.php?page=ws-plugin--s2member-info">read the Changelog</a>, and make some money! :-)';
117
  ws_plugin__s2member_enqueue_admin_notice ($notice, array ("plugins.php", "ws-plugin--s2member-options"));
118
  }
119
  else /* Otherwise, we'll help the site owner out by giving them a link to the Quick Start Guide. */
120
  {
121
+ $notice = '<strong>s2Member</strong> has been <strong>activated</strong>, with the latest version. Nice work!<br />';
122
  $notice .= 'Have fun, <a href="admin.php?page=ws-plugin--s2member-start">read the Quick Start Guide</a>, and make some money! :-)';
123
  ws_plugin__s2member_enqueue_admin_notice ($notice, array ("plugins.php", "ws-plugin--s2member-options"));
124
  }
includes/functions/constants.inc.php CHANGED
@@ -88,7 +88,7 @@ function ws_plugin__s2member_constants ()
88
  define ("S2MEMBER_PAYPAL_ENDPOINT", (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_sandbox"]) ? "www.sandbox.paypal.com" : "www.paypal.com")); /* Using sandbox? */
89
  define ("S2MEMBER_PAYPAL_BUSINESS", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_business"]); /* This is the email address that identifies your paypal business. */
90
  /**/
91
- define ("S2MEMBER_CURRENT_USER_VALUE_FOR_PP_ON0", ((S2MEMBER_CURRENT_USER_SUBSCR_ID) ? "Updating Subscr" : "")); /* Auto-fills the on0 value in PayPal buttons. */
92
  define ("S2MEMBER_CURRENT_USER_VALUE_FOR_PP_OS0", ((S2MEMBER_CURRENT_USER_VALUE_FOR_PP_ON0) ? S2MEMBER_CURRENT_USER_SUBSCR_ID : "")); /* For the os0 value. */
93
  /**/
94
  do_action ("s2member_after_constants");
88
  define ("S2MEMBER_PAYPAL_ENDPOINT", (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_sandbox"]) ? "www.sandbox.paypal.com" : "www.paypal.com")); /* Using sandbox? */
89
  define ("S2MEMBER_PAYPAL_BUSINESS", $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["paypal_business"]); /* This is the email address that identifies your paypal business. */
90
  /**/
91
+ define ("S2MEMBER_CURRENT_USER_VALUE_FOR_PP_ON0", ((S2MEMBER_CURRENT_USER_SUBSCR_ID) ? "Updating Subscr. ID" : "")); /* Auto-fills the on0 value in PayPal buttons. */
92
  define ("S2MEMBER_CURRENT_USER_VALUE_FOR_PP_OS0", ((S2MEMBER_CURRENT_USER_VALUE_FOR_PP_ON0) ? S2MEMBER_CURRENT_USER_SUBSCR_ID : "")); /* For the os0 value. */
93
  /**/
94
  do_action ("s2member_after_constants");
includes/functions/file-download-access.inc.php CHANGED
@@ -124,9 +124,11 @@ function ws_plugin__s2member_check_file_download_access ()
124
  /**/
125
  if ($_GET["s2member_file_download"]) /* Filter $excluded to force free downloads. */
126
  {
127
- $excluded = apply_filters ("s2member_check_file_download_access_excluded", false); /* Or use $_GET["s2member_free_file_download_key"]. */
128
  /**/
129
- if (!$excluded && (!$_GET["s2member_free_file_download_key"] || ws_plugin__s2member_xdecrypt ($_GET["s2member_free_file_download_key"]) !== $_GET["s2member_file_download"]))
 
 
130
  {
131
  $_GET["s2member_file_download"] = trim ($_GET["s2member_file_download"], "/");
132
  /**/
124
  /**/
125
  if ($_GET["s2member_file_download"]) /* Filter $excluded to force free downloads. */
126
  {
127
+ $excluded = apply_filters ("s2member_check_file_download_access_excluded", false); /* Or use $_GET["s2member_free_file_download_key"] with a hash of the xencrypted version. */
128
  /**/
129
+ if (!$excluded && (!$_GET["s2member_free_file_download_key"] || ($_GET["s2member_free_file_download_key"] !== md5 (ws_plugin__s2member_xencrypt ($_GET["s2member_file_download"]))/**/
130
+ /* For backward compatiblity, we also check the xencrypted value, without the hash. This is decprecated as of v2.9. It will be removed completely in a future version. */
131
+ && $_GET["s2member_free_file_download_key"] !== ws_plugin__s2member_xencrypt ($_GET["s2member_file_download"]))))
132
  {
133
  $_GET["s2member_file_download"] = trim ($_GET["s2member_file_download"], "/");
134
  /**/
includes/functions/login-redirection.inc.php CHANGED
@@ -17,16 +17,13 @@ if (realpath (__FILE__) === realpath ($_SERVER["SCRIPT_FILENAME"]))
17
  Function for handling login redirections.
18
  Attach to: add_action("wp_login");
19
  */
20
- function ws_plugin__s2member_login_redirect ()
21
  {
22
- /* Note that current_user_can() will not work here because the cookie was just set. */
23
- global $user; /* Available during the login routine just before wp_login is hooked in. */
24
- /**/
25
  do_action ("s2member_before_login_redirect");
26
  /**/
27
- $uzer = new WP_User ($user->ID); /* Now lets get a user object to check Capabilities. */
28
  /**/
29
- if (!$uzer->has_cap ("edit_posts")) /* In other words, all Subscribers & Members. */
30
  {
31
  do_action ("s2member_during_login_redirect");
32
  /**/
17
  Function for handling login redirections.
18
  Attach to: add_action("wp_login");
19
  */
20
+ function ws_plugin__s2member_login_redirect ($username = FALSE)
21
  {
 
 
 
22
  do_action ("s2member_before_login_redirect");
23
  /**/
24
+ $user = new WP_User ($username); /* Get user object reference. */
25
  /**/
26
+ if (!$user->has_cap ("edit_posts")) /* In other words, all Subscribers & Members. */
27
  {
28
  do_action ("s2member_during_login_redirect");
29
  /**/
includes/functions/menu-pages.inc.php CHANGED
@@ -68,17 +68,17 @@ function ws_plugin__s2member_add_admin_options ()
68
  /**/
69
  add_filter ("plugin_action_links", "_ws_plugin__s2member_add_settings_link", 10, 2);
70
  /**/
71
- add_menu_page ("s2Member Options", "s2Member", "edit_plugins", "ws-plugin--s2member-start", "ws_plugin__s2member_start_page");
72
- add_submenu_page ("ws-plugin--s2member-start", "s2Member Quick Start Guide", "Quick Start Guide", "edit_plugins", "ws-plugin--s2member-start", "ws_plugin__s2member_start_page");
73
- add_submenu_page ("ws-plugin--s2member-start", "s2Member General Options", "General Options", "edit_plugins", "ws-plugin--s2member-options", "ws_plugin__s2member_options_page");
74
- add_submenu_page ("ws-plugin--s2member-start", "s2Member PayPal Options", "PayPal® Options", "edit_plugins", "ws-plugin--s2member-paypal-ops", "ws_plugin__s2member_paypal_ops_page");
75
- add_submenu_page ("ws-plugin--s2member-start", "s2Member PayPal® Buttons", "PayPal® Buttons", "edit_plugins", "ws-plugin--s2member-buttons", "ws_plugin__s2member_buttons_page");
76
- add_submenu_page ("ws-plugin--s2member-start", "s2Member File Download Options", "Download Options", "edit_plugins", "ws-plugin--s2member-down-ops", "ws_plugin__s2member_down_ops_page");
77
- add_submenu_page ("ws-plugin--s2member-start", "s2Member API / Tracking", "API / Tracking", "edit_plugins", "ws-plugin--s2member-trk-ops", "ws_plugin__s2member_trk_ops_page");
78
- add_submenu_page ("ws-plugin--s2member-start", "s2Member API / List Servers", "API / List Servers", "edit_plugins", "ws-plugin--s2member-els-ops", "ws_plugin__s2member_els_ops_page");
79
- add_submenu_page ("ws-plugin--s2member-start", "s2Member API / Notifications", "API / Notifications", "edit_plugins", "ws-plugin--s2member-api-ops", "ws_plugin__s2member_api_ops_page");
80
- add_submenu_page ("ws-plugin--s2member-start", "s2Member API / Scripting", "API / Scripting", "edit_plugins", "ws-plugin--s2member-scripting", "ws_plugin__s2member_scripting_page");
81
- add_submenu_page ("ws-plugin--s2member-start", "s2Member Information", "s2Member Info", "edit_plugins", "ws-plugin--s2member-info", "ws_plugin__s2member_info_page");
82
  /**/
83
  do_action ("s2member_after_add_admin_options");
84
  /**/
@@ -200,19 +200,6 @@ function ws_plugin__s2member_menu_pages_css ()
200
  do_action ("s2member_after_menu_pages_css");
201
  }
202
  /*
203
- Function for building and handling the Quick Start page.
204
- */
205
- function ws_plugin__s2member_start_page ()
206
- {
207
- do_action ("s2member_before_start_page");
208
- /**/
209
- include_once dirname (dirname (__FILE__)) . "/menu-pages/start.inc.php";
210
- /**/
211
- do_action ("s2member_after_start_page");
212
- /**/
213
- return;
214
- }
215
- /*
216
  Function for building and handling the General Options page.
217
  */
218
  function ws_plugin__s2member_options_page ()
@@ -385,4 +372,17 @@ function ws_plugin__s2member_info_page ()
385
  /**/
386
  return;
387
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
388
  ?>
68
  /**/
69
  add_filter ("plugin_action_links", "_ws_plugin__s2member_add_settings_link", 10, 2);
70
  /**/
71
+ add_menu_page ("s2Member Options", "s2Member", "edit_plugins", "ws-plugin--s2member-options", "ws_plugin__s2member_options_page");
72
+ add_submenu_page ("ws-plugin--s2member-options", "s2Member General Options", "General Options", "edit_plugins", "ws-plugin--s2member-options", "ws_plugin__s2member_options_page");
73
+ add_submenu_page ("ws-plugin--s2member-options", "s2Member PayPal Options", "PayPal® Options", "edit_plugins", "ws-plugin--s2member-paypal-ops", "ws_plugin__s2member_paypal_ops_page");
74
+ add_submenu_page ("ws-plugin--s2member-options", "s2Member PayPal® Buttons", "PayPal® Buttons", "edit_plugins", "ws-plugin--s2member-buttons", "ws_plugin__s2member_buttons_page");
75
+ add_submenu_page ("ws-plugin--s2member-options", "s2Member File Download Options", "Download Options", "edit_plugins", "ws-plugin--s2member-down-ops", "ws_plugin__s2member_down_ops_page");
76
+ add_submenu_page ("ws-plugin--s2member-options", "s2Member API / Tracking", "API / Tracking", "edit_plugins", "ws-plugin--s2member-trk-ops", "ws_plugin__s2member_trk_ops_page");
77
+ add_submenu_page ("ws-plugin--s2member-options", "s2Member API / List Servers", "API / List Servers", "edit_plugins", "ws-plugin--s2member-els-ops", "ws_plugin__s2member_els_ops_page");
78
+ add_submenu_page ("ws-plugin--s2member-options", "s2Member API / Notifications", "API / Notifications", "edit_plugins", "ws-plugin--s2member-api-ops", "ws_plugin__s2member_api_ops_page");
79
+ add_submenu_page ("ws-plugin--s2member-options", "s2Member API / Scripting", "API / Scripting", "edit_plugins", "ws-plugin--s2member-scripting", "ws_plugin__s2member_scripting_page");
80
+ add_submenu_page ("ws-plugin--s2member-options", "s2Member Information", "s2Member Info", "edit_plugins", "ws-plugin--s2member-info", "ws_plugin__s2member_info_page");
81
+ add_submenu_page ("ws-plugin--s2member-options", "s2Member Quick Start Guide", "Quick Start Guide", "edit_plugins", "ws-plugin--s2member-start", "ws_plugin__s2member_start_page");
82
  /**/
83
  do_action ("s2member_after_add_admin_options");
84
  /**/
200
  do_action ("s2member_after_menu_pages_css");
201
  }
202
  /*
 
 
 
 
 
 
 
 
 
 
 
 
 
203
  Function for building and handling the General Options page.
204
  */
205
  function ws_plugin__s2member_options_page ()
372
  /**/
373
  return;
374
  }
375
+ /*
376
+ Function for building and handling the Quick Start page.
377
+ */
378
+ function ws_plugin__s2member_start_page ()
379
+ {
380
+ do_action ("s2member_before_start_page");
381
+ /**/
382
+ include_once dirname (dirname (__FILE__)) . "/menu-pages/start.inc.php";
383
+ /**/
384
+ do_action ("s2member_after_start_page");
385
+ /**/
386
+ return;
387
+ }
388
  ?>
includes/functions/paypal-notify.inc.php CHANGED
@@ -164,7 +164,7 @@ function ws_plugin__s2member_paypal_notify ()
164
  /**/
165
  $paypal["s2member_log"][] = "s2Member txn_type identified as (web_accept|subscr_signup) w/o update vars.";
166
  /**/
167
- if ($registration_url = ws_plugin__s2member_register_link_gen ($paypal["subscr_id"], $paypal["custom"], $paypal["item_number"]) && is_array ($cv = preg_split ("/\|/", $paypal["custom"])))
168
  {
169
  $sbj = preg_replace ("/%%registration_url%%/i", $registration_url, $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["signup_email_subject"]);
170
  $msg = preg_replace ("/%%registration_url%%/i", $registration_url, $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["signup_email_message"]);
164
  /**/
165
  $paypal["s2member_log"][] = "s2Member txn_type identified as (web_accept|subscr_signup) w/o update vars.";
166
  /**/
167
+ if (($registration_url = ws_plugin__s2member_register_link_gen ($paypal["subscr_id"], $paypal["custom"], $paypal["item_number"])) && is_array ($cv = preg_split ("/\|/", $paypal["custom"])))
168
  {
169
  $sbj = preg_replace ("/%%registration_url%%/i", $registration_url, $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["signup_email_subject"]);
170
  $msg = preg_replace ("/%%registration_url%%/i", $registration_url, $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["signup_email_message"]);
includes/functions/register-access.inc.php CHANGED
@@ -143,7 +143,7 @@ function ws_plugin__s2member_register_link_gen ($subscr_id = FALSE, $custom = FA
143
  /**/
144
  if ($subscr_id && $custom && $item_number) /* Must have all of these. */
145
  {
146
- $register = ws_plugin__s2member_xencrypt ("subscr_id_custom_item_number:.:|:.:" . $subscr_id . ":.:|:.:" . $custom . ":.:|:.:" . $item_number);
147
  $register_link = ws_plugin__s2member_append_query_var (get_bloginfo ("url") . "/", "s2member_register=" . urlencode ($register));
148
  /**/
149
  if ($shrink && ($tinyurl = @file_get_contents ("http://tinyurl.com/api-create.php?url=" . rawurlencode ($register_link))))
@@ -165,7 +165,7 @@ function ws_plugin__s2member_register ()
165
  /**/
166
  if ($_GET["s2member_register"] || ($_GET["s2member_register"] = $_GET["s2member_paypal_register"]))
167
  {
168
- if (is_array ($register = preg_split ("/\:\.\:\|\:\.\:/", ws_plugin__s2member_xdecrypt ($_GET["s2member_register"]))))
169
  {
170
  if (count ($register) === 4 && $register[0] === "subscr_id_custom_item_number" && $register[1] && $register[2] && $register[3])
171
  {
@@ -415,11 +415,7 @@ if (!function_exists ("wp_generate_password"))
415
  {
416
  do_action ("s2member_before_s2member_generate_password");
417
  /**/
418
- $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
419
- $chars .= ($special_chars) ? "!@#$%^&*()" : "";
420
- /**/
421
- for ($i = 0, $password = ""; $i < $length; $i++)
422
- $password .= substr ($chars, wp_rand (0, strlen ($chars) - 1), 1);
423
  /**/
424
  if (!defined ("BP_VERSION") && $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["custom_reg_password"])
425
  if (wp_verify_nonce (trim (stripslashes ($_POST["ws_plugin__s2member_registration"])), "ws-plugin--s2member-registration"))
143
  /**/
144
  if ($subscr_id && $custom && $item_number) /* Must have all of these. */
145
  {
146
+ $register = ws_plugin__s2member_encrypt ("subscr_id_custom_item_number:.:|:.:" . $subscr_id . ":.:|:.:" . $custom . ":.:|:.:" . $item_number);
147
  $register_link = ws_plugin__s2member_append_query_var (get_bloginfo ("url") . "/", "s2member_register=" . urlencode ($register));
148
  /**/
149
  if ($shrink && ($tinyurl = @file_get_contents ("http://tinyurl.com/api-create.php?url=" . rawurlencode ($register_link))))
165
  /**/
166
  if ($_GET["s2member_register"] || ($_GET["s2member_register"] = $_GET["s2member_paypal_register"]))
167
  {
168
+ if (is_array ($register = preg_split ("/\:\.\:\|\:\.\:/", ws_plugin__s2member_decrypt ($_GET["s2member_register"]))))
169
  {
170
  if (count ($register) === 4 && $register[0] === "subscr_id_custom_item_number" && $register[1] && $register[2] && $register[3])
171
  {
415
  {
416
  do_action ("s2member_before_s2member_generate_password");
417
  /**/
418
+ $password = ws_plugin__s2member_random_str_gen ($length, $special_chars);
 
 
 
 
419
  /**/
420
  if (!defined ("BP_VERSION") && $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["custom_reg_password"])
421
  if (wp_verify_nonce (trim (stripslashes ($_POST["ws_plugin__s2member_registration"])), "ws-plugin--s2member-registration"))
includes/functions/sp-access.inc.php CHANGED
@@ -22,7 +22,7 @@ function ws_plugin__s2member_sp_access_link_gen ($page_ID = FALSE, $hours = 72,
22
  /**/
23
  if ($page_ID && $hours) /* Must have page_ID/hours in order to create an access link. */
24
  {
25
- $sp_access = ws_plugin__s2member_xencrypt ("sp_time_hours:.:|:.:" . $page_ID . ":.:|:.:" . strtotime ("now") . ":.:|:.:" . $hours);
26
  $sp_access_link = ws_plugin__s2member_append_query_var (get_page_link ($page_ID), "s2member_sp_access=" . urlencode ($sp_access));
27
  /**/
28
  if ($shrink && ($tinyurl = @file_get_contents ("http://tinyurl.com/api-create.php?url=" . rawurlencode ($sp_access_link))))
@@ -61,7 +61,7 @@ function ws_plugin__s2member_sp_access ($page_ID = FALSE)
61
  /**/
62
  else if ($_GET["s2member_sp_access"] && $page_ID)
63
  {
64
- if (is_array ($sp_access = preg_split ("/\:\.\:\|\:\.\:/", ws_plugin__s2member_xdecrypt ($_GET["s2member_sp_access"]))))
65
  {
66
  if (count ($sp_access) === 4 && $sp_access[0] === "sp_time_hours" && $sp_access[1] == $page_ID && $sp_access[2] >= strtotime ("-" . $sp_access[3] . " hours"))
67
  {
22
  /**/
23
  if ($page_ID && $hours) /* Must have page_ID/hours in order to create an access link. */
24
  {
25
+ $sp_access = ws_plugin__s2member_encrypt ("sp_time_hours:.:|:.:" . $page_ID . ":.:|:.:" . strtotime ("now") . ":.:|:.:" . $hours);
26
  $sp_access_link = ws_plugin__s2member_append_query_var (get_page_link ($page_ID), "s2member_sp_access=" . urlencode ($sp_access));
27
  /**/
28
  if ($shrink && ($tinyurl = @file_get_contents ("http://tinyurl.com/api-create.php?url=" . rawurlencode ($sp_access_link))))
61
  /**/
62
  else if ($_GET["s2member_sp_access"] && $page_ID)
63
  {
64
+ if (is_array ($sp_access = preg_split ("/\:\.\:\|\:\.\:/", ws_plugin__s2member_decrypt ($_GET["s2member_sp_access"]))))
65
  {
66
  if (count ($sp_access) === 4 && $sp_access[0] === "sp_time_hours" && $sp_access[1] == $page_ID && $sp_access[2] >= strtotime ("-" . $sp_access[3] . " hours"))
67
  {
includes/functions/users-list.inc.php CHANGED
@@ -44,7 +44,7 @@ Attach to: add_filter ("manage_users_custom_column");
44
  */
45
  function ws_plugin__s2member_users_list_display_cols ($_ = FALSE, $col = FALSE, $user_id = FALSE)
46
  {
47
- global $user_object; /* The user_row() function already has this. */
48
  $user = $user_object; /* Shorter reference to the $user_object var. */
49
  static $fields, $fields_4_user_id; /* Used for optimization. */
50
  /**/
44
  */
45
  function ws_plugin__s2member_users_list_display_cols ($_ = FALSE, $col = FALSE, $user_id = FALSE)
46
  {
47
+ global $user_object; /* Already in global scope inside users.php. */
48
  $user = $user_object; /* Shorter reference to the $user_object var. */
49
  static $fields, $fields_4_user_id; /* Used for optimization. */
50
  /**/
includes/functions/utilities.inc.php CHANGED
@@ -124,46 +124,103 @@ function ws_plugin__s2member_curlpsr ($url = FALSE, $vars = FALSE)
124
  return (strlen ($o)) ? $o : false;
125
  }
126
  /*
127
- Base32 encode ( base32 is case insensitive ).
 
 
 
 
 
 
 
 
128
  */
129
- function ws_plugin__s2member_base32_encode ($string = FALSE)
130
  {
131
- for ($i = 0; $i < strlen ((string)$string); $i++)
 
 
 
 
 
 
132
  {
133
- $hexdec = dechex (ord (substr ($string, $i, 1)));
134
- $base32 .= base_convert ($hexdec, 16, 32);
 
 
 
 
 
135
  }
136
- /**/
137
- return (string)$base32;
138
  }
139
  /*
140
- Base32 decode ( base32 is case insensitive ).
141
  */
142
- function ws_plugin__s2member_base32_decode ($base32 = FALSE)
143
  {
144
- for ($i = 0; $i < strlen ((string)$base32); $i += 2)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
145
  {
146
- $hexdec = base_convert (substr ($base32, $i, 2), 32, 16);
147
- $string .= chr (hexdec ($hexdec));
 
 
 
 
 
 
148
  }
149
- /**/
150
- return (string)$string;
 
 
 
 
 
 
 
151
  }
152
  /*
153
- Xencrypt and xdecrypt ( very useful functions ).
154
  */
155
  function ws_plugin__s2member_xencrypt ($string = FALSE, $key = FALSE)
156
  {
157
- $key = (!is_string ($key) || !strlen ($key)) ? "POE993432" : $key;
 
 
 
 
158
  /**/
159
- for ($i = 1; $i <= strlen ((string)$string); $i++)
 
 
160
  {
161
  $char = substr ($string, $i - 1, 1);
162
  $keychar = substr ($key, ($i % strlen ($key)) - 1, 1);
163
  $encrypted .= chr (ord ($char) + ord ($keychar));
164
  }
165
  /**/
166
- return ws_plugin__s2member_base32_encode ((string)$encrypted);
 
 
167
  }
168
  /*
169
  Alias function for API Scripting usage.
@@ -173,35 +230,51 @@ function s2member_xencrypt ($string = FALSE, $key = FALSE)
173
  return ws_plugin__s2member_xencrypt ($string, $key);
174
  }
175
  /*
176
- Xencrypt and xdecrypt ( very useful functions ).
177
  */
178
- function ws_plugin__s2member_xdecrypt ($string = FALSE, $key = FALSE)
179
  {
180
- $key = (!is_string ($key) || !strlen ($key)) ? "POE993432" : $key;
181
  /**/
182
- $string = ws_plugin__s2member_base32_decode ((string)$string);
 
 
183
  /**/
184
- for ($i = 1; $i <= strlen ((string)$string); $i++)
 
 
 
 
 
185
  {
186
- $char = substr ($string, $i - 1, 1);
187
  $keychar = substr ($key, ($i % strlen ($key)) - 1, 1);
188
  $decrypted .= chr (ord ($char) - ord ($keychar));
189
  }
190
  /**/
191
- return (string)$decrypted;
 
 
 
192
  }
193
  /*
194
  Alias function for API Scripting usage.
195
  */
196
- function s2member_xdecrypt ($string = FALSE, $key = FALSE)
197
  {
198
- return ws_plugin__s2member_xdecrypt ($string, $key);
199
  }
200
  /*
201
- Function escapes single quotes.
202
  */
203
- function ws_plugin__s2member_esc_sq ($string = FALSE)
204
  {
205
- return preg_replace ("/'/", "\'", $string);
 
 
 
 
 
 
206
  }
207
  ?>
124
  return (strlen ($o)) ? $o : false;
125
  }
126
  /*
127
+ Function escapes single quotes.
128
+ */
129
+ function ws_plugin__s2member_esc_sq ($string = FALSE)
130
+ {
131
+ return preg_replace ("/'/", "\'", $string);
132
+ }
133
+ /*
134
+ RIJNDAEL 256: two-way encryption/decryption, with a url-safe base64 wrapper.
135
+ Includes a built-in fallback on XOR encryption when mcrypt is not available.
136
  */
137
+ function ws_plugin__s2member_encrypt ($string = FALSE, $key = FALSE)
138
  {
139
+ $string = (is_string ($string)) ? $string : "";
140
+ /**/
141
+ $key = (!is_string ($key) || !strlen ($key)) ? /* For security. */
142
+ $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["sec_encryption_key"] : $key;
143
+ $key = (!is_string ($key) || !strlen ($key)) ? wp_salt () : $key;
144
+ /**/
145
+ if (function_exists ("mcrypt_encrypt") && in_array ("rijndael-256", mcrypt_list_algorithms ()) && in_array ("cbc", mcrypt_list_modes ()))
146
  {
147
+ $string = (strlen ($string)) ? "~r2|" . $string : "";
148
+ $key = substr ($key, 0, mcrypt_get_key_size (MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC));
149
+ $iv = ws_plugin__s2member_random_str_gen (mcrypt_get_iv_size (MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC), false);
150
+ $encrypted = mcrypt_encrypt (MCRYPT_RIJNDAEL_256, $key, $string, MCRYPT_MODE_CBC, $iv);
151
+ $encrypted = (strlen ($encrypted)) ? "~r2:" . $iv . "|" . $encrypted : "";
152
+ /**/
153
+ return ($base64 = str_replace (array ("+", "/", "="), array ("-", "_", "."), base64_encode ($encrypted)));
154
  }
155
+ else /* Fallback on XOR encryption. */
156
+ return ws_plugin__s2member_xencrypt ($string, $key);
157
  }
158
  /*
159
+ Alias function for API Scripting usage.
160
  */
161
+ function s2member_encrypt ($string = FALSE, $key = FALSE)
162
  {
163
+ return ws_plugin__s2member_encrypt ($string, $key);
164
+ }
165
+ /*
166
+ RIJNDAEL 256: two-way encryption/decryption, with a url-safe base64 wrapper.
167
+ Includes a built-in fallback on XOR encryption when mcrypt is not available.
168
+ */
169
+ function ws_plugin__s2member_decrypt ($base64 = FALSE, $key = FALSE)
170
+ {
171
+ $base64 = (is_string ($base64)) ? $base64 : "";
172
+ /**/
173
+ $key = (!is_string ($key) || !strlen ($key)) ? /* For security. */
174
+ $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["sec_encryption_key"] : $key;
175
+ $key = (!is_string ($key) || !strlen ($key)) ? wp_salt () : $key;
176
+ /**/
177
+ $encrypted = base64_decode (str_replace (array ("-", "_", "."), array ("+", "/", "="), $base64));
178
+ /**/
179
+ if (function_exists ("mcrypt_decrypt") && in_array ("rijndael-256", mcrypt_list_algorithms ()) && in_array ("cbc", mcrypt_list_modes ())/**/
180
+ && preg_match ("/^~r2\:(.+?)\|/", $encrypted, $v1)) /* Check validity. */
181
  {
182
+ $encrypted = preg_replace ("/^~r2\:(.+?)\|/", "", $encrypted);
183
+ $key = substr ($key, 0, mcrypt_get_key_size (MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC));
184
+ $decrypted = mcrypt_decrypt (MCRYPT_RIJNDAEL_256, $key, $encrypted, MCRYPT_MODE_CBC, $v1[1]);
185
+ $decrypted = preg_replace ("/^~r2\|/", "", $decrypted, 1, $v2);
186
+ $decrypted = ($v2) ? $decrypted : ""; /* Check validity. */
187
+ $decrypted = rtrim ($decrypted, "\0\4"); /* Nulls/EOTs. */
188
+ /**/
189
+ return ($string = $decrypted);
190
  }
191
+ else /* Fallback on XOR decryption. */
192
+ return ws_plugin__s2member_xdecrypt ($base64, $key);
193
+ }
194
+ /*
195
+ Alias function for API Scripting usage.
196
+ */
197
+ function s2member_decrypt ($base64 = FALSE, $key = FALSE)
198
+ {
199
+ return ws_plugin__s2member_decrypt ($base64, $key);
200
  }
201
  /*
202
+ XOR two-way encryption/decryption, with a base64 wrapper.
203
  */
204
  function ws_plugin__s2member_xencrypt ($string = FALSE, $key = FALSE)
205
  {
206
+ $string = (is_string ($string)) ? $string : "";
207
+ /**/
208
+ $key = (!is_string ($key) || !strlen ($key)) ? /* For security. */
209
+ $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["sec_encryption_key"] : $key;
210
+ $key = (!is_string ($key) || !strlen ($key)) ? wp_salt () : $key;
211
  /**/
212
+ $string = (strlen ($string)) ? "~xe|" . $string : "";
213
+ /**/
214
+ for ($i = 1, $encrypted = ""; $i <= strlen ($string); $i++)
215
  {
216
  $char = substr ($string, $i - 1, 1);
217
  $keychar = substr ($key, ($i % strlen ($key)) - 1, 1);
218
  $encrypted .= chr (ord ($char) + ord ($keychar));
219
  }
220
  /**/
221
+ $encrypted = (strlen ($encrypted)) ? "~xe|" . $encrypted : "";
222
+ /**/
223
+ return ($base64 = str_replace (array ("+", "/", "="), array ("-", "_", "."), base64_encode ($encrypted)));
224
  }
225
  /*
226
  Alias function for API Scripting usage.
230
  return ws_plugin__s2member_xencrypt ($string, $key);
231
  }
232
  /*
233
+ XOR two-way encryption/decryption, with a base64 wrapper.
234
  */
235
+ function ws_plugin__s2member_xdecrypt ($base64 = FALSE, $key = FALSE)
236
  {
237
+ $base64 = (is_string ($base64)) ? $base64 : "";
238
  /**/
239
+ $key = (!is_string ($key) || !strlen ($key)) ? /* For security. */
240
+ $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["sec_encryption_key"] : $key;
241
+ $key = (!is_string ($key) || !strlen ($key)) ? wp_salt () : $key;
242
  /**/
243
+ $encrypted = base64_decode (str_replace (array ("-", "_", "."), array ("+", "/", "="), $base64));
244
+ /**/
245
+ $encrypted = preg_replace ("/^~xe\|/", "", $encrypted, 1, $v1);
246
+ $encrypted = ($v1) ? $encrypted : ""; /* Check validity. */
247
+ /**/
248
+ for ($i = 1, $decrypted = ""; $i <= strlen ($encrypted); $i++)
249
  {
250
+ $char = substr ($encrypted, $i - 1, 1);
251
  $keychar = substr ($key, ($i % strlen ($key)) - 1, 1);
252
  $decrypted .= chr (ord ($char) - ord ($keychar));
253
  }
254
  /**/
255
+ $decrypted = preg_replace ("/^~xe\|/", "", $decrypted, 1, $v2);
256
+ $decrypted = ($v2) ? $decrypted : ""; /* Check validity. */
257
+ /**/
258
+ return ($string = $decrypted);
259
  }
260
  /*
261
  Alias function for API Scripting usage.
262
  */
263
+ function s2member_xdecrypt ($base64 = FALSE, $key = FALSE)
264
  {
265
+ return ws_plugin__s2member_xdecrypt ($base64, $key);
266
  }
267
  /*
268
+ Function generates a random string with letters/numbers/symbols.
269
  */
270
+ function ws_plugin__s2member_random_str_gen ($length = 12, $special_chars = TRUE)
271
  {
272
+ $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
273
+ $chars .= ($special_chars) ? "!@#$%^&*()" : "";
274
+ /**/
275
+ for ($i = 0, $random_str = ""; $i < $length; $i++)
276
+ $random_str .= substr ($chars, mt_rand (0, strlen ($chars) - 1), 1);
277
+ /**/
278
+ return $random_str;
279
  }
280
  ?>
includes/menu-pages/api-ops.inc.php CHANGED
@@ -360,7 +360,7 @@ echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["installation"]) ? '<di
360
  /**/
361
  echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["tools"]) ? '<div class="ws-menu-page-tools"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-tools.png" alt="." /></div>' . "\n" : '';
362
  /**/
363
- echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["tips"]) ? '<div class="ws-menu-page-tips"><a href="' . ws_plugin__s2member_parse_readme_value ("Customization URI") . '"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-tips.png" alt="." /></a></div>' . "\n" : '';
364
  /**/
365
  echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["donations"]) ? '<div class="ws-menu-page-donations"><a href="' . ws_plugin__s2member_parse_readme_value ("Donate link") . '"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-donations.jpg" alt="." /></a></div>' . "\n" : '';
366
  /**/
360
  /**/
361
  echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["tools"]) ? '<div class="ws-menu-page-tools"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-tools.png" alt="." /></div>' . "\n" : '';
362
  /**/
363
+ echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["support"]) ? '<div class="ws-menu-page-support"><a href="' . ws_plugin__s2member_parse_readme_value ("Forum URI") . '"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-support.png" alt="." /></a></div>' . "\n" : '';
364
  /**/
365
  echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["donations"]) ? '<div class="ws-menu-page-donations"><a href="' . ws_plugin__s2member_parse_readme_value ("Donate link") . '"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-donations.jpg" alt="." /></a></div>' . "\n" : '';
366
  /**/
includes/menu-pages/buttons.inc.php CHANGED
@@ -496,7 +496,7 @@ echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["installation"]) ? '<di
496
  /**/
497
  echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["tools"]) ? '<div class="ws-menu-page-tools"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-tools.png" alt="." /></div>' . "\n" : '';
498
  /**/
499
- echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["tips"]) ? '<div class="ws-menu-page-tips"><a href="' . ws_plugin__s2member_parse_readme_value ("Customization URI") . '"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-tips.png" alt="." /></a></div>' . "\n" : '';
500
  /**/
501
  echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["donations"]) ? '<div class="ws-menu-page-donations"><a href="' . ws_plugin__s2member_parse_readme_value ("Donate link") . '"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-donations.jpg" alt="." /></a></div>' . "\n" : '';
502
  /**/
496
  /**/
497
  echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["tools"]) ? '<div class="ws-menu-page-tools"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-tools.png" alt="." /></div>' . "\n" : '';
498
  /**/
499
+ echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["support"]) ? '<div class="ws-menu-page-support"><a href="' . ws_plugin__s2member_parse_readme_value ("Forum URI") . '"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-support.png" alt="." /></a></div>' . "\n" : '';
500
  /**/
501
  echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["donations"]) ? '<div class="ws-menu-page-donations"><a href="' . ws_plugin__s2member_parse_readme_value ("Donate link") . '"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-donations.jpg" alt="." /></a></div>' . "\n" : '';
502
  /**/
includes/menu-pages/down-ops.inc.php CHANGED
@@ -42,7 +42,7 @@ echo '<div class="ws-menu-page-hr"></div>' . "\n";
42
  /**/
43
  echo '<h3>Upload restricted files to this security-enabled directory:<br /> <code>' . preg_replace ("/^" . preg_quote ($_SERVER["DOCUMENT_ROOT"], "/") . "/", "", $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"]) . '</code></h3>' . "\n";
44
  echo '<p>- Then, you can link to these restricted files using this special format:<br />&nbsp;&nbsp;<code>' . get_bloginfo ("url") . '/?<strong>s2member_file_download</strong>=example-file.zip</code><br />&nbsp;&nbsp;<small><em><strong>s2member_file_download</strong> = location of the file, relative to the /' . esc_html (basename ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"])) . '/ directory. In other words, just the file name.</em></small></p>' . "\n";
45
- echo '<p>- If needed, you can make certain files available free, using an extra variable:<br />&nbsp;&nbsp;<code>' . get_bloginfo ("url") . '/?<strong>s2member_file_download</strong>=example-file.zip&<strong>s2member_free_file_download_key</strong>=&lt;?php echo s2member_xencrypt("example-file.zip"); ?&gt;</code><br />&nbsp;&nbsp;<small><em><strong>s2member_free_file_download_key</strong> = &lt;?php echo s2member_xencrypt("location of the file, relative to the /' . esc_html (basename ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"])) . '/ directory"); ?&gt;</em></small></p>' . "\n";
46
  /**/
47
  echo '<div class="ws-menu-page-hr"></div>' . "\n";
48
  /**/
@@ -177,7 +177,7 @@ echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["installation"]) ? '<di
177
  /**/
178
  echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["tools"]) ? '<div class="ws-menu-page-tools"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-tools.png" alt="." /></div>' . "\n" : '';
179
  /**/
180
- echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["tips"]) ? '<div class="ws-menu-page-tips"><a href="' . ws_plugin__s2member_parse_readme_value ("Customization URI") . '"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-tips.png" alt="." /></a></div>' . "\n" : '';
181
  /**/
182
  echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["donations"]) ? '<div class="ws-menu-page-donations"><a href="' . ws_plugin__s2member_parse_readme_value ("Donate link") . '"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-donations.jpg" alt="." /></a></div>' . "\n" : '';
183
  /**/
42
  /**/
43
  echo '<h3>Upload restricted files to this security-enabled directory:<br /> <code>' . preg_replace ("/^" . preg_quote ($_SERVER["DOCUMENT_ROOT"], "/") . "/", "", $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"]) . '</code></h3>' . "\n";
44
  echo '<p>- Then, you can link to these restricted files using this special format:<br />&nbsp;&nbsp;<code>' . get_bloginfo ("url") . '/?<strong>s2member_file_download</strong>=example-file.zip</code><br />&nbsp;&nbsp;<small><em><strong>s2member_file_download</strong> = location of the file, relative to the /' . esc_html (basename ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"])) . '/ directory. In other words, just the file name.</em></small></p>' . "\n";
45
+ echo '<p>- If needed, you can make certain files available free, using an extra variable:<br />&nbsp;&nbsp;<code>' . get_bloginfo ("url") . '/?<strong>s2member_file_download</strong>=example-file.zip&<strong>s2member_free_file_download_key</strong>=&lt;?php echo md5(s2member_xencrypt("example-file.zip")); ?&gt;</code><br />&nbsp;&nbsp;<small><em><strong>s2member_free_file_download_key</strong> = &lt;?php echo md5(s2member_xencrypt("location of the file, relative to the /' . esc_html (basename ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["files_dir"])) . '/ directory")); ?&gt;</em></small></p>' . "\n";
46
  /**/
47
  echo '<div class="ws-menu-page-hr"></div>' . "\n";
48
  /**/
177
  /**/
178
  echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["tools"]) ? '<div class="ws-menu-page-tools"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-tools.png" alt="." /></div>' . "\n" : '';
179
  /**/
180
+ echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["support"]) ? '<div class="ws-menu-page-support"><a href="' . ws_plugin__s2member_parse_readme_value ("Forum URI") . '"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-support.png" alt="." /></a></div>' . "\n" : '';
181
  /**/
182
  echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["donations"]) ? '<div class="ws-menu-page-donations"><a href="' . ws_plugin__s2member_parse_readme_value ("Donate link") . '"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-donations.jpg" alt="." /></a></div>' . "\n" : '';
183
  /**/
includes/menu-pages/els-ops.inc.php CHANGED
@@ -277,7 +277,7 @@ echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["installation"]) ? '<di
277
  /**/
278
  echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["tools"]) ? '<div class="ws-menu-page-tools"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-tools.png" alt="." /></div>' . "\n" : '';
279
  /**/
280
- echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["tips"]) ? '<div class="ws-menu-page-tips"><a href="' . ws_plugin__s2member_parse_readme_value ("Customization URI") . '"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-tips.png" alt="." /></a></div>' . "\n" : '';
281
  /**/
282
  echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["donations"]) ? '<div class="ws-menu-page-donations"><a href="' . ws_plugin__s2member_parse_readme_value ("Donate link") . '"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-donations.jpg" alt="." /></a></div>' . "\n" : '';
283
  /**/
277
  /**/
278
  echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["tools"]) ? '<div class="ws-menu-page-tools"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-tools.png" alt="." /></div>' . "\n" : '';
279
  /**/
280
+ echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["support"]) ? '<div class="ws-menu-page-support"><a href="' . ws_plugin__s2member_parse_readme_value ("Forum URI") . '"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-support.png" alt="." /></a></div>' . "\n" : '';
281
  /**/
282
  echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["donations"]) ? '<div class="ws-menu-page-donations"><a href="' . ws_plugin__s2member_parse_readme_value ("Donate link") . '"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-donations.jpg" alt="." /></a></div>' . "\n" : '';
283
  /**/
includes/menu-pages/info.inc.php CHANGED
@@ -44,7 +44,7 @@ echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["installation"]) ? '<di
44
  /**/
45
  echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["tools"]) ? '<div class="ws-menu-page-tools"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-tools.png" alt="." /></div>' . "\n" : '';
46
  /**/
47
- echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["tips"]) ? '<div class="ws-menu-page-tips"><a href="' . ws_plugin__s2member_parse_readme_value("Customization URI") . '"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-tips.png" alt="." /></a></div>' . "\n" : '';
48
  /**/
49
  echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["donations"]) ? '<div class="ws-menu-page-donations"><a href="' . ws_plugin__s2member_parse_readme_value("Donate link") . '"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-donations.jpg" alt="." /></a></div>' . "\n" : '';
50
  /**/
44
  /**/
45
  echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["tools"]) ? '<div class="ws-menu-page-tools"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-tools.png" alt="." /></div>' . "\n" : '';
46
  /**/
47
+ echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["support"]) ? '<div class="ws-menu-page-support"><a href="' . ws_plugin__s2member_parse_readme_value("Forum URI") . '"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-support.png" alt="." /></a></div>' . "\n" : '';
48
  /**/
49
  echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["donations"]) ? '<div class="ws-menu-page-donations"><a href="' . ws_plugin__s2member_parse_readme_value("Donate link") . '"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-donations.jpg" alt="." /></a></div>' . "\n" : '';
50
  /**/
includes/menu-pages/menu-pages.css CHANGED
@@ -433,11 +433,11 @@ div.ws-menu-page > table.ws-menu-page-table > tbody > tr > td.ws-menu-page-table
433
  width: 200px;
434
  height: 200px;
435
  }
436
- div.ws-menu-page > table.ws-menu-page-table > tbody > tr > td.ws-menu-page-table-r > div.ws-menu-page-tips
437
  {
438
  margin: 0 0 10px 25px;
439
  }
440
- div.ws-menu-page > table.ws-menu-page-table > tbody > tr > td.ws-menu-page-table-r > div.ws-menu-page-tips > a > img
441
  {
442
  width: 200px;
443
  height: 150px;
433
  width: 200px;
434
  height: 200px;
435
  }
436
+ div.ws-menu-page > table.ws-menu-page-table > tbody > tr > td.ws-menu-page-table-r > div.ws-menu-page-support
437
  {
438
  margin: 0 0 10px 25px;
439
  }
440
+ div.ws-menu-page > table.ws-menu-page-table > tbody > tr > td.ws-menu-page-table-r > div.ws-menu-page-support > a > img
441
  {
442
  width: 200px;
443
  height: 150px;
includes/menu-pages/menu-pages.js CHANGED
@@ -83,7 +83,7 @@ jQuery(document).ready (function($)
83
  /**/
84
  $('input.ws-menu-page-media-btn').filter (function() /* Only those that have a rel attribute. */
85
  {
86
- return($(this).attr ('rel')) ? true : false; /* Must have rel targeting an input id. */
87
  })/**/
88
  .click (function() /* Attach click events to media buttons with send_to_editor(). */
89
  {
@@ -128,7 +128,43 @@ jQuery(document).ready (function($)
128
  /*
129
  These routines are all specific to this software.
130
  */
131
- if (location.href.match (/page\=ws-plugin--s2member-buttons/))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
132
  {
133
  $('select#ws-plugin--s2member-level1-term, select#ws-plugin--s2member-level2-term, select#ws-plugin--s2member-level3-term, select#ws-plugin--s2member-level4-term, select#ws-plugin--s2member-modification-term').change (function()
134
  {
83
  /**/
84
  $('input.ws-menu-page-media-btn').filter (function() /* Only those that have a rel attribute. */
85
  {
86
+ return ($(this).attr ('rel')) ? true : false; /* Must have rel targeting an input id. */
87
  })/**/
88
  .click (function() /* Attach click events to media buttons with send_to_editor(). */
89
  {
128
  /*
129
  These routines are all specific to this software.
130
  */
131
+ if (location.href.match (/page\=ws-plugin--s2member-options/))
132
+ {
133
+ ws_plugin__s2member_generateSecurityKey = function() /* Generates a unique Security Key. */
134
+ {
135
+ var mt_rand = function(min, max) /* The PHP equivalent to mt_rand(). */
136
+ {
137
+ min = (arguments.length < 1) ? 0 : min;
138
+ max = (arguments.length < 2) ? 2147483647 : max;
139
+ /**/
140
+ return Math.floor (Math.random () * (max - min + 1)) + min;
141
+ };
142
+ /**/
143
+ var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()';
144
+ for (var i = 0, key = ''; i < 56; i++) key += chars.substr (mt_rand(0, chars.length - 1), 1);
145
+ /**/
146
+ $('input#ws-plugin--s2member-sec-encryption-key').val (key);
147
+ /**/
148
+ return false;
149
+ };
150
+ /**/
151
+ ws_plugin__s2member_enableSecurityKey = function() /* Allow Security Key editing?? */
152
+ {
153
+ if (confirm('Edit Key? Are you sure?\nThis could break your installation!\n\n*Note* If you\'ve been testing s2Member, feel free to change this Key before you go live. Just don\'t go live, and then change it. You\'ll have some very unhappy Customers. Data corruption WILL occur!\n\nFor your safety, s2Member keeps a history of the last 10 Keys that you\'ve used. If you get yourself into a real situation, s2Member will let you revert back to a previous Key.'))
154
+ $('input#ws-plugin--s2member-sec-encryption-key').attr ('disabled', false);
155
+ /**/
156
+ return false;
157
+ };
158
+ /**/
159
+ ws_plugin__s2member_securityKeyHistory = function() /* Displays history of Keys. */
160
+ {
161
+ $('div#ws-plugin--s2member-sec-encryption-key-history').toggle ();
162
+ /**/
163
+ return false;
164
+ };
165
+ }
166
+ /**/
167
+ else if (location.href.match (/page\=ws-plugin--s2member-buttons/))
168
  {
169
  $('select#ws-plugin--s2member-level1-term, select#ws-plugin--s2member-level2-term, select#ws-plugin--s2member-level3-term, select#ws-plugin--s2member-level4-term, select#ws-plugin--s2member-modification-term').change (function()
170
  {
includes/menu-pages/options.inc.php CHANGED
@@ -32,6 +32,39 @@ echo '<form method="post" name="ws_plugin__s2member_options_form" id="ws-plugin-
32
  echo '<input type="hidden" name="ws_plugin__s2member_options_save" id="ws-plugin--s2member-options-save" value="' . esc_attr (wp_create_nonce ("ws-plugin--s2member-options-save")) . '" />' . "\n";
33
  echo '<input type="hidden" name="ws_plugin__s2member_configured" id="ws-plugin--s2member-configured" value="1" />' . "\n";
34
  /**/
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  echo '<div class="ws-menu-page-group" title="Email Configuration">' . "\n";
36
  /**/
37
  echo '<div class="ws-menu-page-section ws-plugin--s2member-email-section">' . "\n";
@@ -1055,7 +1088,7 @@ echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["installation"]) ? '<di
1055
  /**/
1056
  echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["tools"]) ? '<div class="ws-menu-page-tools"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-tools.png" alt="." /></div>' . "\n" : '';
1057
  /**/
1058
- echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["tips"]) ? '<div class="ws-menu-page-tips"><a href="' . ws_plugin__s2member_parse_readme_value ("Customization URI") . '"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-tips.png" alt="." /></a></div>' . "\n" : '';
1059
  /**/
1060
  echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["donations"]) ? '<div class="ws-menu-page-donations"><a href="' . ws_plugin__s2member_parse_readme_value ("Donate link") . '"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-donations.jpg" alt="." /></a></div>' . "\n" : '';
1061
  /**/
32
  echo '<input type="hidden" name="ws_plugin__s2member_options_save" id="ws-plugin--s2member-options-save" value="' . esc_attr (wp_create_nonce ("ws-plugin--s2member-options-save")) . '" />' . "\n";
33
  echo '<input type="hidden" name="ws_plugin__s2member_configured" id="ws-plugin--s2member-configured" value="1" />' . "\n";
34
  /**/
35
+ echo '<div class="ws-menu-page-group" title="Security Encryption Key">' . "\n";
36
+ /**/
37
+ echo '<div class="ws-menu-page-section ws-plugin--s2member-security-section">' . "\n";
38
+ echo '<h3>Security Encryption Key ( optional, for tighter security )</h3>' . "\n";
39
+ echo '<p>Just like WordPress®, s2Member is open-source software. Which is wonderful. However, this also makes it possible for anyone to grab a copy of the software, and try to learn their way around its security measures. In order to keep your installation of s2Member unique/secure, you should configure a Security Encryption Key. s2Member will use your Security Encryption Key to protect itself against hackers. It does this by encrypting all sensitive information with your Key. A Security Encryption Key is unique to your installation.</p>' . "\n";
40
+ echo '<p>Once you configure this, you do NOT want to change it; not ever. In fact, it is a VERY good idea to keep this backed up in a safe place, just in case you need to move your site, or re-install s2Member in the future. Some of the sensitive data that s2Member stores, will be encrypted with this Key. If you change it, that data can no longer be read, even by s2Member itself. In other words, don\'t use s2Member for six months, then decide to change your Key. That would break your installation. You configure this once, for each installation of s2Member; and you NEVER change it.</p>' . "\n";
41
+ /**/
42
+ echo '<table class="form-table">' . "\n";
43
+ echo '<tbody>' . "\n";
44
+ echo '<tr>' . "\n";
45
+ /**/
46
+ echo '<th>' . "\n";
47
+ echo '<label for="ws-plugin--s2member-sec-encryption-key">' . "\n";
48
+ echo 'Security Encryption Key:' . (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["sec_encryption_key"]) ? ' ( <a href="#" onclick="ws_plugin__s2member_enableSecurityKey();" title="( not recommended )">edit key</a> )' : ' ( <a href="#" onclick="ws_plugin__s2member_generateSecurityKey();" title="Insert an auto-generated Key. ( recommended )">auto-generate</a> )') . "\n";
49
+ echo '</label>' . "\n";
50
+ echo '</th>' . "\n";
51
+ /**/
52
+ echo '</tr>' . "\n";
53
+ echo '<tr>' . "\n";
54
+ /**/
55
+ echo '<td>' . "\n";
56
+ echo '<input type="text" name="ws_plugin__s2member_sec_encryption_key" id="ws-plugin--s2member-sec-encryption-key" value="' . format_to_edit ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["sec_encryption_key"]) . '" maxlength="256" autocomplete="off"' . (($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["sec_encryption_key"]) ? ' disabled="disabled"' : '') . ' />' . "\n";
57
+ echo (!$GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["sec_encryption_key"]) ? '<br />This may contain letters, numbers, spaces; even punctuation. Up to 256 characters.<br /><em>Ex: <code>' . esc_html (strtoupper (ws_plugin__s2member_random_str_gen (56))) . '</code></em>' . "\n" : '';
58
+ echo (count ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["sec_encryption_key_history"]) > 1) ? '<br /><a href="#" onclick="ws_plugin__s2member_securityKeyHistory();">Click here</a> for a history of your last 10 Encryption Keys.<div id="ws-plugin--s2member-sec-encryption-key-history" style="display:none;"><code>' . implode ('</code><br /><code>', $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["sec_encryption_key_history"]) . '</code></div>' . "\n" : '';
59
+ echo '</td>' . "\n";
60
+ /**/
61
+ echo '</tr>' . "\n";
62
+ echo '</tbody>' . "\n";
63
+ echo '</table>' . "\n";
64
+ echo '</div>' . "\n";
65
+ /**/
66
+ echo '</div>' . "\n";
67
+ /**/
68
  echo '<div class="ws-menu-page-group" title="Email Configuration">' . "\n";
69
  /**/
70
  echo '<div class="ws-menu-page-section ws-plugin--s2member-email-section">' . "\n";
1088
  /**/
1089
  echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["tools"]) ? '<div class="ws-menu-page-tools"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-tools.png" alt="." /></div>' . "\n" : '';
1090
  /**/
1091
+ echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["support"]) ? '<div class="ws-menu-page-support"><a href="' . ws_plugin__s2member_parse_readme_value ("Forum URI") . '"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-support.png" alt="." /></a></div>' . "\n" : '';
1092
  /**/
1093
  echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["donations"]) ? '<div class="ws-menu-page-donations"><a href="' . ws_plugin__s2member_parse_readme_value ("Donate link") . '"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-donations.jpg" alt="." /></a></div>' . "\n" : '';
1094
  /**/
includes/menu-pages/paypal-ops.inc.php CHANGED
@@ -36,7 +36,7 @@ echo '<div class="ws-menu-page-group" title="PayPal® Account Details">' . "\n";
36
  /**/
37
  echo '<div class="ws-menu-page-section ws-plugin--s2member-paypal-email-section">' . "\n";
38
  echo '<h3>PayPal® EMail Address ( required, please customize this )</h3>' . "\n";
39
- echo '<p>This plugin works in conjunction with PayPal® Website Payments Standard, for businesses. You do NOT need a PayPal® Pro account. You just need to upgrade your Personal PayPal® account to a Business status, which is free. A PayPal® account can be <a href="http://pages.ebay.com/help/buy/questions/upgrade-paypal-account.html" target="_blank" rel="xlink">upgraded</a> from a Personal account to a Business account, simply by going to the `Profile` button under the `My Account` tab, selecting the `Personal Business Information` button, and then clicking the `Upgrade Your Account` button.</p>' . "\n";
40
  /**/
41
  echo '<table class="form-table">' . "\n";
42
  echo '<tbody>' . "\n";
@@ -107,7 +107,7 @@ echo '<p>Log into your PayPal® account and navigate to this section:<br /><code
107
  echo '<p>Edit your IPN settings &amp; turn IPN Notifications: <strong><code>On</code></strong></p>' . "\n";
108
  echo '<p>You\'ll need your IPN URL, which is:<br /><code>' . get_bloginfo ("url") . '/?s2member_paypal_notify=1</code></p>' . "\n";
109
  echo '<p><strong>Quick tip:</strong> In addition to the default IPN Settings inside your PayPal® account, the IPN URL is also set on a per-transaction basis by the special PayPal® Button Code that s2Member provides you with. In other words, if you have multiple sites operating on one PayPal® account, that\'s OK. s2Member dynamically sets the IPN URL for each transaction. The result is that the IPN URL configured from within your PayPal® account, becomes the default, which is then overwritten on a per transaction basis. In fact, PayPal® recently updated their system to support IPN URL preservation. One PayPal® account can handle multiple sites, all using different IPN URLs.' . "\n";
110
- echo '<p><strong>More information:</strong> You\'ll be happy to know that s2Member handles cancellations, expirations, failed payments ( more than 2 in a row ), terminations ( e.g. refunds &amp; chargebacks ) for you automatically. If you log into your PayPal® account and cancel a Member\'s subscription, or, if the Member logs into their PayPal® account and cancels their own subscription, s2Member will be notified of these important changes and react accordingly through the PayPal® IPN service that runs silently behind-the-scene. The PayPal® IPN service will notify s2Member whenever a Member\'s payments have been failing ( more than 2 times in a row ), and/or whenever a Member\'s subscription has expired for any reason. Even refunds &amp; chargeback reversals are supported through the IPN service. If you issue a refund to an unhappy Customer through PayPal®, s2Member will be notified, and the account for that Customer will either be demote to a Free Subscriber, or deleted automatically ( based on your configuration ). The communication from PayPal® -> s2Member is seamless.</p>' . "\n";
111
  echo '</div>' . "\n";
112
  /**/
113
  echo '</div>' . "\n";
@@ -334,7 +334,7 @@ echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["installation"]) ? '<di
334
  /**/
335
  echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["tools"]) ? '<div class="ws-menu-page-tools"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-tools.png" alt="." /></div>' . "\n" : '';
336
  /**/
337
- echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["tips"]) ? '<div class="ws-menu-page-tips"><a href="' . ws_plugin__s2member_parse_readme_value ("Customization URI") . '"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-tips.png" alt="." /></a></div>' . "\n" : '';
338
  /**/
339
  echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["donations"]) ? '<div class="ws-menu-page-donations"><a href="' . ws_plugin__s2member_parse_readme_value ("Donate link") . '"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-donations.jpg" alt="." /></a></div>' . "\n" : '';
340
  /**/
36
  /**/
37
  echo '<div class="ws-menu-page-section ws-plugin--s2member-paypal-email-section">' . "\n";
38
  echo '<h3>PayPal® EMail Address ( required, please customize this )</h3>' . "\n";
39
+ echo '<p>This plugin works in conjunction with <a href="https://www.paypal.com/us/mrb/pal=K8S5Y97AKWYY8" target="_blank" rel="xlink">PayPal® Website Payments Standard</a>, for businesses. You do NOT need a PayPal® Pro account. You just need to upgrade your Personal PayPal® account to a Business status, which is free. A PayPal® account can be <a href="http://pages.ebay.com/help/buy/questions/upgrade-paypal-account.html" target="_blank" rel="xlink">upgraded</a> from a Personal account to a Business account, simply by going to the `Profile` button under the `My Account` tab, selecting the `Personal Business Information` button, and then clicking the `Upgrade Your Account` button.</p>' . "\n";
40
  /**/
41
  echo '<table class="form-table">' . "\n";
42
  echo '<tbody>' . "\n";
107
  echo '<p>Edit your IPN settings &amp; turn IPN Notifications: <strong><code>On</code></strong></p>' . "\n";
108
  echo '<p>You\'ll need your IPN URL, which is:<br /><code>' . get_bloginfo ("url") . '/?s2member_paypal_notify=1</code></p>' . "\n";
109
  echo '<p><strong>Quick tip:</strong> In addition to the default IPN Settings inside your PayPal® account, the IPN URL is also set on a per-transaction basis by the special PayPal® Button Code that s2Member provides you with. In other words, if you have multiple sites operating on one PayPal® account, that\'s OK. s2Member dynamically sets the IPN URL for each transaction. The result is that the IPN URL configured from within your PayPal® account, becomes the default, which is then overwritten on a per transaction basis. In fact, PayPal® recently updated their system to support IPN URL preservation. One PayPal® account can handle multiple sites, all using different IPN URLs.' . "\n";
110
+ echo '<p><strong>More information:</strong> You\'ll be happy to know that s2Member handles cancellations, expirations, failed payments ( more than 2 in a row ), terminations ( e.g. refunds &amp; chargebacks ) for you automatically. If you log into your PayPal® account and cancel a Member\'s subscription, or, if the Member logs into their PayPal® account and cancels their own subscription, s2Member will be notified of these important changes and react accordingly through the PayPal® IPN service that runs silently behind-the-scene. The PayPal® IPN service will notify s2Member whenever a Member\'s payments have been failing ( more than 2 times in a row ), and/or whenever a Member\'s subscription has expired for any reason. Even refunds &amp; chargeback reversals are supported through the IPN service. If you issue a refund to an unhappy Customer through PayPal®, s2Member will be notified, and the account for that Customer will either be demoted to a Free Subscriber, or deleted automatically ( based on your configuration ). The communication from PayPal® -> s2Member is seamless.</p>' . "\n";
111
  echo '</div>' . "\n";
112
  /**/
113
  echo '</div>' . "\n";
334
  /**/
335
  echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["tools"]) ? '<div class="ws-menu-page-tools"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-tools.png" alt="." /></div>' . "\n" : '';
336
  /**/
337
+ echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["support"]) ? '<div class="ws-menu-page-support"><a href="' . ws_plugin__s2member_parse_readme_value ("Forum URI") . '"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-support.png" alt="." /></a></div>' . "\n" : '';
338
  /**/
339
  echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["donations"]) ? '<div class="ws-menu-page-donations"><a href="' . ws_plugin__s2member_parse_readme_value ("Donate link") . '"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-donations.jpg" alt="." /></a></div>' . "\n" : '';
340
  /**/
includes/menu-pages/scripting.inc.php CHANGED
@@ -369,7 +369,7 @@ echo '<p>' . highlight_string (file_get_contents (dirname (__FILE__) . "/code-sa
369
  /**/
370
  echo '<div class="ws-menu-page-hr"></div>' . "\n";
371
  /**/
372
- echo '<p><strong>S2MEMBER_CURRENT_USER_VALUE_FOR_PP_ON0</strong><br />This auto-fills the <code>on0</code> value in PayPal® Button Codes.<br />If a Button Code is presented to a logged-in Member, this will auto-fill the value for the <code>on0</code> input variable, with the string: <code>"Updating Subscr"</code>. Otherwise, it will be an empty string.</p>' . "\n";
373
  echo '<p><strong>S2MEMBER_CURRENT_USER_VALUE_FOR_PP_OS0</strong><br />This auto-fills the <code>os0</code> value in PayPal® Button Codes.<br />If a Button Code is presented to a logged-in Member, this will auto-fill the value for the <code>os0</code> input variable, with the value of <code>S2MEMBER_CURRENT_USER_SUBSCR_ID</code>. Otherwise, it will be an empty string.</p>' . "\n";
374
  echo '<p>These two Constants are special. They are used by the PayPal® Button Generator for s2Member. This is how s2Member identifies an existing Member ( and/or a Free Subscriber ), who is already logged in when they click a PayPal® Modification Button that was generated for you by s2Member. Instead of forcing a Member ( and/or a Free Subscriber ) to re-register for a new account, s2Member can identify their existing account, and update it, according to the modified terms in your Button Code. These three Button Code parameters: <code>on0, os0, modify</code>, work together in harmony. If you\'re using the Shortcode Format for PayPal® Buttons ( recommended ), you won\'t even see these, because they\'re added internally by the Shortcode processor. Anyway, they\'re just documented here for clarity; you probably won\'t use these directly; the Button Code Generator pops them in.</p>' . "\n";
375
  echo '<p><em>' . highlight_string (file_get_contents (dirname (__FILE__) . "/code-samples/current-user-value-for-pp-on0-os0.php"), true) . '</em></p>' . "\n";
@@ -411,7 +411,7 @@ echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["installation"]) ? '<di
411
  /**/
412
  echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["tools"]) ? '<div class="ws-menu-page-tools"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-tools.png" alt="." /></div>' . "\n" : '';
413
  /**/
414
- echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["tips"]) ? '<div class="ws-menu-page-tips"><a href="' . ws_plugin__s2member_parse_readme_value ("Customization URI") . '"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-tips.png" alt="." /></a></div>' . "\n" : '';
415
  /**/
416
  echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["donations"]) ? '<div class="ws-menu-page-donations"><a href="' . ws_plugin__s2member_parse_readme_value ("Donate link") . '"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-donations.jpg" alt="." /></a></div>' . "\n" : '';
417
  /**/
369
  /**/
370
  echo '<div class="ws-menu-page-hr"></div>' . "\n";
371
  /**/
372
+ echo '<p><strong>S2MEMBER_CURRENT_USER_VALUE_FOR_PP_ON0</strong><br />This auto-fills the <code>on0</code> value in PayPal® Button Codes.<br />If a Button Code is presented to a logged-in Member, this will auto-fill the value for the <code>on0</code> input variable, with the string: <code>"Updating Subscr. ID"</code>. Otherwise, it will be an empty string.</p>' . "\n";
373
  echo '<p><strong>S2MEMBER_CURRENT_USER_VALUE_FOR_PP_OS0</strong><br />This auto-fills the <code>os0</code> value in PayPal® Button Codes.<br />If a Button Code is presented to a logged-in Member, this will auto-fill the value for the <code>os0</code> input variable, with the value of <code>S2MEMBER_CURRENT_USER_SUBSCR_ID</code>. Otherwise, it will be an empty string.</p>' . "\n";
374
  echo '<p>These two Constants are special. They are used by the PayPal® Button Generator for s2Member. This is how s2Member identifies an existing Member ( and/or a Free Subscriber ), who is already logged in when they click a PayPal® Modification Button that was generated for you by s2Member. Instead of forcing a Member ( and/or a Free Subscriber ) to re-register for a new account, s2Member can identify their existing account, and update it, according to the modified terms in your Button Code. These three Button Code parameters: <code>on0, os0, modify</code>, work together in harmony. If you\'re using the Shortcode Format for PayPal® Buttons ( recommended ), you won\'t even see these, because they\'re added internally by the Shortcode processor. Anyway, they\'re just documented here for clarity; you probably won\'t use these directly; the Button Code Generator pops them in.</p>' . "\n";
375
  echo '<p><em>' . highlight_string (file_get_contents (dirname (__FILE__) . "/code-samples/current-user-value-for-pp-on0-os0.php"), true) . '</em></p>' . "\n";
411
  /**/
412
  echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["tools"]) ? '<div class="ws-menu-page-tools"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-tools.png" alt="." /></div>' . "\n" : '';
413
  /**/
414
+ echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["support"]) ? '<div class="ws-menu-page-support"><a href="' . ws_plugin__s2member_parse_readme_value ("Forum URI") . '"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-support.png" alt="." /></a></div>' . "\n" : '';
415
  /**/
416
  echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["donations"]) ? '<div class="ws-menu-page-donations"><a href="' . ws_plugin__s2member_parse_readme_value ("Donate link") . '"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-donations.jpg" alt="." /></a></div>' . "\n" : '';
417
  /**/
includes/menu-pages/start.inc.php CHANGED
@@ -133,7 +133,7 @@ echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["installation"]) ? '<di
133
  /**/
134
  echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["tools"]) ? '<div class="ws-menu-page-tools"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-tools.png" alt="." /></div>' . "\n" : '';
135
  /**/
136
- echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["tips"]) ? '<div class="ws-menu-page-tips"><a href="' . ws_plugin__s2member_parse_readme_value ("Customization URI") . '"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-tips.png" alt="." /></a></div>' . "\n" : '';
137
  /**/
138
  echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["donations"]) ? '<div class="ws-menu-page-donations"><a href="' . ws_plugin__s2member_parse_readme_value ("Donate link") . '"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-donations.jpg" alt="." /></a></div>' . "\n" : '';
139
  /**/
133
  /**/
134
  echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["tools"]) ? '<div class="ws-menu-page-tools"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-tools.png" alt="." /></div>' . "\n" : '';
135
  /**/
136
+ echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["support"]) ? '<div class="ws-menu-page-support"><a href="' . ws_plugin__s2member_parse_readme_value ("Forum URI") . '"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-support.png" alt="." /></a></div>' . "\n" : '';
137
  /**/
138
  echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["donations"]) ? '<div class="ws-menu-page-donations"><a href="' . ws_plugin__s2member_parse_readme_value ("Donate link") . '"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-donations.jpg" alt="." /></a></div>' . "\n" : '';
139
  /**/
includes/menu-pages/trk-ops.inc.php CHANGED
@@ -143,7 +143,7 @@ echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["installation"]) ? '<di
143
  /**/
144
  echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["tools"]) ? '<div class="ws-menu-page-tools"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-tools.png" alt="." /></div>' . "\n" : '';
145
  /**/
146
- echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["tips"]) ? '<div class="ws-menu-page-tips"><a href="' . ws_plugin__s2member_parse_readme_value ("Customization URI") . '"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-tips.png" alt="." /></a></div>' . "\n" : '';
147
  /**/
148
  echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["donations"]) ? '<div class="ws-menu-page-donations"><a href="' . ws_plugin__s2member_parse_readme_value ("Donate link") . '"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-donations.jpg" alt="." /></a></div>' . "\n" : '';
149
  /**/
143
  /**/
144
  echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["tools"]) ? '<div class="ws-menu-page-tools"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-tools.png" alt="." /></div>' . "\n" : '';
145
  /**/
146
+ echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["support"]) ? '<div class="ws-menu-page-support"><a href="' . ws_plugin__s2member_parse_readme_value ("Forum URI") . '"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-support.png" alt="." /></a></div>' . "\n" : '';
147
  /**/
148
  echo ($GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"]["donations"]) ? '<div class="ws-menu-page-donations"><a href="' . ws_plugin__s2member_parse_readme_value ("Donate link") . '"><img src="' . $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["dir_url"] . '/images/brand-donations.jpg" alt="." /></a></div>' . "\n" : '';
149
  /**/
includes/syscon.inc.php CHANGED
@@ -39,7 +39,7 @@ $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["cache"] = get_option ("ws_plugin__s2me
39
  /*
40
  Configure the right menu options panel for this software.
41
  */
42
- $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"] = array ("tools" => true, "tips" => true, "donations" => true, "installation" => true);
43
  /*
44
  Configure the file modification time for the syscon.inc.php file.
45
  */
@@ -65,6 +65,9 @@ function ws_plugin__s2member_configure_options_and_their_defaults ($options = FA
65
  /**/
66
  "options_version" => "1.0", /* Used internally to keep runtime files up-to-date. */
67
  /**/
 
 
 
68
  "run_deactivation_routines" => "1", /* Should deactivation routines be processed? */
69
  /**/
70
  "custom_reg_fields" => "", /* A comma delimited list of custom fields to collect/use. */
@@ -201,6 +204,12 @@ function ws_plugin__s2member_configure_options_and_their_defaults ($options = FA
201
  else if ($key === "options_version" && (!is_string ($value) || !is_numeric ($value)))
202
  $value = $default_options[$key];
203
  /**/
 
 
 
 
 
 
204
  else if ($key === "run_deactivation_routines" && (!is_string ($value) || !is_numeric ($value)))
205
  $value = $default_options[$key];
206
  /**/
@@ -348,6 +357,14 @@ function ws_plugin__s2member_configure_options_and_their_defaults ($options = FA
348
  else if ($key === "membership_eot_behavior" && (!is_string ($value) || !preg_match ("/^(demote|delete)$/", $value)))
349
  $value = $default_options[$key];
350
  }
 
 
 
 
 
 
 
 
351
  /**/
352
  return $GLOBALS["WS_PLUGIN__"]["s2member"]["o"];
353
  }
39
  /*
40
  Configure the right menu options panel for this software.
41
  */
42
+ $GLOBALS["WS_PLUGIN__"]["s2member"]["c"]["menu-r"] = array ("tools" => true, "support" => true, "donations" => true, "installation" => true);
43
  /*
44
  Configure the file modification time for the syscon.inc.php file.
45
  */
65
  /**/
66
  "options_version" => "1.0", /* Used internally to keep runtime files up-to-date. */
67
  /**/
68
+ "sec_encryption_key" => "", /* For security. This keeps each installation unique. */
69
+ "sec_encryption_key_history" => array (), /* This keeps a history of the last 10 keys. */
70
+ /**/
71
  "run_deactivation_routines" => "1", /* Should deactivation routines be processed? */
72
  /**/
73
  "custom_reg_fields" => "", /* A comma delimited list of custom fields to collect/use. */
204
  else if ($key === "options_version" && (!is_string ($value) || !is_numeric ($value)))
205
  $value = $default_options[$key];
206
  /**/
207
+ else if ($key === "sec_encryption_key" && (!is_string ($value) || !strlen ($value)))
208
+ $value = $default_options[$key];
209
+ /**/
210
+ else if ($key === "sec_encryption_key_history" && (!is_array ($value) || empty ($value)))
211
+ $value = $default_options[$key];
212
+ /**/
213
  else if ($key === "run_deactivation_routines" && (!is_string ($value) || !is_numeric ($value)))
214
  $value = $default_options[$key];
215
  /**/
357
  else if ($key === "membership_eot_behavior" && (!is_string ($value) || !preg_match ("/^(demote|delete)$/", $value)))
358
  $value = $default_options[$key];
359
  }
360
+ /*
361
+ Keeps a history of the last 10 Security Encryption Keys configured for this installation.
362
+ */
363
+ if ($options !== false && is_string ($options["sec_encryption_key"]) && strlen ($options["sec_encryption_key"]) && !in_array ($options["sec_encryption_key"], $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["sec_encryption_key_history"]))
364
+ {
365
+ array_unshift ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["sec_encryption_key_history"], $options["sec_encryption_key"]);
366
+ $GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["sec_encryption_key_history"] = array_slice ($GLOBALS["WS_PLUGIN__"]["s2member"]["o"]["sec_encryption_key_history"], 0, 10);
367
+ }
368
  /**/
369
  return $GLOBALS["WS_PLUGIN__"]["s2member"]["o"];
370
  }
readme.txt CHANGED
@@ -1,7 +1,7 @@
1
  === s2Member ( Membership w/ PayPal® Integration ) also works w/ BuddyPress ===
2
 
3
- Version: 2.8.9
4
- Stable tag: 2.8.9
5
  Framework: WS-P-2.1
6
 
7
  WordPress Compatible: yes
@@ -21,9 +21,9 @@ Author: PriMoThemes.com / WebSharks, Inc.
21
  Donate link: http://www.primothemes.com/donate/
22
 
23
  Plugin Name: s2Member
 
24
  Professional Installation URI: http://www.primothemes.com/support/
25
  Plugin URI: http://www.primothemes.com/post/s2member-membership-plugin-with-paypal/
26
- Customization URI: http://www.primothemes.com/post/s2member-membership-plugin-with-paypal/#comments
27
  Description: Empowers WordPress® with membership capabilities. Integrates seamlessly with PayPal®. Also compatible with the BuddyPress plugin for WP.
28
  Tags: membership, members, member, register, signup, paypal, pay pal, s2member, subscriber, members only, buddypress, buddy press, buddy press compatible, shopping cart, checkout, api, options panel included, websharks framework, w3c validated code, multi widget support, includes extensive documentation, highly extensible
29
 
@@ -66,6 +66,9 @@ New! - Now you can sell Single-Page Access too, using "Buy Now" buttons. Further
66
 
67
  == Frequently Asked Questions ==
68
 
 
 
 
69
  = Does the PayPal integration work right-out-of-the-box? =
70
  Yes, it can even generate your PayPal® Subscription Buttons for you. Everything is fully integrated. You even get to create your own Pages within WordPress® to handle Membership Options, the Login Welcome Page, etc. For advanced webmasters, there are scripting techniques that are documented as well. These will help you further develop your site and tailor it to meet your specific needs. s2Member API Scripting is NOT required however.
71
 
@@ -93,17 +96,19 @@ Yes, there were some bugs in the beginning, but they have been fixed now. Both Q
93
  = Is s2Member compatible with the BuddyPress plugin for WordPress? =
94
  Yes it is. In fact, we must say... the s2Member/BuddyPress combination is just awesome. These two plugins running together make all sorts of things possible.
95
 
96
- = Do you take feature requests for future versions of s2Member? =
97
- We welcome any and all [contributions](http://www.primothemes.com/donate/) so that s2Member may remain publicly available. If you contribute more than $200, your feature requests will be given high priority, and you will also receive 5 WordPress® themes ( of your choosing ) from PriMoThemes.com.
98
-
99
- = Do you offer professional installation for s2Member? =
100
- Yes, please contact [PriMoThemes.com](http://www.primothemes.com/contact/) for assistance.
101
-
102
- = Is there a discussion forum for s2Member? =
103
- Yes. In the form of comments on [this page](http://www.primothemes.com/post/s2member-membership-plugin-with-paypal/).
104
 
105
  == Changelog ==
106
 
 
 
 
 
 
 
 
 
107
  = 2.8.9 =
108
  * Bug fixed in the Single-Page Access routines. Some Single-Page Access links were reporting "Link Expired". This has been resolved in s2Member v2.8.9.
109
 
@@ -182,7 +187,7 @@ Yes. In the form of comments on [this page](http://www.primothemes.com/post/s2me
182
 
183
  = 2.7.2 =
184
  * WebSharks Framework for Plugins has been updated to P-2.1.
185
- * The s2Member file download headers (`file-download-access.inc.php`) has been updated to support CGI/FastCGI implementations. s2Member has been tested with HostGator, BlueHost, (mt)MediaTemple (gs) and (dv), The Rackspace Cloud, and several dedicated servers running with Apache; including support for both `mod_php` and also `CGI/FastCGI` implementations. s2Member should work fine with any Apache/PHP combination. Please report all bugs to <primothemes@websharks-inc.com>.
186
 
187
  = 2.7.1 =
188
  * A bug in Custom Registration Fields has been corrected. This bug was introduced in v2.7, and has been corrected in v2.7.1. This bug was causing a mysterious [Empty Registration Field](http://www.primothemes.com/post/s2member-membership-plugin-with-paypal/comment-page-3/#comment-312) to appear on the form; when a new Customer registers their Username. Please thank [Jeffrey Nichols](http://jeffreyanichols.com/) for reporting this important issue.
1
  === s2Member ( Membership w/ PayPal® Integration ) also works w/ BuddyPress ===
2
 
3
+ Version: 2.9
4
+ Stable tag: 2.9
5
  Framework: WS-P-2.1
6
 
7
  WordPress Compatible: yes
21
  Donate link: http://www.primothemes.com/donate/
22
 
23
  Plugin Name: s2Member
24
+ Forum URI: http://www.primothemes.com/forums/viewforum.php?f=4
25
  Professional Installation URI: http://www.primothemes.com/support/
26
  Plugin URI: http://www.primothemes.com/post/s2member-membership-plugin-with-paypal/
 
27
  Description: Empowers WordPress® with membership capabilities. Integrates seamlessly with PayPal®. Also compatible with the BuddyPress plugin for WP.
28
  Tags: membership, members, member, register, signup, paypal, pay pal, s2member, subscriber, members only, buddypress, buddy press, buddy press compatible, shopping cart, checkout, api, options panel included, websharks framework, w3c validated code, multi widget support, includes extensive documentation, highly extensible
29
 
66
 
67
  == Frequently Asked Questions ==
68
 
69
+ = Is there a discussion forum for s2Member? =
70
+ Yes. The [Support Forum](http://www.primothemes.com/forums/viewforum.php?f=4) for s2Member is available [here](http://www.primothemes.com/forums/viewforum.php?f=4).
71
+
72
  = Does the PayPal integration work right-out-of-the-box? =
73
  Yes, it can even generate your PayPal® Subscription Buttons for you. Everything is fully integrated. You even get to create your own Pages within WordPress® to handle Membership Options, the Login Welcome Page, etc. For advanced webmasters, there are scripting techniques that are documented as well. These will help you further develop your site and tailor it to meet your specific needs. s2Member API Scripting is NOT required however.
74
 
96
  = Is s2Member compatible with the BuddyPress plugin for WordPress? =
97
  Yes it is. In fact, we must say... the s2Member/BuddyPress combination is just awesome. These two plugins running together make all sorts of things possible.
98
 
99
+ = Where can I download older versions of s2Member? =
100
+ Archived releases of s2Member are maintained [here](http://wordpress.org/extend/plugins/s2member/download/).
 
 
 
 
 
 
101
 
102
  == Changelog ==
103
 
104
+ = 2.9 =
105
+ * This release is all about security and bug fixes, with very few feature additions.
106
+ * Bug fix, `%%registration_url%%` in the Signup Confirmation Email was being replaced with `1`, instead of the full URL. This bug was first introduced in s2Member v2.8.7. This has been corrected in v2.9.
107
+ * s2Member now uses `MCRYPT_RIJNDAEL_256 / CBC` through `mcrypt_encrypt()` when it's available on your server. XOR encryption is used as a fallback for hosts that do not have the mcrypt extension installed. The `MCRYPT_RIJNDAEL_256` algorithm provides much better security.
108
+ * A full security review of s2Member has been completed, in anticipation of the s2Member Pro Module; being released later this month ( May 2010 ). A new panel under: `s2Member -> General Options -> Security Encryption Key` should be configured. Just click the `auto-generate` button there. s2Member will assign a special Security Key to your installation.
109
+ * Please join us in discussion. A new [Support Forum](http://www.primothemes.com/forums/viewforum.php?f=4) has been created for s2Member ( May 2010 ). Feel free to submit code samples, error messages, feature requests, etc.
110
+ * Please report all bugs. If you have any trouble with this release, you can always revert back to a [previous version](http://wordpress.org/extend/plugins/s2member/download/) until the issue is corrected.
111
+
112
  = 2.8.9 =
113
  * Bug fixed in the Single-Page Access routines. Some Single-Page Access links were reporting "Link Expired". This has been resolved in s2Member v2.8.9.
114
 
187
 
188
  = 2.7.2 =
189
  * WebSharks Framework for Plugins has been updated to P-2.1.
190
+ * The s2Member file download headers (`file-download-access.inc.php`) has been updated to support CGI/FastCGI implementations. s2Member has been tested with HostGator, BlueHost, (mt)MediaTemple (gs) and (dv), The Rackspace Cloud, and several dedicated servers running with Apache; including support for both `mod_php` and also `CGI/FastCGI` implementations. s2Member should work fine with any Apache/PHP combination. Please report all bugs through the [Support Forum](http://www.primothemes.com/forums/viewforum.php?f=4).
191
 
192
  = 2.7.1 =
193
  * A bug in Custom Registration Fields has been corrected. This bug was introduced in v2.7, and has been corrected in v2.7.1. This bug was causing a mysterious [Empty Registration Field](http://www.primothemes.com/post/s2member-membership-plugin-with-paypal/comment-page-3/#comment-312) to appear on the form; when a new Customer registers their Username. Please thank [Jeffrey Nichols](http://jeffreyanichols.com/) for reporting this important issue.
s2member.php CHANGED
@@ -9,8 +9,8 @@ along with this software. In the main directory, see: /licensing/
9
  If not, see: <http://www.gnu.org/licenses/>.
10
  */
11
  /*
12
- Version: 2.8.9
13
- Stable tag: 2.8.9
14
  Framework: WS-P-2.1
15
 
16
  WordPress Compatible: yes
@@ -30,9 +30,9 @@ Author: PriMoThemes.com / WebSharks, Inc.
30
  Donate link: http://www.primothemes.com/donate/
31
 
32
  Plugin Name: s2Member
 
33
  Professional Installation URI: http://www.primothemes.com/support/
34
  Plugin URI: http://www.primothemes.com/post/s2member-membership-plugin-with-paypal/
35
- Customization URI: http://www.primothemes.com/post/s2member-membership-plugin-with-paypal/#comments
36
  Description: Empowers WordPress® with membership capabilities. Integrates seamlessly with PayPal®. Also compatible with the BuddyPress plugin for WP.
37
  Tags: membership, members, member, register, signup, paypal, pay pal, s2member, subscriber, members only, buddypress, buddy press, buddy press compatible, shopping cart, checkout, api, options panel included, websharks framework, w3c validated code, multi widget support, includes extensive documentation, highly extensible
38
  */
9
  If not, see: <http://www.gnu.org/licenses/>.
10
  */
11
  /*
12
+ Version: 2.9
13
+ Stable tag: 2.9
14
  Framework: WS-P-2.1
15
 
16
  WordPress Compatible: yes
30
  Donate link: http://www.primothemes.com/donate/
31
 
32
  Plugin Name: s2Member
33
+ Forum URI: http://www.primothemes.com/forums/viewforum.php?f=4
34
  Professional Installation URI: http://www.primothemes.com/support/
35
  Plugin URI: http://www.primothemes.com/post/s2member-membership-plugin-with-paypal/
 
36
  Description: Empowers WordPress® with membership capabilities. Integrates seamlessly with PayPal®. Also compatible with the BuddyPress plugin for WP.
37
  Tags: membership, members, member, register, signup, paypal, pay pal, s2member, subscriber, members only, buddypress, buddy press, buddy press compatible, shopping cart, checkout, api, options panel included, websharks framework, w3c validated code, multi widget support, includes extensive documentation, highly extensible
38
  */